add WellFormedConst predicate

This commit is contained in:
Bastian Kauschke 2020-05-23 18:28:50 +02:00
parent cb2308de54
commit 81831e124e
32 changed files with 296 additions and 61 deletions

View File

@ -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)),

View File

@ -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`.
}

View File

@ -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(..) |

View File

@ -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,
}
}
}

View File

@ -2054,6 +2054,9 @@ define_print_and_forward_display! {
print(c2),
write("`"))
}
ty::PredicateKind::WellFormedConst(c) => {
p!(print(c), write(" well-formed"))
}
}
}

View File

@ -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)
}
}
}
}

View File

@ -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)
}

View File

@ -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>

View File

@ -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

View File

@ -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,

View File

@ -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,
}
})
}

View File

@ -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)

View File

@ -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;
}

View File

@ -77,7 +77,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
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<chalk_ir::Goal<RustInterner<'
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::WellFormedConst(..) => {
bug!("unexpected predicate {}", predicate)
}
}
@ -193,7 +194,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> 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<chalk_ir::QuantifiedWhereClause<RustInterner<'
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self),
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::WellFormedConst(..) => bug!("unexpected predicate {}", &self),
}
}
}

View File

@ -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);

View File

@ -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,
}
}

View File

@ -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| {

View File

@ -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,

View File

@ -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,
}
}

View File

@ -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(..) => (),
}
}

View File

@ -491,7 +491,8 @@ impl<'a> Clean<Option<WherePredicate>> 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"),
}
}
}

View File

@ -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

View File

@ -1,5 +1,3 @@
// check-pass
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
@ -7,6 +5,7 @@ struct Const<const N: usize>;
impl<const C: usize> Const<{C}> {
fn successor() -> Const<{C + 1}> {
//~^ ERROR constant expression depends on a generic parameter
Const
}
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/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

View File

@ -1,7 +1,6 @@
// build-pass
#![allow(incomplete_features)]
#![feature(const_generics)]
pub struct Vector<T, const N: usize>([T; N]);
pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
@ -9,6 +8,7 @@ pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
impl<T, const N: usize> Vector<T, { N }> {
/// Drop the last component and return the vector with one fewer dimension.
pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
//~^ ERROR constant expression depends on a generic parameter
unimplemented!()
}
}

View File

@ -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, { N }>, T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this may fail depending on what value the parameter takes
error: aborting due to previous error

View File

@ -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<const N: usize>() {
fact::<{ N - 1 }>();

View File

@ -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 <https://github.com/rust-lang/rust/issues/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

View File

@ -0,0 +1,40 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
struct PhantomU8<const X: u8>;
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<const INT_BITS: u8, const FRAC_BITS: u8> =
PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
struct Fxp<const INT_BITS: u8, const FRAC_BITS: u8>
where
FxpStorageHelper<INT_BITS, FRAC_BITS>: FxpStorage,
//~^ ERROR constant expression depends on a generic parameter
{
storage: <FxpStorageHelper<INT_BITS, FRAC_BITS> as FxpStorage>::SInt,
}
fn main() {
Fxp::<1, 15> { storage: 0i16 };
Fxp::<2, 15> { storage: 0i32 };
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/44580> for more information
error: constant expression depends on a generic parameter
--> $DIR/issue-68977.rs:31:44
|
LL | FxpStorageHelper<INT_BITS, FRAC_BITS>: FxpStorage,
| ^^^^^^^^^^
|
= note: this may fail depending on what value the parameter takes
error: aborting due to previous error; 1 warning emitted

View File

@ -0,0 +1,16 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
pub fn arr_len<const N: usize>() {
let _: [u8; N + 1];
//~^ ERROR constant expression depends on a generic parameter
}
struct Const<const N: usize>;
pub fn func_call<const N: usize>() {
let _: Const::<{N + 1}>;
//~^ ERROR constant expression depends on a generic parameter
}
fn main() {}

View File

@ -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 <https://github.com/rust-lang/rust/issues/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