diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 776b081a4630f..324074945138c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -424,6 +424,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 => { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 478ac19d199bd..29b91cd874e18 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1719,6 +1719,13 @@ rustc_queries! { feedable } + /// Returns whether the impl or associated function has the `default` keyword. + query default_field(def_id: DefId) -> Option { + desc { |tcx| "looking up the `const` corresponding to the default for `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + feedable + } + 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 diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c6781ecc56681..662b20a259c8f 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -396,14 +396,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]) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8d42b478647dc..7327337a2bd91 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1750,8 +1750,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); @@ -1767,6 +1774,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut err = self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); + if let Some(expr) = source + && let ast::ExprKind::Struct(struct_expr) = &expr.kind + && let Some(Res::Def(_, def_id)) = self.partial_res_map + [&struct_expr.path.segments.iter().last().unwrap().id] + .full_res() + && let Some(default_fields) = self.field_defaults(def_id) + && !struct_expr.fields.is_empty() + { + let last_span = struct_expr.fields.iter().last().unwrap().span; + let mut iter = struct_expr.fields.iter().peekable(); + let mut prev: Option = 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); + } + } + let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { let import_suggestions = self.lookup_import_candidates( diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 499b9bca4d2ad..016431d601847 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -893,6 +893,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, }); @@ -1402,7 +1403,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ignore_import: Option>, ) -> 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))] @@ -1419,6 +1429,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path, opt_ns, parent_scope, + None, finalize, None, ignore_binding, @@ -1431,6 +1442,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path: &[Segment], opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, + source: Option>, finalize: Option, ribs: Option<&PerNS>>>, ignore_binding: Option>, @@ -1605,6 +1617,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // the user it is not accessible. for error in &mut self.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, + }; } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 508bd831ccbea..e9fed20a4dae5 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -403,7 +403,7 @@ pub(crate) enum PathSource<'a> { // 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, &'a [Span]), // `m::A::B` in `::B::C`. @@ -419,7 +419,7 @@ pub(crate) enum PathSource<'a> { impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { - PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, + PathSource::Type | PathSource::Trait(_) | PathSource::Struct(_) => TypeNS, PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) @@ -435,7 +435,7 @@ impl<'a> PathSource<'a> { PathSource::Type | PathSource::Expr(..) | PathSource::Pat - | PathSource::Struct + | PathSource::Struct(_) | PathSource::TupleStruct(..) | PathSource::ReturnTypeNotation => true, PathSource::Trait(_) @@ -450,7 +450,7 @@ impl<'a> PathSource<'a> { 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::TupleStruct(..) => "tuple struct or tuple variant", PathSource::TraitItem(ns) => match ns { TypeNS => "associated type", @@ -531,7 +531,7 @@ impl<'a> PathSource<'a> { || 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 @@ -571,8 +571,8 @@ impl<'a> PathSource<'a> { (PathSource::Trait(_), false) => E0405, (PathSource::Type, true) => E0573, (PathSource::Type, 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, @@ -1458,11 +1458,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path: &[Segment], opt_ns: Option, // `None` indicates a module path in import finalize: Option, + source: PathSource<'ast>, ) -> PathResult<'ra> { self.r.resolve_path_with_ribs( path, opt_ns, &self.parent_scope, + Some(source), finalize, Some(&self.ribs), None, @@ -1967,7 +1969,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | PathSource::ReturnTypeNotation => false, PathSource::Expr(..) | PathSource::Pat - | PathSource::Struct + | PathSource::Struct(_) | PathSource::TupleStruct(..) | PathSource::Delegation => true, }; @@ -3805,7 +3807,7 @@ impl<'a, 'ast, 'ra: 'ast, '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) => { @@ -4214,6 +4216,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { qself, path, ns, + source, path_span, source.defer_to_typeck(), finalize, @@ -4259,7 +4262,7 @@ impl<'a, 'ast, 'ra: 'ast, '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 = @@ -4330,6 +4333,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { qself: &Option>, path: &[Segment], primary_ns: Namespace, + source: PathSource<'ast>, span: Span, defer_to_typeck: bool, finalize: Finalize, @@ -4338,7 +4342,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for (i, &ns) in [primary_ns, TypeNS, ValueNS].iter().enumerate() { if i == 0 || ns != primary_ns { - match self.resolve_qpath(qself, path, ns, finalize)? { + match self.resolve_qpath(qself, path, ns, source, finalize)? { Some(partial_res) if partial_res.unresolved_segments() == 0 || defer_to_typeck => { @@ -4374,6 +4378,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { qself: &Option>, path: &[Segment], ns: Namespace, + source: PathSource<'ast>, finalize: Finalize, ) -> Result, Spanned>> { debug!( @@ -4435,7 +4440,7 @@ impl<'a, 'ast, 'ra: 'ast, '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()) @@ -4659,7 +4664,7 @@ impl<'a, 'ast, 'ra: 'ast, '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 }`. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a80b68d9773d4..98431d3b46acf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -174,7 +174,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, path: &[Segment], span: Span, - source: PathSource<'_>, + source: PathSource<'ast>, res: Option, ) -> BaseError { // Make the base error. @@ -317,7 +317,7 @@ impl<'ast, 'ra: 'ast, '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: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { path: &[Segment], following_seg: Option<&Segment>, span: Span, - source: PathSource<'_>, + source: PathSource<'ast>, res: Option, ) -> (Diag<'tcx>, Vec) { debug!(?res, ?source); @@ -887,7 +887,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_typo( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'ast>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -1206,7 +1206,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_swapping_misplaced_self_ty_and_trait( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'ast>, res: Option, span: Span, ) { @@ -1214,7 +1214,7 @@ impl<'ast, 'ra: 'ast, '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 @@ -1335,13 +1335,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn get_single_associated_item( &mut self, path: &[Segment], - source: &PathSource<'_>, + source: &PathSource<'ast>, filter_fn: &impl Fn(Res) -> bool, ) -> Option { 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 resolutions = self.r.resolutions(module).borrow(); let targets: Vec<_> = @@ -1694,7 +1694,7 @@ impl<'ast, 'ra: 'ast, '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() @@ -2275,7 +2275,7 @@ impl<'ast, 'ra: 'ast, '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); } @@ -3378,7 +3378,12 @@ impl<'ast, 'ra: 'ast, '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)) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 90191b7776f32..193240a702ba5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -772,6 +772,7 @@ struct PrivacyError<'ra> { parent_scope: ParentScope<'ra>, /// Is the format `use a::{b,c}`? single_nested: bool, + source: Option, } #[derive(Debug)] @@ -1023,6 +1024,7 @@ pub struct Resolver<'ra, 'tcx> { /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap>, + field_defaults: LocalDefIdMap>, /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. /// Used for hints during error reporting. @@ -1443,6 +1445,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(), @@ -2176,6 +2179,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn field_defaults(&self, def_id: DefId) -> Option> { + 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. diff --git a/tests/ui/structs/default-field-values/auxiliary/struct_field_default.rs b/tests/ui/structs/default-field-values/auxiliary/struct_field_default.rs index b315df5dba287..a1c9645a1ae23 100644 --- a/tests/ui/structs/default-field-values/auxiliary/struct_field_default.rs +++ b/tests/ui/structs/default-field-values/auxiliary/struct_field_default.rs @@ -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, +} diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor-2.rs b/tests/ui/structs/default-field-values/non-exhaustive-ctor-2.rs new file mode 100644 index 0000000000000..047505c3f1cab --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor-2.rs @@ -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 +} diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor-2.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor-2.stderr new file mode 100644 index 0000000000000..66de73561db28 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor-2.stderr @@ -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`.