Rollup merge of #98283 - TaKO8Ki:point-at-private-fields-in-struct-literal, r=compiler-errors
Point at private fields in struct literal closes #95872
This commit is contained in:
commit
41cb5e9439
@ -26,6 +26,9 @@ macro_rules! pluralize {
|
|||||||
("is", $x:expr) => {
|
("is", $x:expr) => {
|
||||||
if $x == 1 { "is" } else { "are" }
|
if $x == 1 { "is" } else { "are" }
|
||||||
};
|
};
|
||||||
|
("was", $x:expr) => {
|
||||||
|
if $x == 1 { "was" } else { "were" }
|
||||||
|
};
|
||||||
("this", $x:expr) => {
|
("this", $x:expr) => {
|
||||||
if $x == 1 { "this" } else { "these" }
|
if $x == 1 { "this" } else { "these" }
|
||||||
};
|
};
|
||||||
|
@ -26,10 +26,10 @@ use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructEx
|
|||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::Diagnostic;
|
use rustc_errors::{
|
||||||
use rustc_errors::EmissionGuarantee;
|
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
|
||||||
use rustc_errors::ErrorGuaranteed;
|
EmissionGuarantee, ErrorGuaranteed,
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
@ -1701,12 +1701,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
|
self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
|
||||||
} else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() {
|
} else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() {
|
||||||
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
|
debug!(?remaining_fields);
|
||||||
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
|
let private_fields: Vec<&ty::FieldDef> = variant
|
||||||
});
|
.fields
|
||||||
|
.iter()
|
||||||
|
.filter(|field| {
|
||||||
|
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
if inaccessible_remaining_fields {
|
if !private_fields.is_empty() {
|
||||||
self.report_inaccessible_fields(adt_ty, span);
|
self.report_private_fields(adt_ty, span, private_fields, ast_fields);
|
||||||
} else {
|
} else {
|
||||||
self.report_missing_fields(
|
self.report_missing_fields(
|
||||||
adt_ty,
|
adt_ty,
|
||||||
@ -1830,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
/// Report an error for a struct field expression when there are invisible fields.
|
/// Report an error for a struct field expression when there are invisible fields.
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
/// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
/// error: cannot construct `Foo` with struct literal syntax due to private fields
|
||||||
/// --> src/main.rs:8:5
|
/// --> src/main.rs:8:5
|
||||||
/// |
|
/// |
|
||||||
/// 8 | foo::Foo {};
|
/// 8 | foo::Foo {};
|
||||||
@ -1838,13 +1843,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
///
|
///
|
||||||
/// error: aborting due to previous error
|
/// error: aborting due to previous error
|
||||||
/// ```
|
/// ```
|
||||||
fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
|
fn report_private_fields(
|
||||||
self.tcx.sess.span_err(
|
&self,
|
||||||
|
adt_ty: Ty<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
private_fields: Vec<&ty::FieldDef>,
|
||||||
|
used_fields: &'tcx [hir::ExprField<'tcx>],
|
||||||
|
) {
|
||||||
|
let mut err = self.tcx.sess.struct_span_err(
|
||||||
span,
|
span,
|
||||||
&format!(
|
&format!(
|
||||||
"cannot construct `{adt_ty}` with struct literal syntax due to inaccessible fields",
|
"cannot construct `{adt_ty}` with struct literal syntax due to private fields",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
let (used_private_fields, remaining_private_fields): (
|
||||||
|
Vec<(Symbol, Span, bool)>,
|
||||||
|
Vec<(Symbol, Span, bool)>,
|
||||||
|
) = private_fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
match used_fields.iter().find(|used_field| field.name == used_field.ident.name) {
|
||||||
|
Some(used_field) => (field.name, used_field.span, true),
|
||||||
|
None => (field.name, self.tcx.def_span(field.did), false),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.partition(|field| field.2);
|
||||||
|
err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
|
||||||
|
if !remaining_private_fields.is_empty() {
|
||||||
|
let remaining_private_fields_len = remaining_private_fields.len();
|
||||||
|
let names = match &remaining_private_fields
|
||||||
|
.iter()
|
||||||
|
.map(|(name, _, _)| name.to_string())
|
||||||
|
.collect::<Vec<_>>()[..]
|
||||||
|
{
|
||||||
|
_ if remaining_private_fields_len > 6 => String::new(),
|
||||||
|
[name] => format!("`{name}` "),
|
||||||
|
[names @ .., last] => {
|
||||||
|
let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
||||||
|
format!("{} and `{last}` ", names.join(", "))
|
||||||
|
}
|
||||||
|
[] => unreachable!(),
|
||||||
|
};
|
||||||
|
err.note(format!(
|
||||||
|
"... and other private field{s} {names}that {were} not provided",
|
||||||
|
s = pluralize!(remaining_private_fields_len),
|
||||||
|
were = pluralize!("was", remaining_private_fields_len),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_unknown_field(
|
fn report_unknown_field(
|
||||||
|
@ -6,5 +6,5 @@ pub mod foo {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo::Foo {};
|
foo::Foo {};
|
||||||
//~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
//~^ ERROR cannot construct `Foo` with struct literal syntax due to private fields
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
error: cannot construct `Foo` with struct literal syntax due to private fields
|
||||||
--> $DIR/issue-76077.rs:8:5
|
--> $DIR/issue-76077.rs:8:5
|
||||||
|
|
|
|
||||||
LL | foo::Foo {};
|
LL | foo::Foo {};
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... and other private field `you_cant_use_this_field` that was not provided
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ mod foo {
|
|||||||
|
|
||||||
fn correct() {
|
fn correct() {
|
||||||
foo::Pub {};
|
foo::Pub {};
|
||||||
//~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields
|
//~^ ERROR cannot construct `Pub` with struct literal syntax due to private fields
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrong() {
|
fn wrong() {
|
||||||
|
@ -10,11 +10,13 @@ error[E0063]: missing field `y` in initializer of `Enum`
|
|||||||
LL | Enum::Variant { x: () };
|
LL | Enum::Variant { x: () };
|
||||||
| ^^^^^^^^^^^^^ missing `y`
|
| ^^^^^^^^^^^^^ missing `y`
|
||||||
|
|
||||||
error: cannot construct `Pub` with struct literal syntax due to inaccessible fields
|
error: cannot construct `Pub` with struct literal syntax due to private fields
|
||||||
--> $DIR/issue-79593.rs:18:5
|
--> $DIR/issue-79593.rs:18:5
|
||||||
|
|
|
|
||||||
LL | foo::Pub {};
|
LL | foo::Pub {};
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... and other private field `private` that was not provided
|
||||||
|
|
||||||
error[E0063]: missing field `y` in initializer of `Enum`
|
error[E0063]: missing field `y` in initializer of `Enum`
|
||||||
--> $DIR/issue-79593.rs:23:5
|
--> $DIR/issue-79593.rs:23:5
|
||||||
|
@ -7,5 +7,5 @@ pub mod foo {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo::Foo {};
|
foo::Foo {};
|
||||||
//~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
//~^ ERROR cannot construct `Foo` with struct literal syntax due to private fields
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
error: cannot construct `Foo` with struct literal syntax due to private fields
|
||||||
--> $DIR/issue-87872-missing-inaccessible-field-literal.rs:9:5
|
--> $DIR/issue-87872-missing-inaccessible-field-literal.rs:9:5
|
||||||
|
|
|
|
||||||
LL | foo::Foo {};
|
LL | foo::Foo {};
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... and other private field `you_cant_use_this_field` that was not provided
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
pub mod m {
|
||||||
|
pub struct S {
|
||||||
|
pub visible: bool,
|
||||||
|
a: (),
|
||||||
|
b: (),
|
||||||
|
c: (),
|
||||||
|
d: (),
|
||||||
|
e: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = m::S { //~ ERROR cannot construct `S` with struct literal syntax due to private fields
|
||||||
|
visible: true,
|
||||||
|
a: (),
|
||||||
|
b: (),
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
error: cannot construct `S` with struct literal syntax due to private fields
|
||||||
|
--> $DIR/missing-private-fields-in-struct-literal.rs:13:13
|
||||||
|
|
|
||||||
|
LL | let _ = m::S {
|
||||||
|
| ^^^^
|
||||||
|
LL | visible: true,
|
||||||
|
LL | a: (),
|
||||||
|
| ----- private field
|
||||||
|
LL | b: (),
|
||||||
|
| ----- private field
|
||||||
|
|
|
||||||
|
= note: ... and other private fields `c`, `d` and `e` that were not provided
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user