From dee65a4fa15605ade963a86b562e8f40130e8313 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 5 May 2023 10:52:02 +0000 Subject: [PATCH] fix for `Self` not respecting tuple Ctor privacy This fixes #111220 by checking the privacy of tuple constructors using `Self`, so the following code now errors ```rust mod my { pub struct Foo(&'static str); } impl AsRef for my::Foo { fn as_ref(&self) -> &str { let Self(s) = self; // previously compiled, now errors correctly s } } ``` --- compiler/rustc_hir_typeck/messages.ftl | 2 + compiler/rustc_hir_typeck/src/errors.rs | 8 ++++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 7 +++ ...111220-2-tuple-struct-fields-projection.rs | 33 +++++++++++++ ...20-2-tuple-struct-fields-projection.stderr | 9 ++++ .../issue-111220-tuple-struct-fields.rs | 46 +++++++++++++++++++ .../issue-111220-tuple-struct-fields.stderr | 21 +++++++++ 7 files changed, 126 insertions(+) create mode 100644 tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs create mode 100644 tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr create mode 100644 tests/ui/privacy/issue-111220-tuple-struct-fields.rs create mode 100644 tests/ui/privacy/issue-111220-tuple-struct-fields.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 4a669e3f8b8a4..93d3061e9742a 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -90,3 +90,5 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}` [implement] , perhaps you need to implement it *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it } + +hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 102a313067fd2..e45b8e3d024de 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -319,3 +319,11 @@ pub struct CandidateTraitNote { pub item_name: Ident, pub action_or_ty: String, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_ctor_is_private, code = "E0603")] +pub struct CtorIsPrivate { + #[primary_span] + pub span: Span, + pub def: String, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9721e3b427d2b..9a97156054cf8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,4 +1,5 @@ use crate::callee::{self, DeferredCallResolution}; +use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; @@ -1210,6 +1211,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); + // Check the visibility of the ctor. + let vis = tcx.visibility(ctor_def_id); + if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { + tcx.sess + .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); + } let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let user_substs = Self::user_substs_for_adt(ty); user_self_ty = user_substs.user_self_ty; diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs new file mode 100644 index 0000000000000..f413b50277861 --- /dev/null +++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs @@ -0,0 +1,33 @@ +mod b { + pub struct A(u32); +} + +trait Id { + type Assoc; +} +impl Id for b::A { + type Assoc = b::A; +} +impl Id for u32 { + type Assoc = u32; +} + + +trait Trait { + fn method(&self) + where + T: Id; +} + +impl Trait for ::Assoc { + fn method(&self) + where + T: Id, + { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{a}"); + } +} + +fn main() {} diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr new file mode 100644 index 0000000000000..231a4da8b5f7f --- /dev/null +++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr @@ -0,0 +1,9 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-2-tuple-struct-fields-projection.rs:27:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.rs b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs new file mode 100644 index 0000000000000..78d35fd96da3d --- /dev/null +++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs @@ -0,0 +1,46 @@ +mod b { + #[derive(Default)] + pub struct A(u32); +} + +impl b::A { + fn inherent_bypass(&self) { + let Self(x) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{x}"); + } +} + +pub trait B { + fn f(&self); +} + +impl B for b::A { + fn f(&self) { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{}", a); + } +} + +pub trait Projector { + type P; +} + +impl Projector for () { + type P = b::A; +} + +pub trait Bypass2 { + fn f2(&self); +} + +impl Bypass2 for <() as Projector>::P { + fn f2(&self) { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{}", a); + } +} + +fn main() {} diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr new file mode 100644 index 0000000000000..17a32379cc0a8 --- /dev/null +++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr @@ -0,0 +1,21 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:8:13 + | +LL | let Self(x) = self; + | ^^^^^^^ + +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:20:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:40:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0603`.