Skip to content

Commit c81935e

Browse files
committed
make ConstEvaluatable more strict
1 parent 7bc0bf7 commit c81935e

File tree

11 files changed

+133
-26
lines changed

11 files changed

+133
-26
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,19 @@ pub struct Body<'tcx> {
186186
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
187187
pub ignore_interior_mut_in_const_validation: bool,
188188

189+
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
190+
///
191+
/// Note that this does not actually mean that this body is not computable right now.
192+
/// The repeat count in the following example is polymorphic, but can still be evaluated
193+
/// without knowing anything about the type parameter `T`.
194+
///
195+
/// ```rust
196+
/// fn test<T>() {
197+
/// let _ = [0; std::mem::size_of::<*mut T>()];
198+
/// }
199+
/// ```
200+
pub is_polymorphic: bool,
201+
189202
predecessor_cache: PredecessorCache,
190203
}
191204

@@ -208,7 +221,7 @@ impl<'tcx> Body<'tcx> {
208221
local_decls.len()
209222
);
210223

211-
Body {
224+
let mut body = Body {
212225
phase: MirPhase::Build,
213226
basic_blocks,
214227
source_scopes,
@@ -224,8 +237,11 @@ impl<'tcx> Body<'tcx> {
224237
span,
225238
required_consts: Vec::new(),
226239
ignore_interior_mut_in_const_validation: false,
240+
is_polymorphic: false,
227241
predecessor_cache: PredecessorCache::new(),
228-
}
242+
};
243+
body.is_polymorphic = body.has_param_types_or_consts();
244+
body
229245
}
230246

231247
/// Returns a partially initialized MIR body containing only a list of basic blocks.
@@ -234,7 +250,7 @@ impl<'tcx> Body<'tcx> {
234250
/// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different
235251
/// crate.
236252
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
237-
Body {
253+
let mut body = Body {
238254
phase: MirPhase::Build,
239255
basic_blocks,
240256
source_scopes: IndexVec::new(),
@@ -250,8 +266,11 @@ impl<'tcx> Body<'tcx> {
250266
generator_kind: None,
251267
var_debug_info: Vec::new(),
252268
ignore_interior_mut_in_const_validation: false,
269+
is_polymorphic: false,
253270
predecessor_cache: PredecessorCache::new(),
254-
}
271+
};
272+
body.is_polymorphic = body.has_param_types_or_consts();
273+
body
255274
}
256275

257276
#[inline]

compiler/rustc_trait_selection/src/traits/fulfill.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_middle::ty::ToPredicate;
1010
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
1111
use std::marker::PhantomData;
1212

13+
use super::const_evaluatable;
1314
use super::project;
1415
use super::select::SelectionContext;
1516
use super::wf;
@@ -458,16 +459,17 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
458459
}
459460

460461
ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
461-
match self.selcx.infcx().const_eval_resolve(
462-
obligation.param_env,
462+
const_evaluatable::is_const_evaluatable(
463+
self.selcx.infcx(),
463464
def_id,
464465
substs,
465-
None,
466-
Some(obligation.cause.span),
467-
) {
468-
Ok(_) => ProcessResult::Changed(vec![]),
469-
Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
470-
}
466+
obligation.param_env,
467+
obligation.cause.span,
468+
)
469+
.map_or_else(
470+
|e| ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))),
471+
|()| ProcessResult::Changed(vec![]),
472+
)
471473
}
472474

473475
ty::PredicateAtom::ConstEquate(c1, c2) => {

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod auto_trait;
77
mod chalk_fulfill;
88
pub mod codegen;
99
mod coherence;
10+
mod const_evaluatable;
1011
mod engine;
1112
pub mod error_reporting;
1213
mod fulfill;

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use self::EvaluationResult::*;
66
use self::SelectionCandidate::*;
77

88
use super::coherence::{self, Conflict};
9+
use super::const_evaluatable;
910
use super::project;
1011
use super::project::normalize_with_depth_to;
1112
use super::util;
@@ -542,17 +543,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
542543
}
543544

544545
ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
545-
match self.tcx().const_eval_resolve(
546-
obligation.param_env,
546+
const_evaluatable::is_const_evaluatable(
547+
self.infcx,
547548
def_id,
548549
substs,
549-
None,
550-
None,
551-
) {
552-
Ok(_) => Ok(EvaluatedToOk),
553-
Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
554-
Err(_) => Ok(EvaluatedToErr),
555-
}
550+
obligation.param_env,
551+
obligation.cause.span,
552+
)
553+
.map(|()| EvaluatedToOk)
554+
.or_else(|e| match e {
555+
ErrorHandled::TooGeneric => Ok(EvaluatedToAmbig),
556+
_ => Ok(EvaluatedToErr),
557+
})
556558
}
557559

