Skip to content

Commit f791d70

Browse files
Rollup merge of rust-lang#159504 - RalfJung:generic-in-pat, r=BoxyUwU,Nadrieril
Abort const-eval queries early when there are generics in the type Since [recently](rust-lang#156977), const validation has a `has_param` check, which means ConstToPat also implicitly has that check. But it seems better to check this again explicitly here rather then rely on an undocumented property of some other component. The new test behaves the same with or without the PR. I recommend hiding whitespace difference, since rustfmt re-indendet a bunch of stuff. Fixes rust-lang#150296 r? @BoxyUwU
2 parents ae3bbe7 + bb3d6e9 commit f791d70

11 files changed

Lines changed: 86 additions & 49 deletions

File tree

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::const_eval::CheckAlignment;
1919
use crate::interpret::{
2020
CtfeValidationMode, GlobalId, Immediate, InternError, InternKind, InterpCx, InterpErrorKind,
2121
InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ReturnContinuation, create_static_alloc,
22-
intern_const_alloc_recursive, interp_ok, throw_exhaust,
22+
ensure_monomorphic_enough, intern_const_alloc_recursive, interp_ok, throw_exhaust,
2323
};
2424
use crate::{CTRL_C_RECEIVED, diagnostics};
2525

@@ -96,8 +96,10 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
9696
body: &'tcx mir::Body<'tcx>,
9797
) -> InterpResult<'tcx, R> {
9898
let tcx = *ecx.tcx;
99-
let layout = ecx
100-
.layout_of(body.bound_return_ty(tcx).instantiate(tcx, cid.instance.args).skip_norm_wip())?;
99+
let ty = body.bound_return_ty(tcx).instantiate(tcx, cid.instance.args).skip_norm_wip();
100+
ensure_monomorphic_enough(ty)?;
101+
102+
let layout = ecx.layout_of(ty)?;
101103
let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;
102104

