Auto merge of #135846 - estebank:non-exhaustive-dfv-ctor-2, r=BoxyUwU

Detect struct construction with private field in field with default

When trying to construct a struct that has a public field of a private type, suggest using `..` if that field has a default value.

```
error[E0603]: struct `Priv1` is private
  --> $DIR/non-exhaustive-ctor-2.rs:19:39
   |
LL |     let _ = S { field: (), field1: m::Priv1 {} };
   |                            ------     ^^^^^ private struct
   |                            |
   |                            while setting this field
   |
note: the struct `Priv1` is defined here
  --> $DIR/non-exhaustive-ctor-2.rs:14:4
   |
LL |    struct Priv1 {}
   |    ^^^^^^^^^^^^
help: the type `Priv1` of field `field1` is private, but you can construct the default value defined for it in `S` using `..` in the struct initializer expression
   |
LL |     let _ = S { field: (), .. };
   |                            ~~
```
This commit is contained in:
bors 2025-08-10 23:47:25 +00:00
commit 21a19c297d
11 changed files with 321 additions and 36 deletions

View file

@ -395,6 +395,7 @@ provide! { tcx, def_id, other, cdata,
crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
default_field => { cdata.get_default_field(def_id.index) }
is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) }
doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(def_id.index)) }
doc_link_traits_in_scope => {

View file

@ -1864,6 +1864,12 @@ rustc_queries! {
feedable
}
/// Returns whether the field corresponding to the `DefId` has a default field value.
query default_field(def_id: DefId) -> Option<DefId> {
desc { |tcx| "looking up the `const` corresponding to the default for `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
return_result_from_ensure_ok

View file

@ -420,14 +420,18 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
// The fields are not expanded yet.
return;
}
let fields = fields
let field_name = |i, field: &ast::FieldDef| {
field.ident.unwrap_or_else(|| Ident::from_str_and_span(&format!("{i}"), field.span))
};
let field_names: Vec<_> =
fields.iter().enumerate().map(|(i, field)| field_name(i, field)).collect();
let defaults = fields
.iter()
.enumerate()
.map(|(i, field)| {
field.ident.unwrap_or_else(|| Ident::from_str_and_span(&format!("{i}"), field.span))
})
.filter_map(|(i, field)| field.default.as_ref().map(|_| field_name(i, field).name))
.collect();
self.r.field_names.insert(def_id, fields);
self.r.field_names.insert(def_id, field_names);
self.r.field_defaults.insert(def_id, defaults);
}
fn insert_field_visibilities_local(&mut self, def_id: DefId, fields: &[ast::FieldDef]) {

View file

@ -1943,8 +1943,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } =
*privacy_error;
let PrivacyError {
ident,
binding,
outermost_res,
parent_scope,
single_nested,
dedup_span,
ref source,
} = *privacy_error;
let res = binding.res();
let ctor_fields_span = self.ctor_fields_span(binding);
@ -1960,6 +1967,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let mut err =
self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
self.mention_default_field_values(source, ident, &mut err);
let mut not_publicly_reexported = false;
if let Some((this_res, outer_ident)) = outermost_res {
let import_suggestions = self.lookup_import_candidates(
@ -2141,6 +2150,85 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
err.emit();
}
/// When a private field is being set that has a default field value, we suggest using `..` and
/// setting the value of that field implicitly with its default.
///
/// If we encounter code like
/// ```text
/// struct Priv;
/// pub struct S {
/// pub field: Priv = Priv,
/// }
/// ```
/// which is used from a place where `Priv` isn't accessible
/// ```text
/// let _ = S { field: m::Priv1 {} };
/// // ^^^^^ private struct
/// ```
/// we will suggest instead using the `default_field_values` syntax instead:
/// ```text
/// let _ = S { .. };
/// ```
fn mention_default_field_values(
&self,
source: &Option<ast::Expr>,
ident: Ident,
err: &mut Diag<'_>,
) {
let Some(expr) = source else { return };
let ast::ExprKind::Struct(struct_expr) = &expr.kind else { return };
// We don't have to handle type-relative paths because they're forbidden in ADT
// expressions, but that would change with `#[feature(more_qualified_paths)]`.
let Some(Res::Def(_, def_id)) =
self.partial_res_map[&struct_expr.path.segments.iter().last().unwrap().id].full_res()
else {
return;
};
let Some(default_fields) = self.field_defaults(def_id) else { return };
if struct_expr.fields.is_empty() {
return;
}
let last_span = struct_expr.fields.iter().last().unwrap().span;
let mut iter = struct_expr.fields.iter().peekable();
let mut prev: Option<Span> = None;
while let Some(field) = iter.next() {
if field.expr.span.overlaps(ident.span) {
err.span_label(field.ident.span, "while setting this field");
if default_fields.contains(&field.ident.name) {
let sugg = if last_span == field.span {
vec![(field.span, "..".to_string())]
} else {
vec![
(
// Account for trailing commas and ensure we remove them.
match (prev, iter.peek()) {
(_, Some(next)) => field.span.with_hi(next.span.lo()),
(Some(prev), _) => field.span.with_lo(prev.hi()),
(None, None) => field.span,
},
String::new(),
),
(last_span.shrink_to_hi(), ", ..".to_string()),
]
};
err.multipart_suggestion_verbose(
format!(
"the type `{ident}` of field `{}` is private, but you can construct \
the default value defined for it in `{}` using `..` in the struct \
initializer expression",
field.ident,
self.tcx.item_name(def_id),
),
sugg,
Applicability::MachineApplicable,
);
break;
}
}
prev = Some(field.span);
}
}
pub(crate) fn find_similarly_named_module_or_crate(
&self,
ident: Symbol,

View file

@ -1029,6 +1029,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
binding,
dedup_span: path_span,
outermost_res: None,
source: None,
parent_scope: *parent_scope,
single_nested: path_span != root_span,
});
@ -1435,7 +1436,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
parent_scope: &ParentScope<'ra>,
ignore_import: Option<Import<'ra>>,
) -> PathResult<'ra> {
self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import)
self.resolve_path_with_ribs(
path,
opt_ns,
parent_scope,
None,
None,
None,
None,
ignore_import,
)
}
#[instrument(level = "debug", skip(self))]
pub(crate) fn resolve_path<'r>(
@ -1451,6 +1461,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
path,
opt_ns,
parent_scope,
None,
finalize,
None,
ignore_binding,
@ -1463,6 +1474,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path in import
parent_scope: &ParentScope<'ra>,
source: Option<PathSource<'_, '_, '_>>,
finalize: Option<Finalize>,
ribs: Option<&PerNS<Vec<Rib<'ra>>>>,
ignore_binding: Option<NameBinding<'ra>>,
@ -1645,6 +1657,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if finalize.is_some() {
for error in &mut self.get_mut().privacy_errors[privacy_errors_len..] {
error.outermost_res = Some((res, ident));
error.source = match source {
Some(PathSource::Struct(Some(expr)))
| Some(PathSource::Expr(Some(expr))) => Some(expr.clone()),
_ => None,
};
}
}

