From d6b6488e20c8909335e291371e4ad7623f2b9593 Mon Sep 17 00:00:00 2001 From: Russell Johnston Date: Sat, 18 Apr 2020 20:31:56 -0700 Subject: [PATCH 1/2] Handle statics in MIR typeck with user type annotations --- src/librustc_mir/borrow_check/type_check/mod.rs | 14 -------------- src/librustc_mir_build/build/expr/as_constant.rs | 4 ++-- src/librustc_mir_build/hair/cx/expr.rs | 14 ++++++++++++++ src/librustc_mir_build/hair/mod.rs | 1 + .../rustc.BAR-promoted[0].ConstProp.after.mir | 1 + .../rustc.BAR.PromoteTemps.diff | 4 ++++ .../rustc.FOO-promoted[0].ConstProp.after.mir | 1 + .../rustc.FOO.PromoteTemps.diff | 4 ++++ .../32bit/rustc.main.ConstProp.after.mir | 1 + .../64bit/rustc.main.ConstProp.after.mir | 1 + .../64bit/rustc.main.ConstProp.after.mir | 1 + .../64bit/rustc.main.ConstProp.after.mir | 1 + .../rustc.main.ConstProp.diff | 2 ++ 13 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index bd85b48bf4b98..8e846d27277dd 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -366,20 +366,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ); } } - } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { - let unnormalized_ty = tcx.type_of(static_def_id); - let locations = location.to_locations(); - let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty.builtin_deref(true).unwrap().ty; - - if let Err(terr) = self.cx.eq_types( - normalized_ty, - literal_ty, - locations, - ConstraintCategory::Boring, - ) { - span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); - } } if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { diff --git a/src/librustc_mir_build/build/expr/as_constant.rs b/src/librustc_mir_build/build/expr/as_constant.rs index 03ec0b48f8bfe..7e014be2119c2 100644 --- a/src/librustc_mir_build/build/expr/as_constant.rs +++ b/src/librustc_mir_build/build/expr/as_constant.rs @@ -21,7 +21,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let Expr { ty, temp_lifetime: _, span, kind } = expr; match kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), - ExprKind::Literal { literal, user_ty } => { + ExprKind::Literal { literal, user_ty } | + ExprKind::StaticRef { literal, user_ty, .. } => { let user_ty = user_ty.map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, @@ -32,7 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert_eq!(literal.ty, ty); Constant { span, user_ty, literal } } - ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } } diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 21d632b9f6b83..d7257f3df847a 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -6,6 +6,7 @@ use crate::hair::*; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_index::vec::Idx; +use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::BorrowKind; use rustc_middle::ty::adjustment::{ @@ -742,6 +743,18 @@ fn convert_path_expr<'a, 'tcx>( let ty = cx.tcx.static_ptr_ty(id); let ptr = cx.tcx.alloc_map.lock().create_static_alloc(id); let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); + + // Keep regions around in a user type annotation for MIR typeck: + let static_ty = cx.tcx.type_of(id); + let static_ptr_ty = if cx.tcx.is_mutable_static(id) { + cx.tcx.mk_mut_ptr(static_ty) + } else { + let origin = RegionVariableOrigin::AddrOfRegion(expr.span); + let region = cx.infcx.next_region_var(origin); + cx.tcx.mk_imm_ref(region, static_ty) + }; + let user_ty = cx.infcx.canonicalize_user_type_annotation(&UserType::Ty(static_ptr_ty)); + ExprKind::Deref { arg: Expr { ty, @@ -749,6 +762,7 @@ fn convert_path_expr<'a, 'tcx>( span: expr.span, kind: ExprKind::StaticRef { literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty), + user_ty: Some(user_ty), def_id: id, }, } diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs index 601e4412512ab..400b670a5f962 100644 --- a/src/librustc_mir_build/hair/mod.rs +++ b/src/librustc_mir_build/hair/mod.rs @@ -275,6 +275,7 @@ crate enum ExprKind<'tcx> { /// info for diagnostics. StaticRef { literal: &'tcx Const<'tcx>, + user_ty: Option>>, def_id: DefId, }, LlvmInlineAsm { diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir index 256018adaa89b..84cf94202d998 100644 --- a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir +++ b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir @@ -13,6 +13,7 @@ promoted[0] in BAR: &[&i32; 1] = { // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 + // + user_ty: UserType(0) // + literal: Const { ty: &i32, val: Value(Scalar(alloc0+0)) } _2 = _3; // bb0[1]: scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 _1 = [move _2]; // bb0[2]: scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff index bc5b114418e42..4dd6adcbd09e5 100644 --- a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff @@ -1,6 +1,9 @@ - // MIR for `BAR` before PromoteTemps + // MIR for `BAR` after PromoteTemps + | User Type Annotations + | 0: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(&i32) } at $DIR/const-promotion-extern-static.rs:9:33: 9:34 + | static mut BAR: *const &i32 = { let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:17: 9:28 let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 @@ -25,6 +28,7 @@ + // + val: Unevaluated(DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 +- // + user_ty: UserType(0) - // + literal: Const { ty: &i32, val: Value(Scalar(alloc0+0)) } - _4 = &(*_5); // bb0[6]: scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 - _3 = [move _4]; // bb0[7]: scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir index 5bbc05a9cab7c..659e390ce665d 100644 --- a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir +++ b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir @@ -15,6 +15,7 @@ promoted[0] in FOO: &[&i32; 1] = { // + val: Value(Scalar(alloc2+0)) // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 + // + user_ty: UserType(0) // + literal: Const { ty: &i32, val: Value(Scalar(alloc2+0)) } _2 = _3; // bb0[1]: scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 _1 = [move _2]; // bb0[2]: scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff index 7df1a47b2f497..ddb7b05912a4b 100644 --- a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff @@ -1,6 +1,9 @@ - // MIR for `FOO` before PromoteTemps + // MIR for `FOO` after PromoteTemps + | User Type Annotations + | 0: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(&i32) } at $DIR/const-promotion-extern-static.rs:13:42: 13:43 + | static mut FOO: *const &i32 = { let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:17: 13:28 let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 @@ -27,6 +30,7 @@ + // + val: Unevaluated(DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 +- // + user_ty: UserType(0) - // + literal: Const { ty: &i32, val: Value(Scalar(alloc2+0)) } - _4 = &(*_5); // bb0[6]: scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 - _3 = [move _4]; // bb0[7]: scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 diff --git a/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir index 2247b8e155a4b..2c2e2d18d597c 100644 --- a/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir +++ b/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir @@ -14,6 +14,7 @@ fn main() -> () { // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/const_allocation.rs:8:5: 8:8 + // + user_ty: UserType(0) // + literal: Const { ty: &&[(std::option::Option, &[&str])], val: Value(Scalar(alloc0+0)) } _1 = (*_2); // bb0[3]: scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageDead(_2); // bb0[4]: scope 0 at $DIR/const_allocation.rs:8:8: 8:9 diff --git a/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir index d6cca185ab0f7..7f8e377af49b3 100644 --- a/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir +++ b/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir @@ -14,6 +14,7 @@ fn main() -> () { // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/const_allocation.rs:8:5: 8:8 + // + user_ty: UserType(0) // + literal: Const { ty: &&[(std::option::Option, &[&str])], val: Value(Scalar(alloc0+0)) } _1 = (*_2); // bb0[3]: scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageDead(_2); // bb0[4]: scope 0 at $DIR/const_allocation.rs:8:8: 8:9 diff --git a/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir index e61f0a8b69fa7..a93a3fe59f066 100644 --- a/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir +++ b/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir @@ -14,6 +14,7 @@ fn main() -> () { // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/const_allocation2.rs:5:5: 5:8 + // + user_ty: UserType(0) // + literal: Const { ty: &&[(std::option::Option, &[&u8])], val: Value(Scalar(alloc0+0)) } _1 = (*_2); // bb0[3]: scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageDead(_2); // bb0[4]: scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 diff --git a/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir index 7dea5c664d858..bf1cc1659398a 100644 --- a/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir +++ b/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir @@ -14,6 +14,7 @@ fn main() -> () { // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/const_allocation3.rs:5:5: 5:8 + // + user_ty: UserType(0) // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc0+0)) } _1 = (*_2); // bb0[3]: scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 StorageDead(_2); // bb0[4]: scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 diff --git a/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff index d9852539844c9..d60c6522f8c44 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff @@ -22,6 +22,7 @@ // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/read_immutable_static.rs:7:13: 7:16 + // + user_ty: UserType(0) // + literal: Const { ty: &u8, val: Value(Scalar(alloc0+0)) } - _2 = (*_3); // bb0[4]: scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 + _2 = const 2u8; // bb0[4]: scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 @@ -39,6 +40,7 @@ // + val: Value(Scalar(alloc0+0)) // mir::Constant // + span: $DIR/read_immutable_static.rs:7:19: 7:22 + // + user_ty: UserType(1) // + literal: Const { ty: &u8, val: Value(Scalar(alloc0+0)) } - _4 = (*_5); // bb0[8]: scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 - _1 = Add(move _2, move _4); // bb0[9]: scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22 From 8f868332cff801cf288618c46bd6fcc0d10e9ef5 Mon Sep 17 00:00:00 2001 From: Russell Johnston Date: Sat, 18 Apr 2020 11:54:50 -0700 Subject: [PATCH 2/2] Allow constants to refer to statics This relaxes the dynamic and validity checks so that constants can construct pointers to all statics and read from immutable statics. --- src/librustc_mir/const_eval/eval_queries.rs | 56 +++++++------ src/librustc_mir/const_eval/machine.rs | 12 +-- src/librustc_mir/const_eval/mod.rs | 4 +- src/librustc_mir/interpret/machine.rs | 3 - src/librustc_mir/interpret/memory.rs | 14 ++-- src/librustc_mir/interpret/validity.rs | 8 +- src/librustc_mir/transform/const_prop.rs | 3 +- src/test/ui/consts/const-points-to-static.rs | 2 +- .../ui/consts/const-points-to-static.stderr | 13 +-- .../consts/const-prop-read-static-in-const.rs | 3 +- .../const-prop-read-static-in-const.stderr | 14 +--- .../miri_unleashed/const_refers_to_static.rs | 31 +++++-- .../const_refers_to_static.stderr | 81 ++++++++++--------- .../miri_unleashed/use-static-via-const.rs | 29 +++++++ .../use-static-via-const.stderr | 14 ++++ src/test/ui/issues/issue-52060.rs | 1 - src/test/ui/issues/issue-52060.stderr | 11 +-- 17 files changed, 167 insertions(+), 132 deletions(-) create mode 100644 src/test/ui/consts/miri_unleashed/use-static-via-const.rs create mode 100644 src/test/ui/consts/miri_unleashed/use-static-via-const.stderr diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 1592207e4d291..1700464c5fc5b 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -1,9 +1,9 @@ use super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind, - InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, - ScalarMaybeUndef, StackPopCleanup, + intern_const_alloc_recursive, AllocId, Allocation, ConstValue, GlobalAlloc, GlobalId, + Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, + RefTracking, Scalar, ScalarMaybeUndef, StackPopCleanup, }; use rustc_hir::def::DefKind; use rustc_middle::mir; @@ -94,10 +94,13 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( ) } -pub(super) fn op_to_const<'tcx>( +#[derive(Debug)] +pub(super) struct RefersToStatic; + +pub(super) fn try_op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, -) -> ConstValue<'tcx> { +) -> Result, RefersToStatic> { // We do not have value optimizations for everything. // Only scalars and slices, since they are very common. // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result @@ -128,10 +131,16 @@ pub(super) fn op_to_const<'tcx>( op.try_as_mplace(ecx) }; + let alloc_map = ecx.tcx.alloc_map.lock(); + let try_unwrap_memory = |alloc_id: AllocId| match alloc_map.get(alloc_id) { + Some(GlobalAlloc::Memory(mem)) => Ok(mem), + Some(GlobalAlloc::Static(_)) => Err(RefersToStatic), + _ => bug!("expected allocation ID {} to point to memory", alloc_id), + }; let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr { Scalar::Ptr(ptr) => { - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } + let alloc = try_unwrap_memory(ptr.alloc_id)?; + Ok(ConstValue::ByRef { alloc, offset: ptr.offset }) } Scalar::Raw { data, .. } => { assert!(mplace.layout.is_zst()); @@ -141,22 +150,20 @@ pub(super) fn op_to_const<'tcx>( "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what value this integer address must have", ); - ConstValue::Scalar(Scalar::zst()) + Ok(ConstValue::Scalar(Scalar::zst())) } }; match immediate { - Ok(mplace) => to_const_value(mplace), + Ok(mplace) => Ok(to_const_value(mplace)?), // see comment on `let try_as_immediate` above Err(imm) => match *imm { Immediate::Scalar(x) => match x { - ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUndef::Undef => to_const_value(op.assert_mem_place(ecx)), + ScalarMaybeUndef::Scalar(s) => Ok(ConstValue::Scalar(s)), + ScalarMaybeUndef::Undef => Ok(to_const_value(op.assert_mem_place(ecx))?), }, Immediate::ScalarPair(a, b) => { let (data, start) = match a.not_undef().unwrap() { - Scalar::Ptr(ptr) => { - (ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), ptr.offset.bytes()) - } + Scalar::Ptr(ptr) => (try_unwrap_memory(ptr.alloc_id)?, ptr.offset.bytes()), Scalar::Raw { .. } => ( ecx.tcx .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), @@ -166,7 +173,7 @@ pub(super) fn op_to_const<'tcx>( let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); let start = start.try_into().unwrap(); let len: usize = len.try_into().unwrap(); - ConstValue::Slice { data, start, end: start + len } + Ok(ConstValue::Slice { data, start, end: start + len }) } }, } @@ -198,17 +205,20 @@ fn validate_and_turn_into_const<'tcx>( } } // Now that we validated, turn this into a proper constant. - // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides - // whether they become immediates. - if is_static || cid.promoted.is_some() { + // Statics/promoteds are always `ByRef`, for the rest `try_op_to_const` + // decides whether they become immediates. + let value = if !is_static && !cid.promoted.is_some() { + try_op_to_const(&ecx, mplace.into()) + } else { + Err(RefersToStatic) + }; + Ok(value.unwrap_or_else(|RefersToStatic| { let ptr = mplace.ptr.assert_ptr(); - Ok(ConstValue::ByRef { + ConstValue::ByRef { alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), offset: ptr.offset, - }) - } else { - Ok(op_to_const(&ecx, mplace.into())) - } + } + })) })(); val.map_err(|error| { diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index e53ca6b31bb67..41861617c782c 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -8,7 +8,6 @@ use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; use rustc_ast::ast::Mutability; -use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_span::symbol::Symbol; @@ -353,7 +352,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter { memory_extra: &MemoryExtra, alloc_id: AllocId, allocation: &Allocation, - static_def_id: Option, is_write: bool, ) -> InterpResult<'tcx> { if is_write { @@ -368,16 +366,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter { if memory_extra.can_access_statics { // Machine configuration allows us read from anything (e.g., `static` initializer). Ok(()) - } else if static_def_id.is_some() { - // Machine configuration does not allow us to read statics + } else if allocation.mutability != Mutability::Not { + // Machine configuration does not allow us to read mutable statics // (e.g., `const` initializer). + // This is unsound because the content of this allocation may be different now and + // at run-time, so if we permit reading it now we might return the wrong value. Err(ConstEvalErrKind::ConstAccessesStatic.into()) } else { // Immutable global, this read is fine. - // But make sure we never accept a read from something mutable, that would be - // unsound. The reason is that as the content of this allocation may be different - // now and at run-time, so if we permit reading now we might return the wrong value. - assert_eq!(allocation.mutability, Mutability::Not); Ok(()) } } diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs index e1146ef30d131..b74d96b9fbdc0 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -42,7 +42,7 @@ pub(crate) fn const_field<'tcx>( let field = ecx.operand_field(down, field.index()).unwrap(); // and finally move back to the const world, always normalizing because // this is not called for statics. - op_to_const(&ecx, field) + try_op_to_const(&ecx, field).unwrap() } pub(crate) fn const_caller_location( @@ -81,7 +81,7 @@ pub(crate) fn destructure_const<'tcx>( let down = ecx.operand_downcast(op, variant).unwrap(); let fields_iter = (0..field_count).map(|i| { let field_op = ecx.operand_field(down, i).unwrap(); - let val = op_to_const(&ecx, field_op); + let val = try_op_to_const(&ecx, field_op).unwrap(); ty::Const::from_value(tcx, val, field_op.layout.ty) }); let fields = tcx.arena.alloc_from_iter(fields_iter); diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 8bf8d904cb29e..ee8de05650032 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -7,7 +7,6 @@ use std::hash::Hash; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; -use rustc_span::def_id::DefId; use super::{ AllocId, Allocation, AllocationExtra, Frame, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, @@ -207,13 +206,11 @@ pub trait Machine<'mir, 'tcx>: Sized { } /// Called before a global allocation is accessed. - /// `def_id` is `Some` if this is the "lazy" allocation of a static. #[inline] fn before_access_global( _memory_extra: &Self::MemoryExtra, _alloc_id: AllocId, _allocation: &Allocation, - _static_def_id: Option, _is_write: bool, ) -> InterpResult<'tcx> { Ok(()) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 9b2b7196fc0e9..263bd5698e2be 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -430,11 +430,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { is_write: bool, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let alloc = tcx.alloc_map.lock().get(id); - let (alloc, def_id) = match alloc { - Some(GlobalAlloc::Memory(mem)) => { - // Memory of a constant or promoted or anonymous memory referenced by a static. - (mem, None) - } + let alloc = match alloc { + // Memory of a constant or promoted or anonymous memory referenced by a static. + Some(GlobalAlloc::Memory(mem)) => mem, Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { @@ -466,12 +464,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { })?; // Make sure we use the ID of the resolved memory, not the lazy one! let id = raw_const.alloc_id; - let allocation = tcx.alloc_map.lock().unwrap_memory(id); - - (allocation, Some(def_id)) + tcx.alloc_map.lock().unwrap_memory(id) } }; - M::before_access_global(memory_extra, id, alloc, def_id, is_write)?; + M::before_access_global(memory_extra, id, alloc, is_write)?; let alloc = Cow::Borrowed(alloc); // We got tcx memory. Let the machine initialize its "extra" stuff. let (alloc, tag) = M::init_allocation_extra( diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 2dffd78d776bd..6f5dbd878c571 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -411,11 +411,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { return Ok(()); } + // FIXME: Statics referenced from consts are skipped. + // This avoids spurious "const accesses static" errors + // unrelated to validity, but is similarly unsound. if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { - throw_validation_failure!( - format_args!("a {} pointing to a static variable", kind), - self.path - ); + return Ok(()); } } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index cf1c70241bc6e..d138de33f9dfd 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; -use rustc_span::{def_id::DefId, Span}; +use rustc_span::Span; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout}; use rustc_trait_selection::traits; @@ -274,7 +274,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _memory_extra: &(), _alloc_id: AllocId, allocation: &Allocation, - _static_def_id: Option, is_write: bool, ) -> InterpResult<'tcx> { if is_write { diff --git a/src/test/ui/consts/const-points-to-static.rs b/src/test/ui/consts/const-points-to-static.rs index b998b7a97be4e..8c786a7c57015 100644 --- a/src/test/ui/consts/const-points-to-static.rs +++ b/src/test/ui/consts/const-points-to-static.rs @@ -1,10 +1,10 @@ +// check-pass // compile-flags: -Zunleash-the-miri-inside-of-you #![allow(dead_code)] const TEST: &u8 = &MY_STATIC; //~^ skipping const checks -//~| it is undefined behavior to use this value static MY_STATIC: u8 = 4; diff --git a/src/test/ui/consts/const-points-to-static.stderr b/src/test/ui/consts/const-points-to-static.stderr index 62e59531c1e9f..5856056e99356 100644 --- a/src/test/ui/consts/const-points-to-static.stderr +++ b/src/test/ui/consts/const-points-to-static.stderr @@ -1,17 +1,8 @@ warning: skipping const checks - --> $DIR/const-points-to-static.rs:5:20 + --> $DIR/const-points-to-static.rs:6:20 | LL | const TEST: &u8 = &MY_STATIC; | ^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/const-points-to-static.rs:5:1 - | -LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to a static variable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error: aborting due to previous error; 1 warning emitted +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-prop-read-static-in-const.rs b/src/test/ui/consts/const-prop-read-static-in-const.rs index 14ec064e4ceef..8882c03cabe80 100644 --- a/src/test/ui/consts/const-prop-read-static-in-const.rs +++ b/src/test/ui/consts/const-prop-read-static-in-const.rs @@ -1,8 +1,9 @@ +// check-pass // compile-flags: -Zunleash-the-miri-inside-of-you #![allow(dead_code)] -const TEST: u8 = MY_STATIC; //~ ERROR any use of this value will cause an error +const TEST: u8 = MY_STATIC; //~^ skipping const checks static MY_STATIC: u8 = 4; diff --git a/src/test/ui/consts/const-prop-read-static-in-const.stderr b/src/test/ui/consts/const-prop-read-static-in-const.stderr index 0da2dbc888a63..d1807d260afa5 100644 --- a/src/test/ui/consts/const-prop-read-static-in-const.stderr +++ b/src/test/ui/consts/const-prop-read-static-in-const.stderr @@ -1,18 +1,8 @@ warning: skipping const checks - --> $DIR/const-prop-read-static-in-const.rs:5:18 + --> $DIR/const-prop-read-static-in-const.rs:6:18 | LL | const TEST: u8 = MY_STATIC; | ^^^^^^^^^ -error: any use of this value will cause an error - --> $DIR/const-prop-read-static-in-const.rs:5:18 - | -LL | const TEST: u8 = MY_STATIC; - | -----------------^^^^^^^^^- - | | - | constant accesses static - | - = note: `#[deny(const_err)]` on by default - -error: aborting due to previous error; 1 warning emitted +warning: 1 warning emitted diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs b/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs index edbf0e02d8de2..f3a6d38942952 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -1,3 +1,4 @@ +// check-pass // compile-flags: -Zunleash-the-miri-inside-of-you #![warn(const_err)] @@ -6,12 +7,31 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; -const REF_INTERIOR_MUT: &usize = { //~ ERROR undefined behavior to use this value +// Dynamically okay; does not touch any mutable static data: + +const READ_IMMUT: &usize = { + static FOO: usize = 0; + &FOO + //~^ WARN skipping const checks +}; + +const DEREF_IMMUT: usize = *READ_IMMUT; + +const REF_INTERIOR_MUT: &usize = { static FOO: AtomicUsize = AtomicUsize::new(0); unsafe { &*(&FOO as *const _ as *const usize) } //~^ WARN skipping const checks }; +extern { static EXTERN: usize; } +const REF_EXTERN: &usize = unsafe { &EXTERN }; +//~^ WARN skipping const checks + +// Not okay; uses of these consts would read or write mutable static data: + +const DEREF_INTERIOR_MUT: usize = *REF_INTERIOR_MUT; +//~^ WARN any use of this value will cause an error + const MUTATE_INTERIOR_MUT: usize = { static FOO: AtomicUsize = AtomicUsize::new(0); FOO.fetch_add(1, Ordering::Relaxed) //~ WARN any use of this value will cause an error @@ -30,10 +50,7 @@ const READ_MUT: u32 = unsafe { MUTABLE }; //~ WARN any use of this value will ca //~^ WARN skipping const checks //~| WARN skipping const checks -// ok some day perhaps -const READ_IMMUT: &usize = { //~ ERROR it is undefined behavior to use this value - static FOO: usize = 0; - &FOO - //~^ WARN skipping const checks -}; +const READ_EXTERN: usize = unsafe { EXTERN }; //~ WARN any use of this value will cause an error +//~^ WARN skipping const checks + fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index 92e782612b253..04f6c1e7f96cf 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -1,59 +1,73 @@ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:11:18 + --> $DIR/const_refers_to_static.rs:14:6 + | +LL | &FOO + | ^^^ + +warning: skipping const checks + --> $DIR/const_refers_to_static.rs:22:18 | LL | unsafe { &*(&FOO as *const _ as *const usize) } | ^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:17:5 + --> $DIR/const_refers_to_static.rs:27:38 + | +LL | const REF_EXTERN: &usize = unsafe { &EXTERN }; + | ^^^^^^ + +warning: skipping const checks + --> $DIR/const_refers_to_static.rs:37:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) | ^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:17:5 + --> $DIR/const_refers_to_static.rs:37:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:24:17 + --> $DIR/const_refers_to_static.rs:44:17 | LL | unsafe { *(&FOO as *const _ as *const usize) } | ^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:29:32 + --> $DIR/const_refers_to_static.rs:49:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | ^^^^^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:29:32 + --> $DIR/const_refers_to_static.rs:49:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | ^^^^^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:36:6 + --> $DIR/const_refers_to_static.rs:53:37 | -LL | &FOO - | ^^^ +LL | const READ_EXTERN: usize = unsafe { EXTERN }; + | ^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static.rs:9:1 +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static.rs:32:35 | -LL | / const REF_INTERIOR_MUT: &usize = { -LL | | static FOO: AtomicUsize = AtomicUsize::new(0); -LL | | unsafe { &*(&FOO as *const _ as *const usize) } -LL | | -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const DEREF_INTERIOR_MUT: usize = *REF_INTERIOR_MUT; + | ----------------------------------^^^^^^^^^^^^^^^^^- + | | + | constant accesses static | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. +note: the lint level is defined here + --> $DIR/const_refers_to_static.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ warning: any use of this value will cause an error - --> $DIR/const_refers_to_static.rs:17:5 + --> $DIR/const_refers_to_static.rs:37:5 | LL | / const MUTATE_INTERIOR_MUT: usize = { LL | | static FOO: AtomicUsize = AtomicUsize::new(0); @@ -63,15 +77,9 @@ LL | | LL | | LL | | }; | |__- - | -note: the lint level is defined here - --> $DIR/const_refers_to_static.rs:2:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ warning: any use of this value will cause an error - --> $DIR/const_refers_to_static.rs:24:14 + --> $DIR/const_refers_to_static.rs:44:14 | LL | / const READ_INTERIOR_MUT: usize = { LL | | static FOO: AtomicUsize = AtomicUsize::new(0); @@ -82,25 +90,20 @@ LL | | }; | |__- warning: any use of this value will cause an error - --> $DIR/const_refers_to_static.rs:29:32 + --> $DIR/const_refers_to_static.rs:49:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | -------------------------------^^^^^^^--- | | | constant accesses static -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static.rs:34:1 - | -LL | / const READ_IMMUT: &usize = { -LL | | static FOO: usize = 0; -LL | | &FOO -LL | | -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static.rs:53:37 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. +LL | const READ_EXTERN: usize = unsafe { EXTERN }; + | ------------------------------------^^^^^^--- + | | + | cannot read from foreign (extern) static DefId(0:11 ~ const_refers_to_static[317d]::[0]::EXTERN[0]) -error: aborting due to 2 previous errors; 10 warnings emitted +warning: 14 warnings emitted -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/miri_unleashed/use-static-via-const.rs b/src/test/ui/consts/miri_unleashed/use-static-via-const.rs new file mode 100644 index 0000000000000..f0db4c9aa4065 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/use-static-via-const.rs @@ -0,0 +1,29 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you + +static DATA: [u8; 3] = *b"abc"; + +const REF: &'static [u8] = &DATA; +//~^ WARN skipping const checks + +const PTR: *const u8 = DATA.as_ptr(); +//~^ WARN skipping const checks + +fn parse_slice(r: &[u8]) -> bool { + match r { + REF => true, + _ => false, + } +} + +fn parse_id(p: *const u8) -> bool { + match p { + p if p == PTR => true, + _ => false, + } +} + +fn main() { + assert!(parse_slice(&DATA)); + assert!(parse_id(DATA.as_ptr())); +} diff --git a/src/test/ui/consts/miri_unleashed/use-static-via-const.stderr b/src/test/ui/consts/miri_unleashed/use-static-via-const.stderr new file mode 100644 index 0000000000000..395b977b5df33 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/use-static-via-const.stderr @@ -0,0 +1,14 @@ +warning: skipping const checks + --> $DIR/use-static-via-const.rs:6:29 + | +LL | const REF: &'static [u8] = &DATA; + | ^^^^ + +warning: skipping const checks + --> $DIR/use-static-via-const.rs:9:24 + | +LL | const PTR: *const u8 = DATA.as_ptr(); + | ^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/ui/issues/issue-52060.rs b/src/test/ui/issues/issue-52060.rs index fed08902c8b9d..13b914c0331d1 100644 --- a/src/test/ui/issues/issue-52060.rs +++ b/src/test/ui/issues/issue-52060.rs @@ -3,6 +3,5 @@ static A: &'static [u32] = &[1]; static B: [u32; 1] = [0; A.len()]; //~^ ERROR [E0013] -//~| ERROR evaluation of constant value failed fn main() {} diff --git a/src/test/ui/issues/issue-52060.stderr b/src/test/ui/issues/issue-52060.stderr index 502825e9766e3..95e5f2a8282cb 100644 --- a/src/test/ui/issues/issue-52060.stderr +++ b/src/test/ui/issues/issue-52060.stderr @@ -6,13 +6,6 @@ LL | static B: [u32; 1] = [0; A.len()]; | = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0080]: evaluation of constant value failed - --> $DIR/issue-52060.rs:4:26 - | -LL | static B: [u32; 1] = [0; A.len()]; - | ^ constant accesses static - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0013, E0080. -For more information about an error, try `rustc --explain E0013`. +For more information about this error, try `rustc --explain E0013`.