103105
trace!(

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
693693

694694
sym::field_offset => {
695695
let frt_ty = instance.args.type_at(0);
696-
ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?;
696+
ensure_monomorphic_enough(frt_ty)?;
697697

698698
let (ty, variant, field) = if let ty::Adt(def, args) = frt_ty.kind()
699699
&& let Some(FieldInfo { base, variant_idx, field_idx, .. }) =

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
7676

7777
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _) => {
7878
// All reifications must be monomorphic, bail out otherwise.
79-
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
79+
ensure_monomorphic_enough(src.layout.ty)?;
8080

8181
// The src operand does not matter, just its type
8282
match *src.layout.ty.kind() {
@@ -112,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
112112

113113
CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => {
114114
// All reifications must be monomorphic, bail out otherwise.
115-
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
115+
ensure_monomorphic_enough(src.layout.ty)?;
116116

117117
// The src operand does not matter, just its type
118118
match *src.layout.ty.kind() {
@@ -445,8 +445,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
445445
}
446446
_ => {
447447
// Do not ICE if we are not monomorphic enough.
448-
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
449-
ensure_monomorphic_enough(*self.tcx, cast_ty)?;
448+
ensure_monomorphic_enough(src.layout.ty)?;
449+
ensure_monomorphic_enough(cast_ty)?;
450450

451451
span_bug!(
452452
self.cur_span(),
@@ -502,8 +502,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
502502
}
503503
_ => {
504504
// Do not ICE if we are not monomorphic enough.
505-
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
506-
ensure_monomorphic_enough(*self.tcx, cast_ty.ty)?;
505+
ensure_monomorphic_enough(src.layout.ty)?;
506+
ensure_monomorphic_enough(cast_ty.ty)?;
507507

508508
span_bug!(
509509
self.cur_span(),

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,22 +186,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
186186
match intrinsic_name {
187187
sym::type_name => {
188188
let tp_ty = instance.args.type_at(0);
189-
ensure_monomorphic_enough(tcx, tp_ty)?;
189+
ensure_monomorphic_enough(tp_ty)?;
190190
let (alloc_id, meta) = alloc_type_name(tcx, tp_ty);
191191
let val = ConstValue::Slice { alloc_id, meta };
192192
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
193193
self.copy_op(&val, dest)?;
194194
}
195195
sym::needs_drop => {
196196
let tp_ty = instance.args.type_at(0);
197-
ensure_monomorphic_enough(tcx, tp_ty)?;
197+
ensure_monomorphic_enough(tp_ty)?;
198198
let val = ConstValue::from_bool(tp_ty.needs_drop(tcx, self.typing_env));
199199
let val = self.const_val_to_op(val, tcx.types.bool, Some(dest.layout))?;
200200
self.copy_op(&val, dest)?;
201201
}
202202
sym::type_id => {
203203
let tp_ty = instance.args.type_at(0);
204-
ensure_monomorphic_enough(tcx, tp_ty)?;
204+
ensure_monomorphic_enough(tp_ty)?;
205205
self.write_type_id(tp_ty, dest)?;
206206
}
207207
sym::type_id_eq => {

compiler/rustc_const_eval/src/interpret/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
2626
let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty));
2727

2828
// All vtables must be monomorphic, bail out otherwise.
29-
ensure_monomorphic_enough(*self.tcx, ty)?;
30-
ensure_monomorphic_enough(*self.tcx, dyn_ty)?;
29+
ensure_monomorphic_enough(ty)?;
30+
ensure_monomorphic_enough(dyn_ty)?;
3131

3232
let salt = M::get_global_alloc_salt(self, None);
3333
let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);

compiler/rustc_const_eval/src/interpret/util.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>(
1919
ty: Ty<'tcx>,
2020
trait_ty: Ty<'tcx>,
2121
) -> InterpResult<'tcx, (bool, &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>)> {
22-
ensure_monomorphic_enough(ecx.tcx.tcx, ty)?;
23-
ensure_monomorphic_enough(ecx.tcx.tcx, trait_ty)?;
22+
ensure_monomorphic_enough(ty)?;
23+
ensure_monomorphic_enough(trait_ty)?;
2424

2525
let ty::Dynamic(preds, _) = trait_ty.kind() else {
2626
span_bug!(
@@ -50,7 +50,7 @@ pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>(
5050
/// Checks whether a type contains generic parameters which must be instantiated.
5151
///
5252
/// In case it does, returns a `TooGeneric` const eval error.
53-
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(_tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
53+
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(ty: T) -> InterpResult<'tcx>
5454
where
5555
T: TypeVisitable<TyCtxt<'tcx>>,
5656
{

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use super::{
3535
format_interp_error,
3636
};
3737
use crate::enter_trace_span;
38-
use crate::interpret::ensure_monomorphic_enough;
3938

4039
// for the validation errors
4140
#[rustfmt::skip]
@@ -1585,9 +1584,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15851584
) -> InterpResult<'tcx> {
15861585
trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty);
15871586

1588-
// We can't check validity if there are any generics left.
1589-
ensure_monomorphic_enough(*self.tcx, val.layout.ty)?;
1590-
15911587
// Run the visitor.
15921588
self.run_for_validation_mut(|ecx| {
15931589
let reset_padding = reset_provenance_and_padding && {

compiler/rustc_middle/src/mir/consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ impl<'tcx> Const<'tcx> {
341341
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
342342
tcx.const_eval_resolve(typing_env, uneval, span)
343343
}
344-
Const::Val(val, _) => Ok(val),
344+
Const::Val(val, _ty) => Ok(val),
345345
}
346346
}
347347

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,37 @@ impl<'tcx> ConstToPat<'tcx> {
107107
self.tcx.erase_and_anonymize_regions(self.typing_env).with_codegen_normalized(self.tcx);
108108
let alias_const = self.tcx.erase_and_anonymize_regions(alias_const);
109109

110+
let mk_too_generic_err = || {
111+
let mut err = self
112+
.tcx
113+
.dcx()
114+
.create_err(ConstPatternDependsOnGenericParameter { span: self.span });
115+
for arg in alias_const.args {
116+
if let ty::GenericArgKind::Type(ty) = arg.kind()
117+
&& let ty::Param(param_ty) = ty.kind()
118+
{
119+
let def_id = self.tcx.hir_enclosing_body_owner(self.id);
120+
let generics = self.tcx.generics_of(def_id);
121+
let param = generics.type_param(*param_ty, self.tcx);
122+
let span = self.tcx.def_span(param.def_id);
123+
err.span_label(span, "constant depends on this generic parameter");
124+
if let Some(ident) = self.tcx.def_ident_span(def_id)
125+
&& self.tcx.sess.source_map().is_multiline(ident.between(span))
126+
{
127+
// Display the `fn` name as well in the diagnostic, as the generic isn't
128+
// in the same line and it could be confusing otherwise.
129+
err.span_label(ident, "");
130+
}
131+
}
132+
}
133+
return self.mk_err(err, ty);
134+
};
135+
110136
// FIXME(gca): This will become insufficient once associated constants can be
111137
// implemented as `type` consts (project-const-generics#76). At that point it'll
112138
// become necessary to just use type system normalization for all const patterns
113139
// but that's not yet possible.
114-
let mut thir_pat = if alias_const.kind.is_type_const(self.tcx) {
140+
let const_value = if alias_const.kind.is_type_const(self.tcx) {
115141
let Ok(normalize) = self
116142
.tcx
117143
.try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c))
@@ -124,7 +150,7 @@ impl<'tcx> ConstToPat<'tcx> {
124150
let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
125151
return self.mk_err(err, ty);
126152
};
127-
self.valtree_to_pat(value)
153+
value
128154
} else {
129155
// try to resolve e.g. associated constants to their definition on an impl, and then
130156
// evaluate the const.
@@ -147,29 +173,7 @@ impl<'tcx> ConstToPat<'tcx> {
147173
return self.mk_err(err, ty);
148174
}
149175
Err(ErrorHandled::TooGeneric(_)) => {
150-
let mut err = self
151-
.tcx
152-
.dcx()
153-
.create_err(ConstPatternDependsOnGenericParameter { span: self.span });
154-
for arg in alias_const.args {
155-
if let ty::GenericArgKind::Type(ty) = arg.kind()
156-
&& let ty::Param(param_ty) = ty.kind()
157-
{
158-
let def_id = self.tcx.hir_enclosing_body_owner(self.id);
159-
let generics = self.tcx.generics_of(def_id);
160-
let param = generics.type_param(*param_ty, self.tcx);
161-
let span = self.tcx.def_span(param.def_id);
162-
err.span_label(span, "constant depends on this generic parameter");
163-
if let Some(ident) = self.tcx.def_ident_span(def_id)
164-
&& self.tcx.sess.source_map().is_multiline(ident.between(span))
165-
{
166-
// Display the `fn` name as well in the diagnostic, as the generic isn't
167-
// in the same line and it could be confusing otherwise.
168-
err.span_label(ident, "");
169-
}
170-
}
171-
}
172-
return self.mk_err(err, ty);
176+
return mk_too_generic_err();
173177
}
174178
Ok(Err(bad_ty)) => {
175179
// The pattern cannot be turned into a valtree.
@@ -192,8 +196,12 @@ impl<'tcx> ConstToPat<'tcx> {
192196
};
193197

194198
// Lower the valtree to a THIR pattern.
195-
self.valtree_to_pat(ty::Value { ty, valtree })
199+
ty::Value { ty, valtree }
196200
};
201+
if const_value.ty.has_param() {
202+
return mk_too_generic_err();
203+
}
204+
let mut thir_pat = self.valtree_to_pat(const_value);
197205

198206
if !thir_pat.references_error() {
199207
// Always check for `PartialEq` if we had no other errors yet.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//! Ensure we can deal with a pattern that depends on a generic in its path, but the
2+
//! actual pattern value can be computed independent of the generic.
3+
#[derive(PartialEq)]
4+
pub struct Thing<const N: usize>;
5+
6+
impl<const N: usize> Thing<N> {
7+
const A: Self = Thing;
8+
}
9+
10+
fn broken<const N: usize>(x: Thing<N>) {
11+
match x {
12+
<Thing<N>>::A => {} //~ERROR: cannot depend on generic
13+
_ => {}
14+
}
15+
}
16+
17+
fn main() {}

0 commit comments

Comments
 (0)