diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-11-25 21:52:08 +0000 | 
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2025-09-28 21:33:34 +0000 | 
| commit | 8f7d61b9efe1f44701f87fe4647eb1f39d20f434 (patch) | |
| tree | f426df79269952ea7f2e3c35dff5854ba6302227 /compiler/rustc_resolve/src/ident.rs | |
| parent | 8d72d3e1e96f58ca10059a6bb6e8aecba4a0e9cd (diff) | |
| download | rust-8f7d61b9efe1f44701f87fe4647eb1f39d20f434.tar.gz rust-8f7d61b9efe1f44701f87fe4647eb1f39d20f434.zip | |
Detect unconstructable re-exported tuple structs
When a tuple-struct is re-exported that has inaccessible fields at the `use` scope, the type's constructor cannot be accessed through that re-export. We now account for this case and extend the resulting resolution error. We also check if the constructor would be accessible directly, not through the re-export, and if so, we suggest using the full path instead. ``` error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:33 | LL | let crate::Foo(x) = crate::Foo(42); | ^^^^^^^^^^ | note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 | LL | pub use my_mod::Foo; | ^^^^^^^^^^^ help: the type can be constructed directly, because its fields are available from the current scope | LL | let crate::Foo(x) = crate::my_mod::Foo(42); | ~~~~~~~~~~~~~~~~~~ ``` Fix #133343.
Diffstat (limited to 'compiler/rustc_resolve/src/ident.rs')
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 33 | 
1 files changed, 33 insertions, 0 deletions
| diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 51489019950..4415300777f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -901,6 +901,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, + module, finalize, shadowing, ); @@ -1025,6 +1026,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding: Option<NameBinding<'ra>>, shadowed_glob: Option<NameBinding<'ra>>, parent_scope: &ParentScope<'ra>, + module: Module<'ra>, finalize: Finalize, shadowing: Shadowing, ) -> Result<NameBinding<'ra>, (Determinacy, Weak)> { @@ -1076,6 +1078,37 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } + // If we encounter a re-export for a type with private fields, it will not be able to + // be constructed through this re-export. We track that case here to expand later + // privacy errors with appropriate information. + if let Res::Def(_, def_id) = binding.res() { + let struct_ctor = match def_id.as_local() { + Some(def_id) => self.struct_constructors.get(&def_id).cloned(), + None => { + let ctor = self.cstore().ctor_untracked(def_id); + ctor.map(|(ctor_kind, ctor_def_id)| { + let ctor_res = Res::Def( + DefKind::Ctor(rustc_hir::def::CtorOf::Struct, ctor_kind), + ctor_def_id, + ); + let ctor_vis = self.tcx.visibility(ctor_def_id); + let field_visibilities = self + .tcx + .associated_item_def_ids(def_id) + .iter() + .map(|field_id| self.tcx.visibility(field_id)) + .collect(); + (ctor_res, ctor_vis, field_visibilities) + }) + } + }; + if let Some((_, _, fields)) = struct_ctor + && fields.iter().any(|vis| !self.is_accessible_from(*vis, module)) + { + self.inaccessible_ctor_reexport.insert(path_span, binding.span); + } + } + self.record_use(ident, binding, used); return Ok(binding); } | 