558560
ty::PredicateAtom::ConstEquate(c1, c2) => {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use rustc_middle::ty::{self, TypeFoldable};
2+
use rustc_infer::infer::InferCtxt;
3+
use rustc_middle::ty::subst::SubstsRef;
4+
use rustc_span::Span;
5+
use rustc_span::def_id::DefId;
6+
use rustc_middle::mir::interpret::ErrorHandled;
7+
use rustc_hir::def::DefKind;
8+
9+
pub fn is_const_evaluatable<'cx, 'tcx>(
10+
infcx: &InferCtxt<'cx, 'tcx>,
11+
def: ty::WithOptConstParam<DefId>,
12+
substs: SubstsRef<'tcx>,
13+
param_env: ty::ParamEnv<'tcx>,
14+
span: Span,
15+
) -> Result<(), ErrorHandled>
16+
{
17+
let def_kind = infcx.tcx.def_kind(def.did);
18+
match def_kind {
19+
DefKind::AnonConst => {
20+
let mir_body = if let Some(def) = def.as_const_arg() {
21+
infcx.tcx.optimized_mir_of_const_arg(def)
22+
} else {
23+
infcx.tcx.optimized_mir(def.did)
24+
};
25+
if mir_body.is_polymorphic {
26+
return Err(ErrorHandled::TooGeneric);
27+
}
28+
}
29+
_ => {
30+
if substs.has_param_types_or_consts() {
31+
return Err(ErrorHandled::TooGeneric);
32+
}
33+
}
34+
}
35+
36+
match infcx.const_eval_resolve(
37+
param_env,
38+
def,
39+
substs,
40+
None,
41+
Some(span),
42+
) {
43+
Ok(_) => Ok(()),
44+
Err(err) => {
45+
if matches!(err, ErrorHandled::TooGeneric) {
46+
infcx.tcx.sess.delay_span_bug(
47+
span,
48+
&format!("ConstEvaluatable too generic: {:?}, {:?}, {:?}", def, substs, param_env),
49+
);
50+
}
51+
Err(err)
52+
}
53+
}
54+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// check-pass
2+
struct Foo<T>(T);
3+
impl<T> Foo<T> {
4+
const VALUE: usize = std::mem::size_of::<T>();
5+
}
6+
7+
fn test<T>() {
8+
let _ = [0; Foo::<u8>::VALUE];
9+
}
10+
11+
fn main() {}

src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// run-pass
2-
31
#![feature(arbitrary_enum_discriminant, core_intrinsics)]
42

53
extern crate core;
@@ -9,6 +7,7 @@ use core::intrinsics::discriminant_value;
97
enum MyWeirdOption<T> {
108
None = 0,
119
Some(T) = core::mem::size_of::<*mut T>(),
10+
//~^ ERROR constant expression depends on a generic parameter
1211
}
1312

1413
fn main() {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: constant expression depends on a generic parameter
2+
--> $DIR/issue-70453-polymorphic-ctfe.rs:9:15
3+
|
4+
LL | Some(T) = core::mem::size_of::<*mut T>(),
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: this may fail depending on what value the parameter takes
8+
9+
error: aborting due to previous error
10+

src/test/ui/impl-trait/issue-56445.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55

66
use std::marker::PhantomData;
77

8-
pub struct S<'a>
9-
{
8+
pub struct S<'a> {
109
pub m1: PhantomData<&'a u8>,
1110
pub m2: [u8; S::size()],
1211
}

src/test/ui/lazy_normalization_consts/issue-73980.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// check-pass
21
#![feature(lazy_normalization_consts)]
32
#![allow(incomplete_features)]
43

@@ -10,5 +9,6 @@ impl<T: ?Sized> L<T> {
109
}
1110

1211
impl<T> X<T, [u8; L::<T>::S]> {}
12+
//~^ ERROR constant expression depends on a generic parameter
1313

1414
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: constant expression depends on a generic parameter
2+
--> $DIR/issue-73980.rs:11:9
3+
|
4+
LL | impl<T> X<T, [u8; L::<T>::S]> {}
5+
| ^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: this may fail depending on what value the parameter takes
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)