From 25a8b5d58e3899084e191ffd9456f39d29c3263b Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 27 Dec 2019 11:44:36 -0500 Subject: [PATCH 1/8] Fix `Instance::resolve()` incorrectly returning specialized instances We only want to return specializations when `Reveal::All` is passed, not when `Reveal::UserFacing` is. Resolving this fixes several issues with the `ConstProp`, `SimplifyBranches`, and `Inline` MIR optimization passes. Fixes #66901 --- src/librustc/mir/interpret/queries.rs | 2 +- src/librustc/traits/project.rs | 3 + src/librustc/ty/instance.rs | 19 ++++++ src/librustc_mir/const_eval/eval_queries.rs | 22 ++++--- src/librustc_mir/hair/pattern/mod.rs | 8 ++- src/librustc_mir/transform/const_prop.rs | 14 +++- src/librustc_mir/transform/inline.rs | 13 +++- .../mir-opt/inline/inline-specialization.rs | 48 ++++++++++++++ src/test/ui/consts/trait_specialization.rs | 65 +++++++++++++++++++ .../self-in-enum-definition.stderr | 5 ++ 10 files changed, 182 insertions(+), 17 deletions(-) create mode 100644 src/test/mir-opt/inline/inline-specialization.rs create mode 100644 src/test/ui/consts/trait_specialization.rs diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs index e6caa146a627f..c593a51e457b8 100644 --- a/src/librustc/mir/interpret/queries.rs +++ b/src/librustc/mir/interpret/queries.rs @@ -18,7 +18,7 @@ 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); + let param_env = self.param_env(def_id).with_reveal_all(); self.const_eval_validated(param_env.and(cid)) } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 90381895f0a33..bcb012ea51494 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1028,6 +1028,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // In either case, we handle this by not adding a // candidate for an impl if it contains a `default` // type. + // + // NOTE: This should be kept in sync with the similar code in + // `rustc::ty::instance::resolve_associated_item()`. let node_item = assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id); diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index faa83ceaddea2..cfd1779c080ec 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -346,6 +346,25 @@ fn resolve_associated_item<'tcx>( traits::VtableImpl(impl_data) => { let (def_id, substs) = traits::find_associated_item(tcx, param_env, trait_item, rcvr_substs, &impl_data); + + let resolved_item = tcx.associated_item(def_id); + + // Since this is a trait item, we need to see if the item is either a trait default item + // or a specialization because we can't resolve those unless we can `Reveal::All`. + // NOTE: This should be kept in sync with the similar code in + // `rustc::traits::project::assemble_candidates_from_impls()`. + let eligible = if !resolved_item.defaultness.is_default() { + true + } else if param_env.reveal == traits::Reveal::All { + !trait_ref.needs_subst() + } else { + false + }; + + if !eligible { + return None; + } + let substs = tcx.erase_regions(&substs); Some(ty::Instance::new(def_id, substs)) } diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 745b6aabfa6bb..6c4b69d9d767e 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -212,11 +212,7 @@ pub fn const_eval_validated_provider<'tcx>( key.param_env.reveal = Reveal::UserFacing; match tcx.const_eval_validated(key) { // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => { - // Promoteds should never be "too generic" when getting evaluated. - // They either don't get evaluated, or we are in a monomorphic context - assert!(key.value.promoted.is_none()); - } + Err(ErrorHandled::TooGeneric) => {} // dedupliate calls other => return other, } @@ -301,10 +297,18 @@ pub fn const_eval_raw_provider<'tcx>( // Ensure that if the above error was either `TooGeneric` or `Reported` // an error must be reported. let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); - tcx.sess.delay_span_bug( - err.span, - &format!("static eval failure did not emit an error: {:#?}", v), - ); + + // If this is `Reveal:All`, then we need to make sure an error is reported but if + // this is `Reveal::UserFacing`, then it's expected that we could get a + // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either + // succeed or we'll report this error then. + if key.param_env.reveal == Reveal::All { + tcx.sess.delay_span_bug( + err.span, + &format!("static eval failure did not emit an error: {:#?}", v), + ); + } + v } else if def_id.is_local() { // constant defined in this crate, we can figure out a lint level! diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6dd3c0f80da24..8c380589151e8 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -742,7 +742,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let kind = match res { Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { let substs = self.tables.node_substs(id); - match self.tcx.const_eval_resolve(self.param_env, def_id, substs, Some(span)) { + // Use `Reveal::All` here because patterns are always monomorphic even if their function isn't. + match self.tcx.const_eval_resolve( + self.param_env.with_reveal_all(), + def_id, + substs, + Some(span), + ) { Ok(value) => { let pattern = self.const_to_pat(value, id, span); if !is_associated_const { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index a6b30ab5e68cf..62717daed1642 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -33,6 +33,7 @@ use crate::interpret::{ ScalarMaybeUndef, StackPopCleanup, }; use crate::rustc::ty::subst::Subst; +use crate::rustc::ty::TypeFoldable; use crate::transform::{MirPass, MirSource}; /// The maximum number of bytes that we'll allocate space for a return value. @@ -293,13 +294,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source: MirSource<'tcx>, ) -> ConstPropagator<'mir, 'tcx> { let def_id = source.def_id(); - let param_env = tcx.param_env(def_id); + let substs = &InternalSubsts::identity_for_item(tcx, def_id); + let mut param_env = tcx.param_env(def_id); + + // If we're evaluating inside a monomorphic function, then use `Reveal::All` because + // we want to see the same instances that codegen will see. This allows us to `resolve()` + // specializations. + if !substs.needs_subst() { + param_env = param_env.with_reveal_all(); + } + let span = tcx.def_span(def_id); let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine, ()); let can_const_prop = CanConstProp::check(body); - let substs = &InternalSubsts::identity_for_item(tcx, def_id); - let ret = ecx .layout_of(body.return_ty().subst(tcx, substs)) .ok() diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index aa0c71ff0f176..98cd341770965 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -8,8 +8,8 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc::mir::visit::*; use rustc::mir::*; -use rustc::ty::subst::{Subst, SubstsRef}; -use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; use crate::transform::{MirPass, MirSource}; @@ -66,7 +66,14 @@ impl Inliner<'tcx> { let mut callsites = VecDeque::new(); - let param_env = self.tcx.param_env(self.source.def_id()); + let mut param_env = self.tcx.param_env(self.source.def_id()); + + let substs = &InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); + + // For monomorphic functions, we can use `Reveal::All` to resolve specialized instances. + if !substs.needs_subst() { + param_env = param_env.with_reveal_all(); + } // Only do inlining into fn bodies. let id = self.tcx.hir().as_local_hir_id(self.source.def_id()).unwrap(); diff --git a/src/test/mir-opt/inline/inline-specialization.rs b/src/test/mir-opt/inline/inline-specialization.rs new file mode 100644 index 0000000000000..9591019bb4f70 --- /dev/null +++ b/src/test/mir-opt/inline/inline-specialization.rs @@ -0,0 +1,48 @@ +#![feature(specialization)] + +fn main() { + let x = as Foo>::bar(); +} + +trait Foo { + fn bar() -> u32; +} + +impl Foo for Vec { + #[inline(always)] + default fn bar() -> u32 { 123 } +} + +// END RUST SOURCE +// START rustc.main.Inline.before.mir +// let mut _0: (); +// let _1: u32; +// scope 1 { +// debug x => _1; +// } +// bb0: { +// StorageLive(_1); +// _1 = const as Foo>::bar() -> bb1; +// } +// bb1: { +// _0 = (); +// StorageDead(_1); +// return; +// } +// END rustc.main.Inline.before.mir +// START rustc.main.Inline.after.mir +// let mut _0: (); +// let _1: u32; +// scope 1 { +// debug x => _1; +// } +// scope 2 { +// } +// bb0: { +// StorageLive(_1); +// _1 = const 123u32; +// _0 = (); +// StorageDead(_1); +// return; +// } +// END rustc.main.Inline.after.mir diff --git a/src/test/ui/consts/trait_specialization.rs b/src/test/ui/consts/trait_specialization.rs new file mode 100644 index 0000000000000..8010d2fe1aee9 --- /dev/null +++ b/src/test/ui/consts/trait_specialization.rs @@ -0,0 +1,65 @@ +// ignore-wasm32-bare which doesn't support `std::process:exit()` +// compile-flags: -Zmir-opt-level=2 +// run-pass + +// Tests that specialization does not cause optimizations running on polymorphic MIR to resolve +// to a `default` implementation. + +#![feature(specialization)] + +trait Marker {} + +trait SpecializedTrait { + const CONST_BOOL: bool; + const CONST_STR: &'static str; + fn method() -> &'static str; +} +impl SpecializedTrait for T { + default const CONST_BOOL: bool = false; + default const CONST_STR: &'static str = "in default impl"; + #[inline(always)] + default fn method() -> &'static str { + "in default impl" + } +} +impl SpecializedTrait for T { + const CONST_BOOL: bool = true; + const CONST_STR: &'static str = "in specialized impl"; + fn method() -> &'static str { + "in specialized impl" + } +} + +fn const_bool() -> &'static str { + if ::CONST_BOOL { + "in specialized impl" + } else { + "in default impl" + } +} +fn const_str() -> &'static str { + ::CONST_STR +} +fn run_method() -> &'static str { + ::method() +} + +struct TypeA; +impl Marker for TypeA {} +struct TypeB; + +#[inline(never)] +fn exit_if_not_eq(left: &str, right: &str) { + if left != right { + std::process::exit(1); + } +} + +pub fn main() { + exit_if_not_eq("in specialized impl", const_bool::()); + exit_if_not_eq("in default impl", const_bool::()); + exit_if_not_eq("in specialized impl", const_str::()); + exit_if_not_eq("in default impl", const_str::()); + exit_if_not_eq("in specialized impl", run_method::()); + exit_if_not_eq("in default impl", run_method::()); +} diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index dc4050e44abb1..db535b53fcf37 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -4,6 +4,11 @@ error[E0391]: cycle detected when const-evaluating + checking `Alpha::V3::{{cons LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ | +note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`... + --> $DIR/self-in-enum-definition.rs:5:10 + | +LL | V3 = Self::V1 {} as u8 + 2, + | ^^^^^^^^ note: ...which requires const-evaluating `Alpha::V3::{{constant}}#0`... --> $DIR/self-in-enum-definition.rs:5:10 | From 3eb0585173deb61ed0ed3e15fad360882d894568 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Dec 2019 15:10:13 +0100 Subject: [PATCH 2/8] Work around a resolve bug in const prop --- src/librustc_mir/transform/const_prop.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 62717daed1642..bf8e63ebe3dfd 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -20,7 +20,7 @@ use rustc::ty::layout::{ HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, }; use rustc::ty::subst::InternalSubsts; -use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use syntax::ast::Mutability; @@ -418,6 +418,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { + // `eval_const_to_op` uses `Instance::resolve` which still has a bug (#66901) in the + // presence of trait items with a default body. So we just bail out if we aren't 100% + // monomorphic. + if c.literal.needs_subst() { + return None; + } self.ecx.tcx.span = c.span; match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => Some(op), From b3abebd78dcab1cadf7535271ff2ac6188b33cb8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Dec 2019 17:28:07 +0100 Subject: [PATCH 3/8] Prevent polymorphic const prop on assignments --- src/librustc_mir/transform/const_prop.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index bf8e63ebe3dfd..206f8043786d4 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -570,6 +570,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { _ => {} } + // `eval_rvalue_into_place` uses `Instance::resolve` for constants which still has a bug + // (#66901) in the presence of trait items with a default body. So we just bail out if we + // aren't 100% monomorphic. + if rvalue.needs_subst() { + return None; + } + self.use_ecx(source_info, |this| { trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); this.ecx.eval_rvalue_into_place(rvalue, place)?; From e3155abd2efd5d07a8bc323b1ea0a915616c7ae0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 8 Sep 2019 01:42:12 +0300 Subject: [PATCH 4/8] Stabilize attribute macros on inline modules --- src/libsyntax_expand/expand.rs | 11 ++--- .../proc-macro/attributes-on-modules-fail.rs | 21 ++++++++- .../attributes-on-modules-fail.stderr | 26 +++++------ .../ui/proc-macro/attributes-on-modules.rs | 8 +++- .../proc-macro/attributes-on-modules.stderr | 12 ----- src/test/ui/proc-macro/proc-macro-gates.rs | 6 +-- .../ui/proc-macro/proc-macro-gates.stderr | 46 ++++++------------- 7 files changed, 58 insertions(+), 72 deletions(-) delete mode 100644 src/test/ui/proc-macro/attributes-on-modules.stderr diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index b9b449d177915..4f6f88a753b2b 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -717,13 +717,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { let kind = match item { - Annotatable::Item(item) => match &item.kind { - ItemKind::Mod(m) if m.inline => "modules", - _ => return, - }, - Annotatable::TraitItem(_) | Annotatable::ImplItem(_) | Annotatable::ForeignItem(_) => { - return; - } + Annotatable::Item(_) + | Annotatable::TraitItem(_) + | Annotatable::ImplItem(_) + | Annotatable::ForeignItem(_) => return, Annotatable::Stmt(_) => "statements", Annotatable::Expr(_) => "expressions", Annotatable::Arm(..) diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.rs b/src/test/ui/proc-macro/attributes-on-modules-fail.rs index c8bc0b3437436..c506e903e7f89 100644 --- a/src/test/ui/proc-macro/attributes-on-modules-fail.rs +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.rs @@ -3,7 +3,7 @@ #[macro_use] extern crate test_macros; -#[identity_attr] //~ ERROR custom attributes cannot be applied to modules +#[identity_attr] mod m { pub struct X; @@ -19,11 +19,28 @@ mod n {} #[empty_attr] mod module; //~ ERROR non-inline modules in proc macro input are unstable -#[empty_attr] //~ ERROR custom attributes cannot be applied to modules +#[empty_attr] mod outer { mod inner; //~ ERROR non-inline modules in proc macro input are unstable mod inner_inline {} // OK } +#[derive(Empty)] +struct S { + field: [u8; { + #[path = "outer/inner.rs"] + mod inner; //~ ERROR non-inline modules in proc macro input are unstable + mod inner_inline {} // OK + 0 + }] +} + +#[identity_attr] +fn f() { + #[path = "outer/inner.rs"] + mod inner; //~ ERROR non-inline modules in proc macro input are unstable + mod inner_inline {} // OK +} + fn main() {} diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr index 34a5a5aaa54fb..74b9932a916c9 100644 --- a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr @@ -1,12 +1,3 @@ -error[E0658]: custom attributes cannot be applied to modules - --> $DIR/attributes-on-modules-fail.rs:6:1 - | -LL | #[identity_attr] - | ^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54727 - = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable - error: `derive` may only be applied to structs, enums and unions --> $DIR/attributes-on-modules-fail.rs:16:1 | @@ -31,11 +22,20 @@ LL | mod inner; = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to modules - --> $DIR/attributes-on-modules-fail.rs:22:1 +error[E0658]: non-inline modules in proc macro input are unstable + --> $DIR/attributes-on-modules-fail.rs:33:9 + | +LL | mod inner; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error[E0658]: non-inline modules in proc macro input are unstable + --> $DIR/attributes-on-modules-fail.rs:42:5 | -LL | #[empty_attr] - | ^^^^^^^^^^^^^ +LL | mod inner; + | ^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable diff --git a/src/test/ui/proc-macro/attributes-on-modules.rs b/src/test/ui/proc-macro/attributes-on-modules.rs index 12c3ac6d9475b..6c73b0bf19c7f 100644 --- a/src/test/ui/proc-macro/attributes-on-modules.rs +++ b/src/test/ui/proc-macro/attributes-on-modules.rs @@ -1,13 +1,19 @@ +// check-pass // aux-build:test-macros.rs #[macro_use] extern crate test_macros; -#[identity_attr] //~ ERROR custom attributes cannot be applied to modules +#[identity_attr] mod m { pub struct S; } +#[identity_attr] +fn f() { + mod m {} +} + fn main() { let s = m::S; } diff --git a/src/test/ui/proc-macro/attributes-on-modules.stderr b/src/test/ui/proc-macro/attributes-on-modules.stderr deleted file mode 100644 index df75f0bf4b149..0000000000000 --- a/src/test/ui/proc-macro/attributes-on-modules.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: custom attributes cannot be applied to modules - --> $DIR/attributes-on-modules.rs:6:1 - | -LL | #[identity_attr] - | ^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54727 - = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index 591c1e039bd75..5df6ac422ac4b 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -10,12 +10,8 @@ fn _test_inner() { #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable } -#[empty_attr] //~ ERROR: custom attributes cannot be applied to modules -mod _test2 {} - mod _test2_inner { - #![empty_attr] //~ ERROR: custom attributes cannot be applied to modules - //~| ERROR: non-builtin inner attributes are unstable + #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable } #[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index e939434243b6a..fff96572e340f 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -8,7 +8,7 @@ LL | #![empty_attr] = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable error[E0658]: non-builtin inner attributes are unstable - --> $DIR/proc-macro-gates.rs:17:5 + --> $DIR/proc-macro-gates.rs:14:5 | LL | #![empty_attr] | ^^^^^^^^^^^^^^ @@ -16,32 +16,14 @@ LL | #![empty_attr] = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to modules - --> $DIR/proc-macro-gates.rs:13:1 - | -LL | #[empty_attr] - | ^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54727 - = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable - -error[E0658]: custom attributes cannot be applied to modules - --> $DIR/proc-macro-gates.rs:17:5 - | -LL | #![empty_attr] - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54727 - = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable - error: key-value macro attributes are not supported - --> $DIR/proc-macro-gates.rs:21:1 + --> $DIR/proc-macro-gates.rs:17:1 | LL | #[empty_attr = "y"] | ^^^^^^^^^^^^^^^^^^^ error[E0658]: custom attributes cannot be applied to statements - --> $DIR/proc-macro-gates.rs:30:5 + --> $DIR/proc-macro-gates.rs:26:5 | LL | #[empty_attr] | ^^^^^^^^^^^^^ @@ -50,7 +32,7 @@ LL | #[empty_attr] = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: custom attributes cannot be applied to statements - --> $DIR/proc-macro-gates.rs:34:5 + --> $DIR/proc-macro-gates.rs:30:5 | LL | #[empty_attr] | ^^^^^^^^^^^^^ @@ -59,7 +41,7 @@ LL | #[empty_attr] = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: custom attributes cannot be applied to statements - --> $DIR/proc-macro-gates.rs:38:5 + --> $DIR/proc-macro-gates.rs:34:5 | LL | #[empty_attr] | ^^^^^^^^^^^^^ @@ -68,7 +50,7 @@ LL | #[empty_attr] = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: custom attributes cannot be applied to expressions - --> $DIR/proc-macro-gates.rs:42:14 + --> $DIR/proc-macro-gates.rs:38:14 | LL | let _x = #[identity_attr] 2; | ^^^^^^^^^^^^^^^^ @@ -77,7 +59,7 @@ LL | let _x = #[identity_attr] 2; = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: custom attributes cannot be applied to expressions - --> $DIR/proc-macro-gates.rs:45:15 + --> $DIR/proc-macro-gates.rs:41:15 | LL | let _x = [#[identity_attr] 2]; | ^^^^^^^^^^^^^^^^ @@ -86,7 +68,7 @@ LL | let _x = [#[identity_attr] 2]; = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: custom attributes cannot be applied to expressions - --> $DIR/proc-macro-gates.rs:48:14 + --> $DIR/proc-macro-gates.rs:44:14 | LL | let _x = #[identity_attr] println!(); | ^^^^^^^^^^^^^^^^ @@ -95,7 +77,7 @@ LL | let _x = #[identity_attr] println!(); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to patterns - --> $DIR/proc-macro-gates.rs:53:12 + --> $DIR/proc-macro-gates.rs:49:12 | LL | if let identity!(Some(_x)) = Some(3) {} | ^^^^^^^^^^^^^^^^^^^ @@ -104,7 +86,7 @@ LL | if let identity!(Some(_x)) = Some(3) {} = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to statements - --> $DIR/proc-macro-gates.rs:56:5 + --> $DIR/proc-macro-gates.rs:52:5 | LL | empty!(struct S;); | ^^^^^^^^^^^^^^^^^^ @@ -113,7 +95,7 @@ LL | empty!(struct S;); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to statements - --> $DIR/proc-macro-gates.rs:57:5 + --> $DIR/proc-macro-gates.rs:53:5 | LL | empty!(let _x = 3;); | ^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +104,7 @@ LL | empty!(let _x = 3;); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to expressions - --> $DIR/proc-macro-gates.rs:59:14 + --> $DIR/proc-macro-gates.rs:55:14 | LL | let _x = identity!(3); | ^^^^^^^^^^^^ @@ -131,7 +113,7 @@ LL | let _x = identity!(3); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to expressions - --> $DIR/proc-macro-gates.rs:60:15 + --> $DIR/proc-macro-gates.rs:56:15 | LL | let _x = [empty!(3)]; | ^^^^^^^^^ @@ -139,6 +121,6 @@ LL | let _x = [empty!(3)]; = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error: aborting due to 16 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. From a0d8b794d61098693f53f5e6e7da29e1ea1a1c94 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 28 Dec 2019 17:37:22 +0300 Subject: [PATCH 5/8] resolve: Minor cleanup of duplicate macro reexports --- src/librustc_resolve/resolve_imports.rs | 26 +------------------------ src/test/ui/issues/issue-38715.rs | 2 +- src/test/ui/issues/issue-38715.stderr | 14 ++++++------- 3 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 800c40ffdb173..afbfb647b3cac 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -528,31 +528,7 @@ impl<'a> Resolver<'a> { resolution.shadowed_glob = Some(glob_binding); } (false, false) => { - if let (&NameBindingKind::Res(_, true), &NameBindingKind::Res(_, true)) = - (&old_binding.kind, &binding.kind) - { - this.session - .struct_span_err( - binding.span, - &format!( - "a macro named `{}` has already been exported", - key.ident - ), - ) - .span_label( - binding.span, - format!("`{}` already exported", key.ident), - ) - .span_note( - old_binding.span, - "previous macro export is now shadowed", - ) - .emit(); - - resolution.binding = Some(binding); - } else { - return Err(old_binding); - } + return Err(old_binding); } } } else { diff --git a/src/test/ui/issues/issue-38715.rs b/src/test/ui/issues/issue-38715.rs index 7e9defab58864..9a9a501cae157 100644 --- a/src/test/ui/issues/issue-38715.rs +++ b/src/test/ui/issues/issue-38715.rs @@ -2,6 +2,6 @@ macro_rules! foo { ($i:ident) => {} } #[macro_export] -macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported +macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times fn main() {} diff --git a/src/test/ui/issues/issue-38715.stderr b/src/test/ui/issues/issue-38715.stderr index d7c4f88ff5079..c87d9f7360b98 100644 --- a/src/test/ui/issues/issue-38715.stderr +++ b/src/test/ui/issues/issue-38715.stderr @@ -1,14 +1,14 @@ -error: a macro named `foo` has already been exported +error[E0428]: the name `foo` is defined multiple times --> $DIR/issue-38715.rs:5:1 | +LL | macro_rules! foo { ($i:ident) => {} } + | ---------------- previous definition of the macro `foo` here +... LL | macro_rules! foo { () => {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `foo` already exported - | -note: previous macro export is now shadowed - --> $DIR/issue-38715.rs:2:1 + | ^^^^^^^^^^^^^^^^ `foo` redefined here | -LL | macro_rules! foo { ($i:ident) => {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `foo` must be defined only once in the macro namespace of this module error: aborting due to previous error +For more information about this error, try `rustc --explain E0428`. From 31e1c412b34b032b8e8010fd4d922ebfcad698ba Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 27 Dec 2019 14:33:22 -0500 Subject: [PATCH 6/8] Resolve long compile times when evaluating always valid constants This extends the existing logic which skips validating every integer or floating point number type to also skip validating empty structs because they are also trivially valid. Fixes #67539 --- src/librustc_mir/interpret/validity.rs | 15 ++++-- .../const-eval/validate_uninhabited_zsts.rs | 24 +++++++++ .../validate_uninhabited_zsts.stderr | 52 +++++++++++++++++++ src/test/ui/consts/huge-values.rs | 10 ++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs create mode 100644 src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr create mode 100644 src/test/ui/consts/huge-values.rs diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index df8cb5d692b15..448a2765fd3e0 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -580,10 +580,19 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } ty::Array(tys, ..) | ty::Slice(tys) if { - // This optimization applies only for integer and floating point types - // (i.e., types that can hold arbitrary bytes). + // This optimization applies for types that can hold arbitrary bytes (such as + // integer and floating point types) or for structs or tuples with no fields. + // FIXME(wesleywiser) This logic could be extended further to arbitrary structs + // or tuples made up of integer/floating point types or inhabited ZSTs with no + // padding. match tys.kind { ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, + ty::Tuple(tys) if tys.len() == 0 => true, + ty::Adt(adt_def, _) + if adt_def.is_struct() && adt_def.all_fields().next().is_none() => + { + true + } _ => false, } } => @@ -609,7 +618,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Size is not 0, get a pointer. let ptr = self.ecx.force_ptr(mplace.ptr)?; - // This is the optimization: we just check the entire range at once. + // Optimization: we just check the entire range at once. // NOTE: Keep this in sync with the handling of integer and float // types above, in `visit_primitive`. // In run-time mode, we accept pointers in here. This is actually more diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs new file mode 100644 index 0000000000000..f18e00fd633ea --- /dev/null +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -0,0 +1,24 @@ +#![feature(const_fn)] +#![feature(const_transmute)] + +const fn foo() -> ! { + unsafe { std::mem::transmute(()) } + //~^ WARN any use of this value will cause an error [const_err] + //~| WARN the type `!` does not permit zero-initialization [invalid_value] +} + +#[derive(Clone, Copy)] +enum Empty { } + +#[warn(const_err)] +const FOO: [Empty; 3] = [foo(); 3]; + +#[warn(const_err)] +const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; +//~^ ERROR it is undefined behavior to use this value +//~| WARN the type `Empty` does not permit zero-initialization + +fn main() { + FOO; + BAR; +} diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr new file mode 100644 index 0000000000000..bde7f2536fac1 --- /dev/null +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -0,0 +1,52 @@ +warning: any use of this value will cause an error + --> $DIR/validate_uninhabited_zsts.rs:5:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | entering unreachable code + | inside call to `foo` at $DIR/validate_uninhabited_zsts.rs:14:26 +... +LL | const FOO: [Empty; 3] = [foo(); 3]; + | ----------------------------------- + | +note: lint level defined here + --> $DIR/validate_uninhabited_zsts.rs:13:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validate_uninhabited_zsts.rs:17:1 + | +LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type + | + = 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. + +warning: the type `!` does not permit zero-initialization + --> $DIR/validate_uninhabited_zsts.rs:5:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `#[warn(invalid_value)]` on by default + = note: The never type (`!`) has no valid value + +warning: the type `Empty` does not permit zero-initialization + --> $DIR/validate_uninhabited_zsts.rs:17:35 + | +LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: 0-variant enums have no valid value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/huge-values.rs b/src/test/ui/consts/huge-values.rs new file mode 100644 index 0000000000000..bfdeef620efdd --- /dev/null +++ b/src/test/ui/consts/huge-values.rs @@ -0,0 +1,10 @@ +// build-pass + +#[derive(Clone, Copy)] +struct Foo; + +fn main() { + let _ = [(); 4_000_000_000]; + let _ = [0u8; 4_000_000_000]; + let _ = [Foo; 4_000_000_000]; +} From 5e1b366fb6c7bb11f08a085a07f7c11666fdf80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 28 Dec 2019 13:51:29 -0800 Subject: [PATCH 7/8] Do not ICE on lifetime error involving closures --- .../diagnostics/conflict_errors.rs | 22 +++++++++++++++++-- ...ure-doesnt-life-long-enough-issue-67634.rs | 3 +++ ...doesnt-life-long-enough-issue-67634.stderr | 15 +++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs create mode 100644 src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 79221329ead48..af6fcb6922a8b 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -882,9 +882,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( drop_span, format!( - "...but `{}` will be dropped here, when the function `{}` returns", + "...but `{}` will be dropped here, when the {} returns", name, - self.infcx.tcx.hir().name(fn_hir_id), + self.infcx + .tcx + .hir() + .opt_name(fn_hir_id) + .map(|name| format!("function `{}`", name)) + .unwrap_or_else(|| { + match &self + .infcx + .tcx + .typeck_tables_of(self.mir_def_id) + .node_type(fn_hir_id) + .kind + { + ty::Closure(..) => "enclosing closure", + ty::Generator(..) => "enclosing generator", + kind => bug!("expected closure or generator, found {:?}", kind), + } + .to_string() + }) ), ); diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs new file mode 100644 index 0000000000000..19d7f0190479e --- /dev/null +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs @@ -0,0 +1,3 @@ +fn main() { + [0].iter().flat_map(|a| [0].iter().map(|_| &a)); //~ ERROR `a` does not live long enough +} diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr new file mode 100644 index 0000000000000..cb0b481e74876 --- /dev/null +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr @@ -0,0 +1,15 @@ +error[E0597]: `a` does not live long enough + --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:49 + | +LL | [0].iter().flat_map(|a| [0].iter().map(|_| &a)); + | - ^- ...but `a` will be dropped here, when the enclosing closure returns + | | | + | | `a` would have to be valid for `'_`... + | has type `&i32` + | + = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments + = note: to learn more, visit + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 5fd8abd2278624dd7e3b08a46a5599850c81b40d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 29 Dec 2019 00:26:25 +0100 Subject: [PATCH 8/8] Ensure that we don't cause *new* hard errors if we suddenly can evaluate more constants during const prop --- src/librustc_mir/transform/const_prop.rs | 70 ++++++++++++++---------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 206f8043786d4..c36f793511553 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -6,6 +6,7 @@ use std::cell::Cell; use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; +use rustc::hir::HirId; use rustc::mir::interpret::{InterpResult, PanicInfo, Scalar}; use rustc::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, @@ -33,7 +34,6 @@ use crate::interpret::{ ScalarMaybeUndef, StackPopCleanup, }; use crate::rustc::ty::subst::Subst; -use crate::rustc::ty::TypeFoldable; use crate::transform::{MirPass, MirSource}; /// The maximum number of bytes that we'll allocate space for a return value. @@ -261,6 +261,9 @@ struct ConstPropagator<'mir, 'tcx> { source_scopes: IndexVec, local_decls: IndexVec>, ret: Option>, + // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store + // the last known `SourceInfo` here and just keep revisiting it. + source_info: Option, } impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { @@ -339,6 +342,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it local_decls: body.local_decls.clone(), ret: ret.map(Into::into), + source_info: None, } } @@ -360,6 +364,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }; } + fn lint_root(&self, source_info: SourceInfo) -> Option { + match &self.source_scopes[source_info.scope].local_data { + ClearCrossCrate::Set(data) => Some(data.lint_root), + ClearCrossCrate::Clear => None, + } + } + fn use_ecx(&mut self, source_info: SourceInfo, f: F) -> Option where F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, @@ -368,10 +379,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // FIXME(eddyb) move this to the `Panic(_)` error case, so that // `f(self)` is always called, and that the only difference when the // scope's `local_data` is missing, is that the lint isn't emitted. - let lint_root = match &self.source_scopes[source_info.scope].local_data { - ClearCrossCrate::Set(data) => data.lint_root, - ClearCrossCrate::Clear => return None, - }; + let lint_root = self.lint_root(source_info)?; let r = match f(self) { Ok(val) => Some(val), Err(error) => { @@ -417,19 +425,31 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { r } - fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { - // `eval_const_to_op` uses `Instance::resolve` which still has a bug (#66901) in the - // presence of trait items with a default body. So we just bail out if we aren't 100% - // monomorphic. - if c.literal.needs_subst() { - return None; - } + fn eval_constant( + &mut self, + c: &Constant<'tcx>, + source_info: SourceInfo, + ) -> Option> { self.ecx.tcx.span = c.span; match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => Some(op), Err(error) => { let err = error_to_const_error(&self.ecx, error); - err.report_as_error(self.ecx.tcx, "erroneous constant used"); + match self.lint_root(source_info) { + Some(lint_root) if c.literal.needs_subst() => { + // Out of backwards compatibility we cannot report hard errors in unused + // generic functions using associated constants of the generic parameters. + err.report_as_lint( + self.ecx.tcx, + "erroneous constant used", + lint_root, + Some(c.span), + ); + } + _ => { + err.report_as_error(self.ecx.tcx, "erroneous constant used"); + } + } None } } @@ -442,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c), + Operand::Constant(ref c) => self.eval_constant(c, source_info), Operand::Move(ref place) | Operand::Copy(ref place) => { self.eval_place(place, source_info) } @@ -509,10 +529,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let right_size = r.layout.size; let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); if r_bits.map_or(false, |b| b >= left_bits as u128) { - let lint_root = match &self.source_scopes[source_info.scope].local_data { - ClearCrossCrate::Set(data) => data.lint_root, - ClearCrossCrate::Clear => return None, - }; + let lint_root = self.lint_root(source_info)?; let dir = if *op == BinOp::Shr { "right" } else { "left" }; self.tcx.lint_hir( ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, @@ -570,13 +587,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { _ => {} } - // `eval_rvalue_into_place` uses `Instance::resolve` for constants which still has a bug - // (#66901) in the presence of trait items with a default body. So we just bail out if we - // aren't 100% monomorphic. - if rvalue.needs_subst() { - return None; - } - self.use_ecx(source_info, |this| { trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); this.ecx.eval_rvalue_into_place(rvalue, place)?; @@ -769,18 +779,19 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - self.eval_constant(constant); + self.eval_constant(constant, self.source_info.unwrap()); } fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { trace!("visit_statement: {:?}", statement); + let source_info = statement.source_info; + self.source_info = Some(source_info); if let StatementKind::Assign(box (ref place, ref mut rval)) = statement.kind { let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(local) = place.as_local() { - let source = statement.source_info; let can_const_prop = self.can_const_prop[local]; - if let Some(()) = self.const_prop(rval, place_layout, source, place) { + if let Some(()) = self.const_prop(rval, place_layout, source_info, place) { if can_const_prop == ConstPropMode::FullConstProp || can_const_prop == ConstPropMode::OnlyPropagateInto { @@ -823,8 +834,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { } fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); let source_info = terminator.source_info; + self.source_info = Some(source_info); + self.super_terminator(terminator, location); match &mut terminator.kind { TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => { if let Some(value) = self.eval_operand(&cond, source_info) {