check `mut`-restriction when tuple constructor is used as a value * check mut restriction when tuple ctor is used as a value * add missing stderr file for mut-restriction ctor value test * simplify def_kind matching in tuple ctor mut restriction check Match the DefKind::Ctor directly on the result of tcx.def_kind instead of binding it to a local first. Extend the ctor-value ui test with additional enum variants covering plain and crate-restricted fields. * test: exercise new ctor variants * address review: drop shell.nix, add tests
diff --git a/compiler/rustc_mir_transform/src/check_mut_restriction.rs b/compiler/rustc_mir_transform/src/check_mut_restriction.rs index 9d6809e..96f3679 100644 --- a/compiler/rustc_mir_transform/src/check_mut_restriction.rs +++ b/compiler/rustc_mir_transform/src/check_mut_restriction.rs
@@ -1,3 +1,4 @@ +use rustc_hir::def::{CtorOf, DefKind}; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; @@ -34,6 +35,40 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { self.super_statement(statement, location); } + // Tuple constructors used as values can bypass field mut restrictions if not checked here. + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + if let ty::FnDef(def_id, _) = *constant.const_.ty().kind() + && let DefKind::Ctor(ctor_of, _) = self.tcx.def_kind(def_id) + { + let body_did = self.body.source.instance.def_id(); + let adt_did = match ctor_of { + CtorOf::Struct => self.tcx.parent(def_id), + CtorOf::Variant => self.tcx.parent(self.tcx.parent(def_id)), + }; + let adt = self.tcx.adt_def(adt_did); + let variant = match ctor_of { + CtorOf::Struct => adt.non_enum_variant(), + CtorOf::Variant => adt.variant_with_ctor_id(def_id), + }; + + let mut_restriction = + variant.fields.iter().fold(ty::RestrictionKind::Unrestricted, |acc, field| { + acc.stricter_of(field.mut_restriction, self.tcx) + }); + if !mut_restriction.is_allowed_in(body_did, self.tcx) { + self.tcx.dcx().emit_err(diagnostics::ConstructionOfTyWithMutRestrictedField { + construction_span: constant.span, + restriction_span: mut_restriction.expect_span(), + name: variant.name, + descr: adt.variant_descr(), + restriction_path: mut_restriction.restriction_path(self.tcx), + }); + } + } + + self.super_const_operand(constant, location); + } + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { if context.is_mutating_use() { let body_did = self.body.source.instance.def_id();
diff --git a/tests/ui/mut-restriction/mut-restriction-ctor-value.rs b/tests/ui/mut-restriction/mut-restriction-ctor-value.rs new file mode 100644 index 0000000..7ca33ff --- /dev/null +++ b/tests/ui/mut-restriction/mut-restriction-ctor-value.rs
@@ -0,0 +1,40 @@ +//@ edition: 2018.. +#![feature(mut_restriction)] + +pub mod inner { + #[derive(Default)] + pub struct Wrapper(pub mut(self) u8); + + pub enum EnumTup { + Tup(mut(self) u8), + Foo(u8), + Bar(u8, mut(crate) u8), + } + + pub fn construct_inner() { + let _ = Wrapper; + let _ = EnumTup::Tup; + let _ = EnumTup::Foo; + let _ = EnumTup::Bar; + } +} + +fn param_is_fn(_: fn(u8) -> inner::Wrapper) {} +fn param_impl_fn(_: impl Fn(u8) -> inner::Wrapper) {} + +fn main() { + let _ = inner::Wrapper; + //~^ ERROR `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + + param_is_fn(inner::Wrapper); + //~^ ERROR `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + + param_impl_fn(inner::Wrapper); + //~^ ERROR `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + + let _ = inner::EnumTup::Tup; + //~^ ERROR `Tup` cannot be constructed using a `variant` expression outside `crate::inner` + + let _ = inner::EnumTup::Foo; + let _ = inner::EnumTup::Bar; +}
diff --git a/tests/ui/mut-restriction/mut-restriction-ctor-value.stderr b/tests/ui/mut-restriction/mut-restriction-ctor-value.stderr new file mode 100644 index 0000000..b10a3c1 --- /dev/null +++ b/tests/ui/mut-restriction/mut-restriction-ctor-value.stderr
@@ -0,0 +1,38 @@ +error: `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:26:13 + | +LL | pub struct Wrapper(pub mut(self) u8); + | --------- field restricted here +... +LL | let _ = inner::Wrapper; + | ^^^^^^^^^^^^^^ + +error: `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:29:17 + | +LL | pub struct Wrapper(pub mut(self) u8); + | --------- field restricted here +... +LL | param_is_fn(inner::Wrapper); + | ^^^^^^^^^^^^^^ + +error: `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:32:19 + | +LL | pub struct Wrapper(pub mut(self) u8); + | --------- field restricted here +... +LL | param_impl_fn(inner::Wrapper); + | ^^^^^^^^^^^^^^ + +error: `Tup` cannot be constructed using a `variant` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:35:13 + | +LL | Tup(mut(self) u8), + | --------- field restricted here +... +LL | let _ = inner::EnumTup::Tup; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors +