From e1f408e6c8d440224dfa45f8b1a97ed84c790fcd Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 09:42:29 +0200 Subject: [PATCH 1/6] const_evaluatable_checked: collect predicates from fn_sig --- compiler/rustc_typeck/src/collect.rs | 23 +++++++++++++++---- .../cross_crate_predicate.rs | 1 + .../cross_crate_predicate.stderr | 20 +++++++++++++++- .../from-sig-fail.rs | 11 +++++++++ .../from-sig-fail.stderr | 9 ++++++++ .../const_evaluatable_checked/from-sig.rs | 14 +++++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 458622dd65a39..d04b5cf588f72 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1678,8 +1678,10 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate if tcx.features().const_evaluatable_checked { let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); - result.predicates = - tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + if !const_evaluatable.is_empty() { + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + } } debug!("predicates_defined_on({:?}) = {:?}", def_id, result); @@ -1690,7 +1692,7 @@ pub fn const_evaluatable_predicates_of<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, predicates: &ty::GenericPredicates<'tcx>, -) -> impl Iterator, Span)> { +) -> Vec<(ty::Predicate<'tcx>, Span)> { #[derive(Default)] struct ConstCollector<'tcx> { ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>, Span); 4]>, @@ -1711,10 +1713,21 @@ pub fn const_evaluatable_predicates_of<'tcx>( collector.curr_span = span; pred.visit_with(&mut collector); } - warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); + + match tcx.def_kind(def_id) { + DefKind::Fn | DefKind::AssocFn => { + tcx.fn_sig(def_id).visit_with(&mut collector); + } + _ => (), + } + debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); + + // We only want unique const evaluatable predicates. + collector.ct.sort(); + collector.ct.dedup(); collector.ct.into_iter().map(move |(def_id, subst, span)| { (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) - }) + }).collect() } /// Returns a list of all type predicates (explicit and implicit) for the definition with diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs index 223699233298d..52b89cfa04588 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs @@ -8,6 +8,7 @@ fn user() { //~^ ERROR constant expression depends //~| ERROR constant expression depends //~| ERROR constant expression depends + //~| ERROR constant expression depends } fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index 63abb782b93a3..e8afb495e602b 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -11,6 +11,19 @@ LL | [u8; std::mem::size_of::() - 1]: Sized, | = note: this may fail depending on what value the parameter takes +error: constant expression depends on a generic parameter + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ----- required by this bound in `test1` + | + = note: this may fail depending on what value the parameter takes + error: constant expression depends on a generic parameter --> $DIR/cross_crate_predicate.rs:7:13 | @@ -29,8 +42,13 @@ error: constant expression depends on a generic parameter | LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ----- required by this bound in `test1::{{constant}}#1` | = note: this may fail depending on what value the parameter takes -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs new file mode 100644 index 0000000000000..3da4688702c96 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -0,0 +1,11 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] { + //~^ ERROR evaluation of constant + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr new file mode 100644 index 0000000000000..a5acfec34aa87 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/from-sig-fail.rs:4:35 + | +LL | fn test() -> [u8; N - 1] { + | ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs new file mode 100644 index 0000000000000..5c05a5acfe96d --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} From ac1d0d8b28008277a39a3f4d4a6bc34772c06888 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 09:48:20 +0200 Subject: [PATCH 2/6] fmt, use IndexSet directly instead of UniquePredicates --- compiler/rustc_typeck/src/collect.rs | 55 ++++++++++------------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index d04b5cf588f72..fd2cd03a9c180 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1679,8 +1679,9 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate if tcx.features().const_evaluatable_checked { let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); if !const_evaluatable.is_empty() { - result.predicates = - tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + result.predicates = tcx + .arena + .alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); } } @@ -1725,9 +1726,13 @@ pub fn const_evaluatable_predicates_of<'tcx>( // We only want unique const evaluatable predicates. collector.ct.sort(); collector.ct.dedup(); - collector.ct.into_iter().map(move |(def_id, subst, span)| { - (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) - }).collect() + collector + .ct + .into_iter() + .map(move |(def_id, subst, span)| { + (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) + }) + .collect() } /// Returns a list of all type predicates (explicit and implicit) for the definition with @@ -1767,29 +1772,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat debug!("explicit_predicates_of(def_id={:?})", def_id); - /// A data structure with unique elements, which preserves order of insertion. - /// Preserving the order of insertion is important here so as not to break - /// compile-fail UI tests. - struct UniquePredicates<'tcx> { - predicates: FxIndexSet<(ty::Predicate<'tcx>, Span)>, - } - - impl<'tcx> UniquePredicates<'tcx> { - fn new() -> Self { - UniquePredicates { predicates: FxIndexSet::default() } - } - - fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) { - self.predicates.insert(value); - } - - fn extend, Span)>>(&mut self, iter: I) { - for value in iter { - self.push(value); - } - } - } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let node = tcx.hir().get(hir_id); @@ -1802,7 +1784,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); - let mut predicates = UniquePredicates::new(); + // We use an `IndexSet` to preserves order of insertion. + // Preserving the order of insertion is important here so as not to break + // compile-fail UI tests. + let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => { @@ -1904,7 +1889,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.push(( + predicates.insert(( trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), tcx.def_span(def_id), )); @@ -1928,7 +1913,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat hir::GenericBound::Outlives(lt) => { let bound = AstConv::ast_region_to_region(&icx, <, None); let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); - predicates.push((outlives.to_predicate(tcx), lt.span)); + predicates.insert((outlives.to_predicate(tcx), lt.span)); } _ => bug!(), }); @@ -1983,7 +1968,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(predicate) .potentially_quantified(tcx, ty::PredicateKind::ForAll), span, @@ -2027,11 +2012,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) .potentially_quantified(tcx, ty::PredicateKind::ForAll), lifetime.span, - )) + )); } } } @@ -2076,7 +2061,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat })) } - let mut predicates: Vec<_> = predicates.predicates.into_iter().collect(); + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come From f8d3f401df47cf680180c357fabdc8c76c2a08ab Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 10:54:09 +0200 Subject: [PATCH 3/6] walk hir to get const evaluatable predicates --- compiler/rustc_typeck/src/collect.rs | 143 ++++++++++-------- .../cross_crate_predicate.stderr | 20 +-- .../let-bindings.stderr | 6 +- 3 files changed, 96 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index fd2cd03a9c180..d341e7eec41a3 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -37,12 +37,11 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; -use rustc_middle::ty::{TypeFoldable, TypeVisitor}; use rustc_session::config::SanitizerSet; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -51,8 +50,6 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; -use smallvec::SmallVec; - mod type_of; struct OnlySelfBounds(bool); @@ -1676,65 +1673,10 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate } } - if tcx.features().const_evaluatable_checked { - let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); - if !const_evaluatable.is_empty() { - result.predicates = tcx - .arena - .alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); - } - } - debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result } -pub fn const_evaluatable_predicates_of<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - predicates: &ty::GenericPredicates<'tcx>, -) -> Vec<(ty::Predicate<'tcx>, Span)> { - #[derive(Default)] - struct ConstCollector<'tcx> { - ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>, Span); 4]>, - curr_span: Span, - } - - impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> { - fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { - if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { - self.ct.push((def, substs, self.curr_span)); - } - false - } - } - - let mut collector = ConstCollector::default(); - for &(pred, span) in predicates.predicates.iter() { - collector.curr_span = span; - pred.visit_with(&mut collector); - } - - match tcx.def_kind(def_id) { - DefKind::Fn | DefKind::AssocFn => { - tcx.fn_sig(def_id).visit_with(&mut collector); - } - _ => (), - } - debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); - - // We only want unique const evaluatable predicates. - collector.ct.sort(); - collector.ct.dedup(); - collector - .ct - .into_iter() - .map(move |(def_id, subst, span)| { - (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) - }) - .collect() -} - /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus /// `Self: Trait` predicates for traits. @@ -2061,6 +2003,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat })) } + if tcx.features().const_evaluatable_checked { + predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); + } + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we @@ -2087,6 +2033,85 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } +fn const_evaluatable_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> { + struct ConstCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>, + } + + impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + let def_id = self.tcx.hir().local_def_id(c.hir_id); + let ct = ty::Const::from_anon_const(self.tcx, def_id); + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + let span = self.tcx.hir().span(c.hir_id); + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + span, + )); + } + } + + // Look into `TyAlias`. + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + use ty::fold::{TypeFoldable, TypeVisitor}; + struct TyAliasVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>, + span: Span, + } + + impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + self.span, + )); + } + false + } + } + + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind { + if let Res::Def(DefKind::TyAlias, def_id) = path.res { + let mut visitor = + TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span }; + self.tcx.type_of(def_id).visit_with(&mut visitor); + } + } + + intravisit::walk_ty(self, ty) + } + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let node = tcx.hir().get(hir_id); + + let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + if let Some(generics) = node.generics() { + warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); + collector.visit_generics(generics); + } + + if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) { + warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); + collector.visit_fn_decl(fn_sig.decl); + } + warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); + + collector.preds +} + fn projection_ty_from_predicates( tcx: TyCtxt<'tcx>, key: ( diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index e8afb495e602b..e7da191e670ec 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -4,10 +4,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1` + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes @@ -17,10 +17,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1` +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes @@ -30,10 +30,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1::{{constant}}#1` + | ---------------------------- required by this bound in `test1::{{constant}}#1` | = note: this may fail depending on what value the parameter takes @@ -43,10 +43,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1::{{constant}}#1` +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ---------------------------- required by this bound in `test1::{{constant}}#1` | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index 5749defb3e12c..b76e300663d76 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -1,10 +1,8 @@ -error: overly complex generic constant +error: constant expression depends on a generic parameter --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test::{{constant}}#0` | = help: consider moving this anonymous constant into a `const` function From b8402d6a6e6cadd3d877c952a2c5bbd694afbc2d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 11:36:54 +0200 Subject: [PATCH 4/6] assign the correct `DefId` in `nominal_obligations` --- .../rustc_trait_selection/src/traits/wf.rs | 20 +++++++++++++++---- .../cross_crate_predicate.stderr | 4 ++-- .../let-bindings.stderr | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 998990f374cb9..909cd2aa1551e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -7,8 +7,9 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; -use std::rc::Rc; +use std::iter; +use std::rc::Rc; /// Returns the set of obligations needed to make `arg` well-formed. /// If `arg` contains unresolved inference variables, this may include /// further WF obligations. However, if `arg` IS an unresolved @@ -616,13 +617,24 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Vec> { - let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); + let predicates = self.infcx.tcx.predicates_of(def_id); + let mut origins = vec![def_id; predicates.predicates.len()]; + let mut head = predicates; + while let Some(parent) = head.parent { + head = self.infcx.tcx.predicates_of(parent); + origins.extend(iter::repeat(parent).take(head.predicates.len())); + } + + let predicates = predicates.instantiate(self.infcx.tcx, substs); + debug_assert_eq!(predicates.predicates.len(), origins.len()); + predicates .predicates .into_iter() .zip(predicates.spans.into_iter()) - .map(|(pred, span)| { - let cause = self.cause(traits::BindingObligation(def_id, span)); + .zip(origins.into_iter().rev()) + .map(|((pred, span), origin_def_id)| { + let cause = self.cause(traits::BindingObligation(origin_def_id, span)); traits::Obligation::new(cause, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index e7da191e670ec..4af68118be31f 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -33,7 +33,7 @@ LL | let _ = const_evaluatable_lib::test1::(); ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, - | ---------------------------- required by this bound in `test1::{{constant}}#1` + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes @@ -46,7 +46,7 @@ LL | let _ = const_evaluatable_lib::test1::(); ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ---------------------------- required by this bound in `test1::{{constant}}#1` + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index b76e300663d76..dd27b81ee0342 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -2,7 +2,7 @@ error: constant expression depends on a generic parameter --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test::{{constant}}#0` + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test` | = help: consider moving this anonymous constant into a `const` function From 3f9015b22d774dd2af0c3c95dbfb0270d5e0bf7e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 11:55:03 +0200 Subject: [PATCH 5/6] visit impl self ty + trait --- compiler/rustc_typeck/src/collect.rs | 12 +++++++++ .../const_evaluatable_checked/impl-bounds.rs | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index d341e7eec41a3..a571bd58abc34 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2098,6 +2098,18 @@ fn const_evaluatable_predicates_of<'tcx>( let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + if let hir::Node::Item(item) = node { + if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind { + if let Some(of_trait) = of_trait { + warn!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); + collector.visit_trait_ref(of_trait); + } + + warn!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); + collector.visit_ty(self_ty); + } + } + if let Some(generics) = node.generics() { warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); collector.visit_generics(generics); diff --git a/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs new file mode 100644 index 0000000000000..193a365f9b65b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs @@ -0,0 +1,25 @@ +// check-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::mem::size_of; + +struct Foo(T); + +impl Foo() }> { + fn test() { + let _: [u8; std::mem::size_of::()]; + } +} + +trait Bar { + fn test_me(); +} + +impl Bar<{ size_of::() }> for Foo { + fn test_me() { + let _: [u8; std::mem::size_of::()]; + } +} + +fn main() {} From 21edd10dc5ae8cde041f84a38fd0c4a44a36965d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 18:00:32 +0200 Subject: [PATCH 6/6] update tests --- .../const_evaluatable_checked/let-bindings.stderr | 6 ++++-- src/test/ui/const-generics/issues/issue-76595.stderr | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index dd27b81ee0342..5749defb3e12c 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -1,8 +1,10 @@ -error: constant expression depends on a generic parameter +error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test` + | ^^^^^^-^^^^^^^^^^^^^ + | | + | unsupported statement | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr index 2e457595393ca..bbc81693fc0ef 100644 --- a/src/test/ui/const-generics/issues/issue-76595.stderr +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -8,7 +8,7 @@ error: constant expression depends on a generic parameter --> $DIR/issue-76595.rs:15:5 | LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { - | ---- required by this bound in `test` + | ------------------------------- required by this bound in `test` ... LL | test::<2>(); | ^^^^^^^^^