View file

@ -424,7 +424,7 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
/// Paths in path patterns `Path`.
Pat,
/// Paths in struct expressions and patterns `Path { .. }`.
Struct,
Struct(Option<&'a Expr>),
/// Paths in tuple struct patterns `Path(..)`.
TupleStruct(Span, &'ra [Span]),
/// `m::A::B` in `<T as m::A>::B::C`.
@ -447,7 +447,7 @@ impl PathSource<'_, '_, '_> {
match self {
PathSource::Type
| PathSource::Trait(_)
| PathSource::Struct
| PathSource::Struct(_)
| PathSource::DefineOpaques => TypeNS,
PathSource::Expr(..)
| PathSource::Pat
@ -464,7 +464,7 @@ impl PathSource<'_, '_, '_> {
PathSource::Type
| PathSource::Expr(..)
| PathSource::Pat
| PathSource::Struct
| PathSource::Struct(_)
| PathSource::TupleStruct(..)
| PathSource::ReturnTypeNotation => true,
PathSource::Trait(_)
@ -481,7 +481,7 @@ impl PathSource<'_, '_, '_> {
PathSource::Type => "type",
PathSource::Trait(_) => "trait",
PathSource::Pat => "unit struct, unit variant or constant",
PathSource::Struct => "struct, variant or union type",
PathSource::Struct(_) => "struct, variant or union type",
PathSource::TraitItem(ValueNS, PathSource::TupleStruct(..))
| PathSource::TupleStruct(..) => "tuple struct or tuple variant",
PathSource::TraitItem(ns, _) => match ns {
@ -576,7 +576,7 @@ impl PathSource<'_, '_, '_> {
|| matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
}
PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(),
PathSource::Struct => matches!(
PathSource::Struct(_) => matches!(
res,
Res::Def(
DefKind::Struct
@ -616,8 +616,8 @@ impl PathSource<'_, '_, '_> {
(PathSource::Trait(_), false) => E0405,
(PathSource::Type | PathSource::DefineOpaques, true) => E0573,
(PathSource::Type | PathSource::DefineOpaques, false) => E0412,
(PathSource::Struct, true) => E0574,
(PathSource::Struct, false) => E0422,
(PathSource::Struct(_), true) => E0574,
(PathSource::Struct(_), false) => E0422,
(PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423,
(PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
(PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
@ -1482,11 +1482,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path in import
finalize: Option<Finalize>,
source: PathSource<'_, 'ast, 'ra>,
) -> PathResult<'ra> {
self.r.cm().resolve_path_with_ribs(
path,
opt_ns,
&self.parent_scope,
Some(source),
finalize,
Some(&self.ribs),
None,
@ -1966,7 +1968,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
&mut self,
partial_res: PartialRes,
path: &[Segment],
source: PathSource<'_, '_, '_>,
source: PathSource<'_, 'ast, 'ra>,
path_span: Span,
) {
let proj_start = path.len() - partial_res.unresolved_segments();
@ -2019,7 +2021,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
| PathSource::ReturnTypeNotation => false,
PathSource::Expr(..)
| PathSource::Pat
| PathSource::Struct
| PathSource::Struct(_)
| PathSource::TupleStruct(..)
| PathSource::DefineOpaques
| PathSource::Delegation => true,
@ -3866,7 +3868,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.smart_resolve_path(pat.id, qself, path, PathSource::Pat);
}
PatKind::Struct(ref qself, ref path, ref _fields, ref rest) => {
self.smart_resolve_path(pat.id, qself, path, PathSource::Struct);
self.smart_resolve_path(pat.id, qself, path, PathSource::Struct(None));
self.record_patterns_with_skipped_bindings(pat, rest);
}
PatKind::Or(ref ps) => {
@ -4110,7 +4112,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
id: NodeId,
qself: &Option<Box<QSelf>>,
path: &Path,
source: PathSource<'_, 'ast, '_>,
source: PathSource<'_, 'ast, 'ra>,
) {
self.smart_resolve_path_fragment(
qself,
@ -4127,7 +4129,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
&mut self,
qself: &Option<Box<QSelf>>,
path: &[Segment],
source: PathSource<'_, 'ast, '_>,
source: PathSource<'_, 'ast, 'ra>,
finalize: Finalize,
record_partial_res: RecordPartialRes,
parent_qself: Option<&QSelf>,
@ -4365,7 +4367,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std)));
std_path.extend(path);
if let PathResult::Module(_) | PathResult::NonModule(_) =
self.resolve_path(&std_path, Some(ns), None)
self.resolve_path(&std_path, Some(ns), None, source)
{
// Check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
let item_span =
@ -4439,7 +4441,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
span: Span,
defer_to_typeck: bool,
finalize: Finalize,
source: PathSource<'_, 'ast, '_>,
source: PathSource<'_, 'ast, 'ra>,
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
let mut fin_res = None;
@ -4488,7 +4490,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
path: &[Segment],
ns: Namespace,
finalize: Finalize,
source: PathSource<'_, 'ast, '_>,
source: PathSource<'_, 'ast, 'ra>,
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
debug!(
"resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
@ -4551,7 +4553,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
)));
}
let result = match self.resolve_path(path, Some(ns), Some(finalize)) {
let result = match self.resolve_path(path, Some(ns), Some(finalize), source) {
PathResult::NonModule(path_res) => path_res,
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
PartialRes::new(module.res().unwrap())
@ -4774,7 +4776,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
ExprKind::Struct(ref se) => {
self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct);
self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct(parent));
// This is the same as `visit::walk_expr(self, expr);`, but we want to pass the
// parent in for accurate suggestions when encountering `Foo { bar }` that should
// have been `Foo { bar: self.bar }`.

View file

@ -174,7 +174,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
&mut self,
path: &[Segment],
span: Span,
source: PathSource<'_, '_, '_>,
source: PathSource<'_, 'ast, 'ra>,
res: Option<Res>,
) -> BaseError {
// Make the base error.
@ -318,7 +318,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
(String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)
} else {
let mod_path = &path[..path.len() - 1];
let mod_res = self.resolve_path(mod_path, Some(TypeNS), None);
let mod_res = self.resolve_path(mod_path, Some(TypeNS), None, source);
let mod_prefix = match mod_res {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
_ => None,
@ -419,7 +419,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
path: &[Segment],
following_seg: Option<&Segment>,
span: Span,
source: PathSource<'_, '_, '_>,
source: PathSource<'_, 'ast, 'ra>,
res: Option<Res>,
qself: Option<&QSelf>,
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
@ -1014,7 +1014,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
fn suggest_typo(
&mut self,
err: &mut Diag<'_>,
source: PathSource<'_, '_, '_>,
source: PathSource<'_, 'ast, 'ra>,
path: &[Segment],
following_seg: Option<&Segment>,
span: Span,
@ -1333,7 +1333,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
fn suggest_swapping_misplaced_self_ty_and_trait(
&mut self,
err: &mut Diag<'_>,
source: PathSource<'_, '_, '_>,
source: PathSource<'_, 'ast, 'ra>,
res: Option<Res>,
span: Span,
) {
@ -1341,7 +1341,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
self.diag_metadata.currently_processing_impl_trait.clone()
&& let TyKind::Path(_, self_ty_path) = &self_ty.kind
&& let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source)
&& let ModuleKind::Def(DefKind::Trait, ..) = module.kind
&& trait_ref.path.span == span
&& let PathSource::Trait(_) = source
@ -1449,13 +1449,13 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
fn get_single_associated_item(
&mut self,
path: &[Segment],
source: &PathSource<'_, '_, '_>,
source: &PathSource<'_, 'ast, 'ra>,
filter_fn: &impl Fn(Res) -> bool,
) -> Option<TypoSuggestion> {
if let crate::PathSource::TraitItem(_, _) = source {
let mod_path = &path[..path.len() - 1];
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, None, None)
self.resolve_path(mod_path, None, None, *source)
{
let targets: Vec<_> = self
.r
@ -1854,7 +1854,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
PathSource::Expr(Some(Expr {
kind: ExprKind::Index(..) | ExprKind::Call(..), ..
}))
| PathSource::Struct,
| PathSource::Struct(_),
) => {
// Don't suggest macro if it's unstable.
let suggestable = def_id.is_local()
@ -2502,7 +2502,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
// Search in module.
let mod_path = &path[..path.len() - 1];
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, Some(TypeNS), None)
self.resolve_path(mod_path, Some(TypeNS), None, PathSource::Type)
{
self.r.add_module_candidates(module, &mut names, &filter_fn, None);
}
@ -3673,7 +3673,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
if let TyKind::Path(None, path) = &ty.kind {
// Check if the path being borrowed is likely to be owned.
let path: Vec<_> = Segment::from_path(path);
match self.resolve_path(&path, Some(TypeNS), None) {
match self.resolve_path(
&path,
Some(TypeNS),
None,
PathSource::Type,
) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
match module.res() {
Some(Res::PrimTy(PrimTy::Str)) => {

View file

@ -822,6 +822,7 @@ struct PrivacyError<'ra> {
parent_scope: ParentScope<'ra>,
/// Is the format `use a::{b,c}`?
single_nested: bool,
source: Option<ast::Expr>,
}
#[derive(Debug)]
@ -1064,6 +1065,7 @@ pub struct Resolver<'ra, 'tcx> {
/// N.B., this is used only for better diagnostics, not name resolution itself.
field_names: LocalDefIdMap<Vec<Ident>>,
field_defaults: LocalDefIdMap<Vec<Symbol>>,
/// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax.
/// Used for hints during error reporting.
@ -1538,6 +1540,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
extern_prelude,
field_names: Default::default(),
field_defaults: Default::default(),
field_visibility_spans: FxHashMap::default(),
determined_imports: Vec::new(),
@ -2318,6 +2321,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
fn field_defaults(&self, def_id: DefId) -> Option<Vec<Symbol>> {
match def_id.as_local() {
Some(def_id) => self.field_defaults.get(&def_id).cloned(),
None => Some(
self.tcx
.associated_item_def_ids(def_id)
.iter()
.filter_map(|&def_id| {
self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id))
})
.collect(),
),
}
}
/// Checks if an expression refers to a function marked with
/// `#[rustc_legacy_const_generics]` and returns the argument index list
/// from the attribute.

View file

@ -3,3 +3,13 @@
pub struct A {
pub a: isize = 42,
}
struct Priv;
pub struct B {
pub a: Priv = Priv,
}
pub struct C {
pub a: Priv,
}

View file

@ -0,0 +1,29 @@
//@ aux-build:struct_field_default.rs
#![feature(default_field_values)]
extern crate struct_field_default as xc;
use m::S;
mod m {
pub struct S {
pub field: () = (),
pub field1: Priv1 = Priv1 {},
pub field2: Priv2 = Priv2,
}
struct Priv1 {}
struct Priv2;
}
fn main() {
let _ = S { field: (), field1: m::Priv1 {} };
//~^ ERROR missing field `field2`
//~| ERROR struct `Priv1` is private
let _ = S { field: (), field1: m::Priv1 {}, field2: m::Priv2 };
//~^ ERROR struct `Priv1` is private
//~| ERROR unit struct `Priv2` is private
let _ = xc::B { a: xc::Priv };
//~^ ERROR unit struct `Priv` is private
let _ = xc::C { a: xc::Priv };
//~^ ERROR unit struct `Priv` is private
}

View file

@ -0,0 +1,105 @@
error[E0603]: struct `Priv1` is private
--> $DIR/non-exhaustive-ctor-2.rs:19:39
|
LL | let _ = S { field: (), field1: m::Priv1 {} };
| ------ ^^^^^ private struct
| |
| while setting this field
|
note: the struct `Priv1` is defined here
--> $DIR/non-exhaustive-ctor-2.rs:14:4
|
LL | struct Priv1 {}
| ^^^^^^^^^^^^
help: the type `Priv1` of field `field1` is private, but you can construct the default value defined for it in `S` using `..` in the struct initializer expression
|
LL - let _ = S { field: (), field1: m::Priv1 {} };
LL + let _ = S { field: (), .. };
|
error[E0603]: struct `Priv1` is private
--> $DIR/non-exhaustive-ctor-2.rs:22:39
|
LL | let _ = S { field: (), field1: m::Priv1 {}, field2: m::Priv2 };
| ------ ^^^^^ private struct
| |
| while setting this field
|
note: the struct `Priv1` is defined here
--> $DIR/non-exhaustive-ctor-2.rs:14:4
|
LL | struct Priv1 {}
| ^^^^^^^^^^^^
help: the type `Priv1` of field `field1` is private, but you can construct the default value defined for it in `S` using `..` in the struct initializer expression
|
LL - let _ = S { field: (), field1: m::Priv1 {}, field2: m::Priv2 };
LL + let _ = S { field: (), field2: m::Priv2, .. };
|
error[E0603]: unit struct `Priv2` is private
--> $DIR/non-exhaustive-ctor-2.rs:22:60
|
LL | let _ = S { field: (), field1: m::Priv1 {}, field2: m::Priv2 };
| ------ ^^^^^ private unit struct
| |
| while setting this field
|
note: the unit struct `Priv2` is defined here
--> $DIR/non-exhaustive-ctor-2.rs:15:4
|
LL | struct Priv2;
| ^^^^^^^^^^^^^
help: the type `Priv2` of field `field2` is private, but you can construct the default value defined for it in `S` using `..` in the struct initializer expression
|
LL - let _ = S { field: (), field1: m::Priv1 {}, field2: m::Priv2 };
LL + let _ = S { field: (), field1: m::Priv1 {}, .. };
|
error[E0603]: unit struct `Priv` is private
--> $DIR/non-exhaustive-ctor-2.rs:25:28
|
LL | let _ = xc::B { a: xc::Priv };
| - ^^^^ private unit struct
| |
| while setting this field
|
note: the unit struct `Priv` is defined here
--> $DIR/auxiliary/struct_field_default.rs:7:1
|
LL | struct Priv;
| ^^^^^^^^^^^
help: the type `Priv` of field `a` is private, but you can construct the default value defined for it in `B` using `..` in the struct initializer expression
|
LL - let _ = xc::B { a: xc::Priv };
LL + let _ = xc::B { .. };
|
error[E0603]: unit struct `Priv` is private
--> $DIR/non-exhaustive-ctor-2.rs:27:28
|
LL | let _ = xc::C { a: xc::Priv };
| - ^^^^ private unit struct
| |
| while setting this field
|
note: the unit struct `Priv` is defined here
--> $DIR/auxiliary/struct_field_default.rs:7:1
|
LL | struct Priv;
| ^^^^^^^^^^^
error[E0063]: missing field `field2` in initializer of `S`
--> $DIR/non-exhaustive-ctor-2.rs:19:13
|
LL | let _ = S { field: (), field1: m::Priv1 {} };
| ^ missing `field2`
|
help: all remaining fields have default values, you can use those values with `..`
|
LL | let _ = S { field: (), field1: m::Priv1 {}, .. };
| ++++
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0063, E0603.
For more information about an error, try `rustc --explain E0063`.