diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs index 46bf1d9695796..6e699b328a2a8 100644 --- a/src/librustc/mir/interpret/queries.rs +++ b/src/librustc/mir/interpret/queries.rs @@ -1,6 +1,7 @@ use super::{ConstEvalResult, ErrorHandled, GlobalId}; use crate::mir; +use crate::ty::fold::TypeFoldable; use crate::ty::subst::{InternalSubsts, SubstsRef}; use crate::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; @@ -9,7 +10,7 @@ use rustc_span::Span; impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a - /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + /// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned. pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { // In some situations def_id will have substitutions within scope, but they aren't allowed // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions @@ -18,7 +19,13 @@ impl<'tcx> TyCtxt<'tcx> { let substs = InternalSubsts::identity_for_item(self, def_id); let instance = ty::Instance::new(def_id, substs); let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all(); + let needs_subst = instance.needs_subst(); + let param_env = if needs_subst { + self.param_env(def_id) + } else { + self.param_env(def_id).with_reveal_all() + }; + debug!("const_eval_poly: needs_subst = {:?}. param_env = {:?}", needs_subst, param_env); self.const_eval_global_id(param_env, cid, None) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 906e46edfe7ff..d2500941cf195 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -47,7 +47,7 @@ use rustc_trait_selection::traits::misc::can_type_implement_copy; use crate::nonstandard_style::{method_context, MethodLateContext}; -use log::debug; +use log::{debug, trace}; use std::fmt::Write; // hardwired lints from librustc @@ -1181,16 +1181,22 @@ fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) { + trace!("UnusedBrokenConst: check_item(_, _, {:?}", it); match it.kind { - hir::ItemKind::Const(_, body_id) => { - check_const(cx, body_id); - } - hir::ItemKind::Static(_, _, body_id) => { + hir::ItemKind::Const(_, body_id) | hir::ItemKind::Static(_, _, body_id) => { + trace!("UnusedBrokenConst: checking {:?}", body_id); check_const(cx, body_id); } _ => {} } } + fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ImplItem<'_>) { + trace!("UnusedBrokenConst: check_impl_item(_, _, it = {:?})", it); + if let hir::ImplItemKind::Const(_, body_id) = it.kind { + trace!("UnusedBrokenConst: checking {:?}", body_id); + check_const(cx, body_id); + } + } } declare_lint! { diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index ffbff00cf3760..fe6e3df5a1f69 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -181,6 +181,8 @@ fn validate_and_turn_into_const<'tcx>( let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; + debug!("validate_and_turn_into_const: mplace = {:?}", mplace); + // FIXME do not validate promoteds until a decision on // https://github.com/rust-lang/rust/issues/67465 is made if cid.promoted.is_none() { @@ -209,6 +211,7 @@ fn validate_and_turn_into_const<'tcx>( })(); val.map_err(|error| { + trace!("Validation failed: {:?}", error); let err = error_to_const_error(&ecx, error); match err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { diag.note(note_on_undefined_behavior_error()); @@ -251,7 +254,14 @@ pub fn const_eval_validated_provider<'tcx>( }); } - tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key)) + tcx.const_eval_raw(key).and_then(|val| { + trace!( + "const_eval_raw succeeded. val.alloc_id = {:?}. val.ty = {:?}", + val.alloc_id, + val.ty + ); + validate_and_turn_into_const(tcx, val, key) + }) } pub fn const_eval_raw_provider<'tcx>( @@ -271,7 +281,9 @@ pub fn const_eval_raw_provider<'tcx>( key.param_env.reveal = Reveal::UserFacing; match tcx.const_eval_raw(key) { // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} + Err(ErrorHandled::TooGeneric) => { + trace!("const_eval_raw: retrying with RevealAll"); + } // deduplicate calls other => return other, } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c2baabf4233ce..905cbe5e566e9 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -206,9 +206,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { #[inline] fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { - self.tcx - .layout_of(self.param_env.and(ty)) - .map_err(|layout| err_inval!(Layout(layout)).into()) + self.tcx.layout_of(self.param_env.and(ty)).map_err(|layout| { + let result = err_inval!(Layout(layout)).into(); + trace!("layout_of: returning error: {:?}", result); + result + }) } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 94c9a8b2a6d59..f533ca026867f 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -305,7 +305,9 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let pointee_type = val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; - let layout = self.layout_of(pointee_type)?; + let layout = self.layout_of(pointee_type); + debug!("ref_to_mplace: layout_of(pointee_type = {:?}) = {:?}", pointee_type, layout); + let layout = layout?; let (ptr, meta) = match *val { Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None), Immediate::ScalarPair(ptr, meta) => { @@ -1134,6 +1136,7 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // This must be an allocation in `tcx` assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some()); + trace!("raw_const_to_mplace: raw.ty = {:?}", raw.ty); let ptr = self.tag_global_base_pointer(Pointer::from(raw.alloc_id)); let layout = self.layout_of(raw.ty)?; Ok(MPlaceTy::from_aligned_ptr(ptr, layout)) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index a355a22748010..3cda575ad97ca 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -475,15 +475,25 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M Ok(true) } ty::RawPtr(..) => { - // We are conservative with undef for integers, but try to - // actually enforce our current rules for raw pointers. - let place = try_validation!( - self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), - "undefined pointer", - self.path - ); - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; + let imm = self.ecx.read_immediate(value)?; + let pointee_kind = &imm.layout.ty.builtin_deref(true).unwrap().ty.kind; + match pointee_kind { + ty::Param(_) => { + // Creating pointers to T is valid. We only reach this case for unused + // associated consts. + } + _ => { + // We are conservative with undef for integers, but try to + // actually enforce our current rules for raw pointers. + let place = try_validation!( + self.ecx.ref_to_mplace(imm), + "undefined pointer", + self.path + ); + if place.layout.is_unsized() { + self.check_wide_ptr_meta(place.meta, place.layout)?; + } + } } Ok(true) } diff --git a/src/test/ui/associated-const/lints-used-unused.rs b/src/test/ui/associated-const/lints-used-unused.rs new file mode 100644 index 0000000000000..8d34351a7d1e6 --- /dev/null +++ b/src/test/ui/associated-const/lints-used-unused.rs @@ -0,0 +1,29 @@ +// Tests that associated constants are checked whether they are used or not. +// +// revisions: used unused +// compile-flags: -Copt-level=2 --emit link + +#![cfg_attr(unused, allow(dead_code))] +#![deny(arithmetic_overflow)] + +pub trait Foo { + const N: i32; +} + +struct S; + +impl Foo for S { + const N: i32 = 1 << 42; + //~^ ERROR this arithmetic operation will overflow + //~| ERROR any use of this value will cause an error +} + +impl Foo for Vec { + const N: i32 = --T::N + (-i32::MIN); + //~^ ERROR this arithmetic operation will overflow +} + +fn main() { + #[cfg(used)] + let _ = S::N; // FIXME: "erroneous constant used" -- awaiting #67176 +} diff --git a/src/test/ui/associated-const/lints-used-unused.unused.stderr b/src/test/ui/associated-const/lints-used-unused.unused.stderr new file mode 100644 index 0000000000000..cc50d342f2537 --- /dev/null +++ b/src/test/ui/associated-const/lints-used-unused.unused.stderr @@ -0,0 +1,30 @@ +error: this arithmetic operation will overflow + --> $DIR/lints-used-unused.rs:16:20 + | +LL | const N: i32 = 1 << 42; + | ^^^^^^^ attempt to shift left with overflow + | +note: the lint level is defined here + --> $DIR/lints-used-unused.rs:7:9 + | +LL | #![deny(arithmetic_overflow)] + | ^^^^^^^^^^^^^^^^^^^ + +error: any use of this value will cause an error + --> $DIR/lints-used-unused.rs:16:20 + | +LL | const N: i32 = 1 << 42; + | ---------------^^^^^^^- + | | + | attempt to shift left with overflow + | + = note: `#[deny(const_err)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/lints-used-unused.rs:22:29 + | +LL | const N: i32 = --T::N + (-i32::MIN); + | ^^^^^^^^^^^ attempt to negate with overflow + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/associated-const/lints-used-unused.used.stderr b/src/test/ui/associated-const/lints-used-unused.used.stderr new file mode 100644 index 0000000000000..cc50d342f2537 --- /dev/null +++ b/src/test/ui/associated-const/lints-used-unused.used.stderr @@ -0,0 +1,30 @@ +error: this arithmetic operation will overflow + --> $DIR/lints-used-unused.rs:16:20 + | +LL | const N: i32 = 1 << 42; + | ^^^^^^^ attempt to shift left with overflow + | +note: the lint level is defined here + --> $DIR/lints-used-unused.rs:7:9 + | +LL | #![deny(arithmetic_overflow)] + | ^^^^^^^^^^^^^^^^^^^ + +error: any use of this value will cause an error + --> $DIR/lints-used-unused.rs:16:20 + | +LL | const N: i32 = 1 << 42; + | ---------------^^^^^^^- + | | + | attempt to shift left with overflow + | + = note: `#[deny(const_err)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/lints-used-unused.rs:22:29 + | +LL | const N: i32 = --T::N + (-i32::MIN); + | ^^^^^^^^^^^ attempt to negate with overflow + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/issue-69020.noopt.stderr b/src/test/ui/consts/issue-69020.noopt.stderr index c48a106ef4656..dec88bf343590 100644 --- a/src/test/ui/consts/issue-69020.noopt.stderr +++ b/src/test/ui/consts/issue-69020.noopt.stderr @@ -6,25 +6,59 @@ LL | const NEG: i32 = -i32::MIN + T::NEG; | = note: `#[deny(arithmetic_overflow)]` on by default +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:21:22 + | +LL | const NEG: i32 = -i32::MIN + T::NEG; + | -----------------^^^^^^^^^---------- + | | + | attempt to negate with overflow + | + = note: `#[deny(const_err)]` on by default + error: this arithmetic operation will overflow - --> $DIR/issue-69020.rs:23:22 + --> $DIR/issue-69020.rs:24:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; | ^^^^^^^^^^^^ attempt to add with overflow +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:24:22 + | +LL | const ADD: i32 = (i32::MAX+1) + T::ADD; + | -----------------^^^^^^^^^^^^---------- + | | + | attempt to add with overflow + error: this operation will panic at runtime - --> $DIR/issue-69020.rs:25:22 + --> $DIR/issue-69020.rs:27:22 | LL | const DIV: i32 = (1/0) + T::DIV; | ^^^^^ attempt to divide by zero | = note: `#[deny(unconditional_panic)]` on by default -error: this operation will panic at runtime +error: any use of this value will cause an error --> $DIR/issue-69020.rs:27:22 | +LL | const DIV: i32 = (1/0) + T::DIV; + | -----------------^^^^^---------- + | | + | attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:30:22 + | LL | const OOB: i32 = [1][1] + T::OOB; | ^^^^^^ index out of bounds: the len is 1 but the index is 1 -error: aborting due to 4 previous errors +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:30:22 + | +LL | const OOB: i32 = [1][1] + T::OOB; + | -----------------^^^^^^---------- + | | + | index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/issue-69020.opt.stderr b/src/test/ui/consts/issue-69020.opt.stderr index c48a106ef4656..dec88bf343590 100644 --- a/src/test/ui/consts/issue-69020.opt.stderr +++ b/src/test/ui/consts/issue-69020.opt.stderr @@ -6,25 +6,59 @@ LL | const NEG: i32 = -i32::MIN + T::NEG; | = note: `#[deny(arithmetic_overflow)]` on by default +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:21:22 + | +LL | const NEG: i32 = -i32::MIN + T::NEG; + | -----------------^^^^^^^^^---------- + | | + | attempt to negate with overflow + | + = note: `#[deny(const_err)]` on by default + error: this arithmetic operation will overflow - --> $DIR/issue-69020.rs:23:22 + --> $DIR/issue-69020.rs:24:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; | ^^^^^^^^^^^^ attempt to add with overflow +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:24:22 + | +LL | const ADD: i32 = (i32::MAX+1) + T::ADD; + | -----------------^^^^^^^^^^^^---------- + | | + | attempt to add with overflow + error: this operation will panic at runtime - --> $DIR/issue-69020.rs:25:22 + --> $DIR/issue-69020.rs:27:22 | LL | const DIV: i32 = (1/0) + T::DIV; | ^^^^^ attempt to divide by zero | = note: `#[deny(unconditional_panic)]` on by default -error: this operation will panic at runtime +error: any use of this value will cause an error --> $DIR/issue-69020.rs:27:22 | +LL | const DIV: i32 = (1/0) + T::DIV; + | -----------------^^^^^---------- + | | + | attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:30:22 + | LL | const OOB: i32 = [1][1] + T::OOB; | ^^^^^^ index out of bounds: the len is 1 but the index is 1 -error: aborting due to 4 previous errors +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:30:22 + | +LL | const OOB: i32 = [1][1] + T::OOB; + | -----------------^^^^^^---------- + | | + | index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr b/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr index c48a106ef4656..dec88bf343590 100644 --- a/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr @@ -6,25 +6,59 @@ LL | const NEG: i32 = -i32::MIN + T::NEG; | = note: `#[deny(arithmetic_overflow)]` on by default +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:21:22 + | +LL | const NEG: i32 = -i32::MIN + T::NEG; + | -----------------^^^^^^^^^---------- + | | + | attempt to negate with overflow + | + = note: `#[deny(const_err)]` on by default + error: this arithmetic operation will overflow - --> $DIR/issue-69020.rs:23:22 + --> $DIR/issue-69020.rs:24:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; | ^^^^^^^^^^^^ attempt to add with overflow +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:24:22 + | +LL | const ADD: i32 = (i32::MAX+1) + T::ADD; + | -----------------^^^^^^^^^^^^---------- + | | + | attempt to add with overflow + error: this operation will panic at runtime - --> $DIR/issue-69020.rs:25:22 + --> $DIR/issue-69020.rs:27:22 | LL | const DIV: i32 = (1/0) + T::DIV; | ^^^^^ attempt to divide by zero | = note: `#[deny(unconditional_panic)]` on by default -error: this operation will panic at runtime +error: any use of this value will cause an error --> $DIR/issue-69020.rs:27:22 | +LL | const DIV: i32 = (1/0) + T::DIV; + | -----------------^^^^^---------- + | | + | attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:30:22 + | LL | const OOB: i32 = [1][1] + T::OOB; | ^^^^^^ index out of bounds: the len is 1 but the index is 1 -error: aborting due to 4 previous errors +error: any use of this value will cause an error + --> $DIR/issue-69020.rs:30:22 + | +LL | const OOB: i32 = [1][1] + T::OOB; + | -----------------^^^^^^---------- + | | + | index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/issue-69020.rs b/src/test/ui/consts/issue-69020.rs index e079feb04d447..8ee14466799af 100644 --- a/src/test/ui/consts/issue-69020.rs +++ b/src/test/ui/consts/issue-69020.rs @@ -20,10 +20,14 @@ pub trait Foo { impl Foo for Vec { const NEG: i32 = -i32::MIN + T::NEG; //~^ ERROR arithmetic operation will overflow + //~| ERROR any use of this value will cause an error const ADD: i32 = (i32::MAX+1) + T::ADD; //~^ ERROR arithmetic operation will overflow + //~| ERROR any use of this value will cause an error const DIV: i32 = (1/0) + T::DIV; //~^ ERROR operation will panic + //~| ERROR any use of this value will cause an error const OOB: i32 = [1][1] + T::OOB; //~^ ERROR operation will panic + //~| ERROR any use of this value will cause an error } diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs index 7deee5320a878..ca3d502293d04 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs @@ -15,7 +15,7 @@ pub trait Foo { } impl Foo for Vec { - const N: i32 = T::N << 42; // FIXME this should warn + const N: i32 = T::N << 42; // ERROR: arithmetic operation will overflow } pub fn foo(x: i32) {