Rollup merge of #97105 - JulianKnodt:const_dep_gen_const_expr, r=lcnr
Add tests for lint on type dependent on consts r? `@lcnr`
This commit is contained in:
commit
89bdbd0294
6 changed files with 246 additions and 136 deletions
|
@ -20,6 +20,7 @@
|
|||
#![feature(label_break_value)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
||||
|
|
|
@ -39,9 +39,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
let tcx = infcx.tcx;
|
||||
|
||||
if tcx.features().generic_const_exprs {
|
||||
match AbstractConst::new(tcx, uv)? {
|
||||
// We are looking at a generic abstract constant.
|
||||
Some(ct) => {
|
||||
if let Some(ct) = AbstractConst::new(tcx, uv)? {
|
||||
if satisfied_from_param_env(tcx, ct, param_env)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -93,34 +91,32 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
FailureKind::MentionsParam => {
|
||||
return Err(NotConstEvaluatable::MentionsParam);
|
||||
}
|
||||
FailureKind::Concrete => {
|
||||
// Dealt with below by the same code which handles this
|
||||
// without the feature gate.
|
||||
// returned below
|
||||
FailureKind::Concrete => {}
|
||||
}
|
||||
}
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
|
||||
match concrete {
|
||||
Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() {
|
||||
infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
|
||||
NotConstEvaluatable::MentionsParam
|
||||
} else {
|
||||
NotConstEvaluatable::MentionsInfer
|
||||
}),
|
||||
Err(ErrorHandled::Linted) => {
|
||||
let reported = infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "constant in type had error reported as lint");
|
||||
Err(NotConstEvaluatable::Error(reported))
|
||||
}
|
||||
None => {
|
||||
// If we are dealing with a concrete constant, we can
|
||||
// reuse the old code path and try to evaluate
|
||||
// the constant.
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let future_compat_lint = || {
|
||||
if let Some(local_def_id) = uv.def.did.as_local() {
|
||||
infcx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
|
||||
infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
|
||||
span,
|
||||
|err| {
|
||||
err.build("cannot use constants which depend on generic parameters in types")
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
} else {
|
||||
// FIXME: We should only try to evaluate a given constant here if it is fully concrete
|
||||
// as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
|
||||
//
|
||||
|
@ -131,29 +127,13 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
// See #74595 for more details about this.
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
|
||||
|
||||
if concrete.is_ok() && uv.substs.has_param_types_or_consts() {
|
||||
match infcx.tcx.def_kind(uv.def.did) {
|
||||
DefKind::AnonConst | DefKind::InlineConst => {
|
||||
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
|
||||
|
||||
if mir_body.is_polymorphic {
|
||||
future_compat_lint();
|
||||
}
|
||||
}
|
||||
_ => future_compat_lint(),
|
||||
}
|
||||
}
|
||||
|
||||
match concrete {
|
||||
// If we're evaluating a foreign constant, under a nightly compiler without generic
|
||||
// const exprs, AND it would've passed if that expression had been evaluated with
|
||||
// generic const exprs, then suggest using generic const exprs.
|
||||
if concrete.is_err()
|
||||
&& tcx.sess.is_nightly_build()
|
||||
&& !uv.def.did.is_local()
|
||||
&& !tcx.features().generic_const_exprs
|
||||
Err(_) if tcx.sess.is_nightly_build()
|
||||
&& let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
|
||||
&& satisfied_from_param_env(tcx, ct, param_env) == Ok(true)
|
||||
{
|
||||
&& satisfied_from_param_env(tcx, ct, param_env) == Ok(true) => {
|
||||
tcx.sess
|
||||
.struct_span_fatal(
|
||||
// Slightly better span than just using `span` alone
|
||||
|
@ -170,11 +150,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
.emit()
|
||||
}
|
||||
|
||||
debug!(?concrete, "is_const_evaluatable");
|
||||
match concrete {
|
||||
Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
|
||||
true => NotConstEvaluatable::MentionsInfer,
|
||||
false => NotConstEvaluatable::MentionsParam,
|
||||
Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
|
||||
NotConstEvaluatable::MentionsInfer
|
||||
} else {
|
||||
NotConstEvaluatable::MentionsParam
|
||||
}),
|
||||
Err(ErrorHandled::Linted) => {
|
||||
let reported =
|
||||
|
@ -182,7 +161,26 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
Err(NotConstEvaluatable::Error(reported))
|
||||
}
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Ok(_) => Ok(()),
|
||||
Ok(_) => {
|
||||
if uv.substs.has_param_types_or_consts() {
|
||||
assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
|
||||
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
|
||||
|
||||
if mir_body.is_polymorphic {
|
||||
let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
|
||||
tcx.hir().local_def_id_to_hir_id(local_def_id),
|
||||
span,
|
||||
|err| {
|
||||
err.build("cannot use constants which depend on generic parameters in types").emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/dependence_lint.rs:13:32
|
||||
|
|
||||
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/dependence_lint.rs:20:37
|
||||
|
|
||||
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/dependence_lint.rs:9:9
|
||||
|
|
||||
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(const_evaluatable_unchecked)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/dependence_lint.rs:16:9
|
||||
|
|
||||
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
|
||||
|
||||
error: aborting due to 2 previous errors; 2 warnings emitted
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
error: overly complex generic constant
|
||||
--> $DIR/dependence_lint.rs:16:9
|
||||
|
|
||||
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: overly complex generic constant
|
||||
--> $DIR/dependence_lint.rs:20:17
|
||||
|
|
||||
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/dependence_lint.rs:13:12
|
||||
|
|
||||
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); size_of::<*mut T>()]:`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/dependence_lint.rs:9:9
|
||||
|
|
||||
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); size_of::<*mut T>()]:`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// revisions: full gce
|
||||
|
||||
#![cfg_attr(gce, feature(generic_const_exprs))]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
fn foo<T>() {
|
||||
[0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
|
||||
//[gce]~^ ERROR unconstrained
|
||||
//[full]~^^ WARNING cannot use constants
|
||||
//[full]~| WARNING this was previously accepted
|
||||
let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
//[full]~^ ERROR generic parameters may not be used
|
||||
//[gce]~^^ ERROR unconstrained generic
|
||||
[0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
|
||||
//[gce]~^ ERROR overly complex
|
||||
//[full]~^^ WARNING cannot use constants
|
||||
//[full]~| WARNING this was previously accepted
|
||||
let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
|
||||
//[full]~^ ERROR generic parameters may not be used
|
||||
//[gce]~^^ ERROR overly complex
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,13 @@
|
|||
// check-pass
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn two_args<const N: usize, const M: usize>() -> [u8; M + 2] {
|
||||
[0; M + 2]
|
||||
}
|
||||
|
||||
fn yay<const N: usize>() -> [u8; 4] {
|
||||
two_args::<N, 2>() // no lint
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue