From 81831e124e002188d95d690ea090067b3653055f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 18:28:50 +0200 Subject: [PATCH] add WellFormedConst predicate --- src/librustc_infer/infer/outlives/mod.rs | 3 +- src/librustc_infer/traits/util.rs | 5 ++ src/librustc_lint/builtin.rs | 1 + src/librustc_middle/ty/mod.rs | 12 +++- src/librustc_middle/ty/print/pretty.rs | 3 + src/librustc_middle/ty/structural_impls.rs | 4 ++ .../transform/qualify_min_const_fn.rs | 3 +- src/librustc_trait_selection/opaque_types.rs | 3 +- .../traits/error_reporting/mod.rs | 18 +++++ .../traits/fulfill.rs | 15 +++++ .../traits/object_safety.rs | 6 +- src/librustc_trait_selection/traits/select.rs | 14 ++++ src/librustc_trait_selection/traits/wf.rs | 26 +++++--- src/librustc_traits/chalk/lowering.rs | 11 ++-- .../implied_outlives_bounds.rs | 3 +- .../normalize_erasing_regions.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/mod.rs | 65 +++++++++++-------- .../impl_wf_check/min_specialization.rs | 3 +- src/librustc_typeck/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- .../cannot-infer-const-args.stderr | 4 +- .../ui/const-generics/issues/issue-61747.rs | 3 +- .../const-generics/issues/issue-61747.stderr | 12 +++- .../ui/const-generics/issues/issue-62220.rs | 4 +- .../const-generics/issues/issue-62220.stderr | 10 +++ .../ui/const-generics/issues/issue-66205.rs | 4 +- .../const-generics/issues/issue-66205.stderr | 11 +++- .../ui/const-generics/issues/issue-68977.rs | 40 ++++++++++++ .../const-generics/issues/issue-68977.stderr | 19 ++++++ src/test/ui/const-generics/wf-misc.rs | 16 +++++ src/test/ui/const-generics/wf-misc.stderr | 27 ++++++++ 32 files changed, 296 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-62220.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68977.rs create mode 100644 src/test/ui/const-generics/issues/issue-68977.stderr create mode 100644 src/test/ui/const-generics/wf-misc.rs create mode 100644 src/test/ui/const-generics/wf-misc.stderr diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index fd3b38e9d67b..ad8e44a6c1d3 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -20,7 +20,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 8081cac0067f..1aaa07d23cc9 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -45,6 +45,8 @@ pub fn anonymize_predicate<'tcx>( } ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2), + + ty::PredicateKind::WellFormedConst(ct) => ty::PredicateKind::WellFormedConst(ct), }; if new != *kind { new.to_predicate(tcx) } else { pred } @@ -204,6 +206,9 @@ impl Elaborator<'tcx> { // Currently, we do not elaborate const-equate // predicates. } + ty::PredicateKind::WellFormedConst(..) => { + // Currently, we do not elaborate WF predicates. + } ty::PredicateKind::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e17e8b7b9640..bde761b01c3a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1218,6 +1218,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { Projection(..) | // Ignore bounds that a user can't type WellFormed(..) | + WellFormedConst(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 4cd3be932def..554553dc6b4c 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1079,6 +1079,9 @@ pub enum PredicateKind<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + + /// Constant must be well formed. + WellFormedConst(&'tcx Const<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -1195,6 +1198,9 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::ConstEquate(c1, c2) => { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } + PredicateKind::WellFormedConst(c) => { + PredicateKind::WellFormedConst(c.subst(tcx, substs)) + } }; if new != *kind { new.to_predicate(tcx) } else { self } @@ -1386,7 +1392,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) => None, + | PredicateKind::ConstEquate(..) + | PredicateKind::WellFormedConst(..) => None, } } @@ -1401,7 +1408,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) => None, + | PredicateKind::ConstEquate(..) + | PredicateKind::WellFormedConst(..) => None, } } } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 6a11e775c8c5..6eb11b0c9429 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2054,6 +2054,9 @@ define_print_and_forward_display! { print(c2), write("`")) } + ty::PredicateKind::WellFormedConst(c) => { + p!(print(c), write(" well-formed")) + } } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index c6ecb08615fc..19a2e89ca417 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -247,6 +247,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateKind::WellFormedConst(c) => write!(f, "WellFormedConst({:?})", c), } } } @@ -507,6 +508,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) } + ty::PredicateKind::WellFormedConst(c) => { + tcx.lift(&c).map(ty::PredicateKind::WellFormedConst) + } } } } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 5615aa84eecd..22959c6a3df2 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -29,7 +29,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Projection(_) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => continue, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => continue, ty::PredicateKind::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index f78a6207a3ab..8bbcfb1ade58 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1277,7 +1277,8 @@ crate fn required_region_bounds( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f8b33b782c01..1134cafbae43 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -610,6 +610,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + ty::PredicateKind::WellFormedConst(ct) => { + // Const WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "const WF predicate not satisfied for {:?}", ct); + } + ty::PredicateKind::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, @@ -1540,6 +1549,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) } + ty::PredicateKind::WellFormedConst(ct) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if ct.references_error() || self.tcx.sess.has_errors() { + return; + } + self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) + } + ty::PredicateKind::Subtype(ref data) => { if data.references_error() || self.tcx.sess.has_errors() { // no need to overload user in such cases diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index c1d9b0a2d88e..8ab81246e7d9 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -476,6 +476,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } + ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( + self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + constant, + obligation.cause.span, + ) { + Some(predicates) => ProcessResult::Changed(mk_pending(predicates)), + None => { + pending_obligation.stalled_on = + vec![TyOrConstInferVar::maybe_from_const(constant).unwrap()]; + ProcessResult::Unchanged + } + }, + &ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 5befc797a517..ee7aa6b165d6 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -283,7 +283,8 @@ fn predicates_reference_self( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, } }) .collect() @@ -318,7 +319,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => false, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => false, } }) } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 7aa5aa2dae89..9dd0592c45fb 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -450,6 +450,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => Ok(EvaluatedToAmbig), }, + ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + constant, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + } + None => Ok(EvaluatedToAmbig), + }, + ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => { // We do not consider region relationships when evaluating trait matches. Ok(EvaluatedToOkModuloRegions) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 60a888152142..458a6f5b88f2 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -128,15 +128,15 @@ pub fn predicate_obligations<'a, 'tcx>( let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for subst in substs.iter().copied() { + for subst in substs.iter() { wf.compute(subst); } } - ty::PredicateKind::ConstEquate(c1, c2) => { - wf.compute(c1.ty.into()); - wf.compute(c2.ty.into()); + &ty::PredicateKind::ConstEquate(c1, c2) => { + wf.compute(c1.into()); + wf.compute(c2.into()); } - ty::Predicate::WellFormedConst(constant) => { + &ty::PredicateKind::WellFormedConst(constant) => { wf.compute(constant.into()); } } @@ -368,7 +368,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); + let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs) + .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new( cause, @@ -389,11 +390,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()), + ty::PredicateKind::WellFormedConst(resolved_constant) + .to_predicate(self.tcx()), )); } } - _ => (), + ty::ConstKind::Error + | ty::ConstKind::Param(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Placeholder(..) => { + // These variants are trivially WF, so nothing to do here. + } + ty::ConstKind::Value(..) => { + // FIXME: Enforce that values are structually-matchable. + } } continue; } diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index a33ada2fb6ef..b624598322a0 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -77,7 +77,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment chalk_ir::InEnvironment>> { let clauses = self.environment.into_iter().filter_map(|clause| match clause { ChalkEnvironmentClause::Predicate(predicate) => { - match &predicate.kind() { + match predicate.kind() { ty::PredicateKind::Trait(predicate, _) => { let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, predicate); @@ -126,7 +126,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => { bug!("unexpected predicate {}", predicate) } } @@ -193,7 +194,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => { + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } } @@ -460,7 +462,8 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 5dee71a2338c..073dfe4d5920 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -101,7 +101,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => vec![], + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => vec![], ty::PredicateKind::WellFormed(subty) => { wf_types.push(subty); diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index fcb75142269d..6a8d81085c57 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => true, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => true, } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 91562d576ea8..c17b3d78125c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -814,7 +814,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8fa65a135ac..374ba1c73141 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3353,28 +3353,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - - // HACK(eddyb) emulate what a `WellFormedConst` obligation would do. - // This code should be replaced with the proper WF handling ASAP. - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { - assert!(promoted.is_none()); - - // HACK(eddyb) let's hope these are always empty. - // let obligations = self.nominal_obligations(def_id, substs); - // self.out.extend(obligations); - - let cause = traits::ObligationCause::new( - self.tcx.def_span(const_def_id.to_def_id()), - self.body_id, - traits::MiscObligation, - ); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx), - )); - } - + self.register_wf_const_obligation( + c, + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); c } @@ -3424,11 +3407,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - /// Registers obligations that all types appearing in `substs` are well-formed. + /// Registers an obligation for checking later, during regionck, that the type `ty` must + /// outlive the region `r`. + pub fn register_wf_const_obligation( + &self, + ct: &'tcx ty::Const<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateKind::WellFormedConst(ct).to_predicate(self.tcx), + )); + } + + /// Registers obligations that all `substs` are well-formed. pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for ty in substs.types() { - if !ty.references_error() { - self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + for subst in substs { + match subst.unpack() { + GenericArgKind::Lifetime(..) => { + // Nothing to do for lifetimes. + } + GenericArgKind::Type(ty) => { + if !ty.references_error() { + self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + } + } + GenericArgKind::Const(ct) => { + if !ct.references_error() { + self.register_wf_const_obligation(ct, expr.span, traits::MiscObligation); + } + } } } } @@ -3860,6 +3872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::RegionOutlives(..) => None, ty::PredicateKind::TypeOutlives(..) => None, ty::PredicateKind::WellFormed(..) => None, + ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::ObjectSafe(..) => None, ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::ConstEquate(..) => None, diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index bf9a4d1cb6ca..b2e8716b0380 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 5740cc224cc5..cf8be687f602 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -59,7 +59,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => (), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 371df7444b00..5c2d6c6453db 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -491,7 +491,8 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => panic!("not user writable"), } } } diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr index 6696b025855a..b29d27e52475 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.stderr +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -11,7 +11,9 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:9:5 | LL | foo(); - | ^^^ cannot infer type for fn item `fn() -> usize {foo::<{_: usize}>}` + | ^^^ + | + = note: unable to infer the value of a const parameter error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index 9e0572d3568c..cc671163e85a 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete @@ -7,6 +5,7 @@ struct Const; impl Const<{C}> { fn successor() -> Const<{C + 1}> { + //~^ ERROR constant expression depends on a generic parameter Const } } diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr index 2e405370dc0d..2685d9fdf167 100644 --- a/src/test/ui/const-generics/issues/issue-61747.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61747.rs:3:12 + --> $DIR/issue-61747.rs:1:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ @@ -7,5 +7,13 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: constant expression depends on a generic parameter + --> $DIR/issue-61747.rs:7:23 + | +LL | fn successor() -> Const<{C + 1}> { + | ^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index c95b30632017..5c4a0d31a895 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,7 +1,6 @@ -// build-pass #![allow(incomplete_features)] - #![feature(const_generics)] + pub struct Vector([T; N]); pub type TruncatedVector = Vector; @@ -9,6 +8,7 @@ pub type TruncatedVector = Vector; impl Vector { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector, T) { + //~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.stderr new file mode 100644 index 000000000000..d91d2bb326fc --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62220.rs:10:27 + | +LL | pub fn trunc(self) -> (TruncatedVector, T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 76bde1815be1..7cedf51ca040 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,6 +1,6 @@ -#![allow(incomplete_features, dead_code, unconditional_recursion)] +#![allow(dead_code, unconditional_recursion)] #![feature(const_generics)] -#![feature(lazy_normalization_consts)] +//~^ WARN the feature `const_generics` is incomplete fn fact() { fact::<{ N - 1 }>(); diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr index 416b675b56d2..1e9c0f2f3d9e 100644 --- a/src/test/ui/const-generics/issues/issue-66205.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.stderr @@ -1,3 +1,12 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-66205.rs:2:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + error: constant expression depends on a generic parameter --> $DIR/issue-66205.rs:6:12 | @@ -6,5 +15,5 @@ LL | fact::<{ N - 1 }>(); | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs new file mode 100644 index 000000000000..346ea3c20424 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -0,0 +1,40 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +struct PhantomU8; + +trait FxpStorage { + type SInt; // Add arithmetic traits as needed. +} + +macro_rules! fxp_storage_impls { + ($($($n:literal)|+ => $sint:ty),* $(,)?) => { + $($(impl FxpStorage for PhantomU8<$n> { + type SInt = $sint; + })*)* + } +} + +fxp_storage_impls! { + 1 => i8, + 2 => i16, + 3 | 4 => i32, + 5 | 6 | 7 | 8 => i64, + 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 => i128, +} + +type FxpStorageHelper = + PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + +struct Fxp +where + FxpStorageHelper: FxpStorage, + //~^ ERROR constant expression depends on a generic parameter +{ + storage: as FxpStorage>::SInt, +} + +fn main() { + Fxp::<1, 15> { storage: 0i16 }; + Fxp::<2, 15> { storage: 0i32 }; +} diff --git a/src/test/ui/const-generics/issues/issue-68977.stderr b/src/test/ui/const-generics/issues/issue-68977.stderr new file mode 100644 index 000000000000..e1190d9026da --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68977.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/issue-68977.rs:31:44 + | +LL | FxpStorageHelper: FxpStorage, + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs new file mode 100644 index 000000000000..4ff1b9e2da5b --- /dev/null +++ b/src/test/ui/const-generics/wf-misc.rs @@ -0,0 +1,16 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +pub fn arr_len() { + let _: [u8; N + 1]; + //~^ ERROR constant expression depends on a generic parameter +} + +struct Const; + +pub fn func_call() { + let _: Const::<{N + 1}>; + //~^ ERROR constant expression depends on a generic parameter +} + +fn main() {} diff --git a/src/test/ui/const-generics/wf-misc.stderr b/src/test/ui/const-generics/wf-misc.stderr new file mode 100644 index 000000000000..03f2bf3f5269 --- /dev/null +++ b/src/test/ui/const-generics/wf-misc.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/wf-misc.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/wf-misc.rs:5:12 + | +LL | let _: [u8; N + 1]; + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/wf-misc.rs:12:12 + | +LL | let _: Const::<{N + 1}>; + | ^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors; 1 warning emitted +