Skip to content

Commit 041c1e6

Browse files
committed
Auto merge of rust-lang#137972 - BoxyUwU:ty_const_wf_before_eval, r=<try>
Ensure constants are WF before calling into CTFE Fixes rust-lang#127643 Fixes rust-lang#131046 Fixes rust-lang#131406 Fixes rust-lang#133066 I'll write a PR desc for this tommorow r? `@ghost`
2 parents 961351c + a475ffe commit 041c1e6

File tree

56 files changed

+911
-257
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+911
-257
lines changed

compiler/rustc_const_eval/src/check_consts/ops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
142142
|err, self_ty, trait_id| {
143143
// FIXME(const_trait_impl): Do we need any of this on the non-const codepath?
144144

145-
let trait_ref = TraitRef::from_method(tcx, trait_id, self.args);
145+
let trait_ref = TraitRef::from_assoc_args(tcx, trait_id, self.args);
146146

147147
match self_ty.kind() {
148148
Param(param_ty) => {

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+38
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,44 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
335335
tcx: TyCtxt<'tcx>,
336336
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
337337
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
338+
// Avoid evaluating instances with impossible bounds required to hold as
339+
// this can result in executing code that should never be executed.
340+
let instance_def = key.value.instance.def_id();
341+
if tcx.def_kind(instance_def) == DefKind::AnonConst
342+
&& let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(instance_def)
343+
{ // ... do nothing for GCE anon consts as it would cycle
344+
} else if tcx.def_kind(instance_def) == DefKind::AnonConst
345+
&& let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(instance_def)
346+
{
347+
// Instead of erroring when encountering a repeat expr hack const with impossible
348+
// preds we just FCW, as anon consts are unnameable and this code *might* wind up
349+
// supported one day if the anon const is a path expr.
350+
if tcx.instantiate_and_check_impossible_predicates((
351+
instance_def,
352+
tcx.erase_regions(key.value.instance.args),
353+
)) {
354+
if let Some(local_def) = instance_def.as_local() {
355+
tcx.node_span_lint(
356+
rustc_session::lint::builtin::CONST_EVALUATABLE_UNCHECKED,
357+
tcx.local_def_id_to_hir_id(local_def),
358+
tcx.def_span(instance_def),
359+
|lint| {
360+
lint.primary_message(
361+
"cannot use constants which depend on trivially-false where clauses",
362+
);
363+
},
364+
)
365+
} else {
366+
// If the repeat expr count is from some upstream crate then we don't care to
367+
// lint on it as it should have been linted on when compiling the upstream crate.
368+
}
369+
};
370+
} else if tcx
371+
.instantiate_and_check_impossible_predicates((instance_def, key.value.instance.args))
372+
{
373+
return Err(ErrorHandled::TooGeneric(tcx.def_span(instance_def)));
374+
}
375+
338376
// This shouldn't be used for statics, since statics are conceptually places,
339377
// not values -- so what we do here could break pointer identity.
340378
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));

compiler/rustc_const_eval/src/interpret/call.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
741741
let tcx = *self.tcx;
742742

743743
let trait_def_id = tcx.trait_of_item(def_id).unwrap();
744-
let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args);
744+
let virtual_trait_ref =
745+
ty::TraitRef::from_assoc_args(tcx, trait_def_id, virtual_instance.args);
745746
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
746747
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
747748

compiler/rustc_hir_analysis/src/collect.rs

+25
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub(crate) fn provide(providers: &mut Providers) {
8989
opaque_ty_origin,
9090
rendered_precise_capturing_args,
9191
const_param_default,
92+
anon_const_kind,
9293
..*providers
9394
};
9495
}
@@ -1827,3 +1828,27 @@ fn const_param_default<'tcx>(
18271828
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
18281829
ty::EarlyBinder::bind(ct)
18291830
}
1831+
1832+
fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
1833+
let hir_id = tcx.local_def_id_to_hir_id(def);
1834+
let const_arg_id = tcx.parent_hir_id(hir_id);
1835+
match tcx.hir_node(const_arg_id) {
1836+
hir::Node::ConstArg(_) => {
1837+
if tcx.features().generic_const_exprs() {
1838+
ty::AnonConstKind::GCEConst
1839+
} else if tcx.features().min_generic_const_args() {
1840+
ty::AnonConstKind::MCGConst
1841+
} else if let hir::Node::Expr(hir::Expr {
1842+
kind: hir::ExprKind::Repeat(_, repeat_count),
1843+
..
1844+
}) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
1845+
&& repeat_count.hir_id == const_arg_id
1846+
{
1847+
ty::AnonConstKind::RepeatExprCount
1848+
} else {
1849+
ty::AnonConstKind::MCGConst
1850+
}
1851+
}
1852+
_ => ty::AnonConstKind::NonTypeSystem,
1853+
}
1854+
}

compiler/rustc_hir_analysis/src/collect/generics_of.rs

+30-42
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
104104
}
105105
}
106106

107-
if in_param_ty {
108-
// We do not allow generic parameters in anon consts if we are inside
109-
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
110-
None
111-
} else if tcx.features().generic_const_exprs() {
112-
let parent_node = tcx.parent_hir_node(hir_id);
113-
debug!(?parent_node);
114-
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
115-
&& constant.hir_id == hir_id
116-
{
117-
// enum variant discriminants are not allowed to use any kind of generics
118-
None
119-
} else if let Some(param_id) =
120-
tcx.hir().opt_const_param_default_param_def_id(hir_id)
107+
match tcx.anon_const_kind(def_id) {
108+
// Stable: anon consts are not able to use any generic parameters...
109+
ty::AnonConstKind::MCGConst => None,
110+
// we provide generics to repeat expr counts as a backwards compatibility hack. #76200
111+
ty::AnonConstKind::RepeatExprCount => Some(parent_did),
112+
113+
// Even GCE anon const should not be allowed to use generic parameters as it would be
114+
// trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::<N>]`.
115+
//
116+
// We could potentially mirror the hack done for defaults of generic parameters but
117+
// this case just doesn't come up much compared to `const N: u32 = ...`. Long term the
118+
// hack for defaulted parameters should be removed eventually anyway.
119+
ty::AnonConstKind::GCEConst if in_param_ty => None,
120+
// GCE anon consts as a default for a generic parameter should have their provided generics
121+
// "truncated" up to whatever generic parameter this anon const is within the default of.
122+
//
123+
// FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type
124+
// parameter defaults, e.g. `T = Foo</*defid*/>`.
125+
ty::AnonConstKind::GCEConst
126+
if let Some(param_id) =
127+
tcx.hir().opt_const_param_default_param_def_id(hir_id) =>
121128
{
122129
// If the def_id we are calling generics_of on is an anon ct default i.e:
123130
//
@@ -161,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
161168
has_self: generics.has_self,
162169
has_late_bound_regions: generics.has_late_bound_regions,
163170
};
164-
} else {
165-
// HACK(eddyb) this provides the correct generics when
166-
// `feature(generic_const_expressions)` is enabled, so that const expressions
167-
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
168-
//
169-
// Note that we do not supply the parent generics when using
170-
// `min_const_generics`.
171-
Some(parent_did)
172171
}
173-
} else {
174-
let parent_node = tcx.parent_hir_node(hir_id);
175-
let parent_node = match parent_node {
176-
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
177-
_ => parent_node,
178-
};
179-
match parent_node {
180-
// HACK(eddyb) this provides the correct generics for repeat
181-
// expressions' count (i.e. `N` in `[x; N]`), and explicit
182-
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
183-
// as they shouldn't be able to cause query cycle errors.
184-
Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. })
185-
if ct.anon_const_hir_id() == Some(hir_id) =>
186-
{
187-
Some(parent_did)
188-
}
189-
Node::TyPat(_) => Some(parent_did),
190-
// Field default values inherit the ADT's generics.
191-
Node::Field(_) => Some(parent_did),
192-
_ => None,
172+
ty::AnonConstKind::GCEConst => Some(parent_did),
173+
174+
// Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/`
175+
ty::AnonConstKind::NonTypeSystem
176+
if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) =>
177+
{
178+
Some(parent_did)
193179
}
180+
// Default to no generic parameters for other kinds of anon consts
181+
ty::AnonConstKind::NonTypeSystem => None,
194182
}
195183
}
196184
Node::ConstBlock(_)

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ provide! { tcx, def_id, other, cdata,
429429
doc_link_traits_in_scope => {
430430
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
431431
}
432+
anon_const_kind => { table }
432433
}
433434

434435
pub(in crate::rmeta) fn provide(providers: &mut Providers) {

compiler/rustc_metadata/src/rmeta/encoder.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
15641564
<- tcx.explicit_implied_const_bounds(def_id).skip_binder());
15651565
}
15661566
}
1567+
if let DefKind::AnonConst = def_kind {
1568+
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
1569+
}
15671570
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
15681571
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
15691572
{

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ define_tables! {
469469
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
470470
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
471471
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
472+
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
472473
}
473474

474475
#[derive(TyEncodable, TyDecodable)]

compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ trivial! {
302302
rustc_middle::ty::Asyncness,
303303
rustc_middle::ty::AsyncDestructor,
304304
rustc_middle::ty::BoundVariableKind,
305+
rustc_middle::ty::AnonConstKind,
305306
rustc_middle::ty::DeducedParamAttrs,
306307
rustc_middle::ty::Destructor,
307308
rustc_middle::ty::fast_reject::SimplifiedType,

compiler/rustc_middle/src/query/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2512,6 +2512,12 @@ rustc_queries! {
25122512
desc { "estimating codegen size of `{}`", key }
25132513
cache_on_disk_if { true }
25142514
}
2515+
2516+
query anon_const_kind(def_id: DefId) -> ty::AnonConstKind {
2517+
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
2518+
cache_on_disk_if { def_id.is_local() }
2519+
separate_provide_extern
2520+
}
25152521
}
25162522

25172523
rustc_query_append! { define_callbacks! }

compiler/rustc_middle/src/ty/consts.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::Cow;
22

33
use rustc_data_structures::intern::Interned;
44
use rustc_error_messages::MultiSpan;
5-
use rustc_macros::HashStable;
5+
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
66
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
77

88
use crate::ty::{self, Ty, TyCtxt};
@@ -244,3 +244,11 @@ impl<'tcx> Const<'tcx> {
244244
matches!(self.kind(), ty::ConstKind::Infer(_))
245245
}
246246
}
247+
248+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
249+
pub enum AnonConstKind {
250+
GCEConst,
251+
MCGConst,
252+
RepeatExprCount,
253+
NonTypeSystem,
254+
}

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
761761
}
762762

763763
impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features {
764+
fn min_generic_const_args(self) -> bool {
765+
self.min_generic_const_args()
766+
}
767+
764768
fn generic_const_exprs(self) -> bool {
765769
self.generic_const_exprs()
766770
}

compiler/rustc_middle/src/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ pub use self::closure::{
6161
place_to_string_for_capture,
6262
};
6363
pub use self::consts::{
64-
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind,
65-
Value,
64+
AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
65+
ValTree, ValTreeKind, Value,
6666
};
6767
pub use self::context::{
6868
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,

compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ trivially_parameterized_over_tcx! {
6666
crate::mir::ConstQualifs,
6767
ty::AssocItemContainer,
6868
ty::Asyncness,
69+
ty::AnonConstKind,
6970
ty::DeducedParamAttrs,
7071
ty::Generics,
7172
ty::ImplPolarity,

compiler/rustc_next_trait_solver/src/solve/mod.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,26 @@ where
143143
) -> QueryResult<I> {
144144
match ct.kind() {
145145
ty::ConstKind::Unevaluated(uv) => {
146+
// `ConstEvaluatable` goals don't really need to exist under `mgca` as we can assume all
147+
// generic const args can be sucessfully evaluated as they have been checked at def site.
148+
//
149+
// The only reason we keep this around is so that wf checking of signatures is guaranteed
150+
// to wind up normalizing constants emitting errors if they are ill formed. The equivalent
151+
// check does not exist for types and results in diverging aliases not being normalized during
152+
// wfck sometimes.
153+
//
154+
// Regardless, the point being that the behaviour of this goal doesn't really matter so we just
155+
// always return `Ok` and evaluate for the CTFE side effect of emitting an error.
156+
if self.cx().features().min_generic_const_args() {
157+
let _ = self.evaluate_const(param_env, uv);
158+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
159+
}
160+
146161
// We never return `NoSolution` here as `evaluate_const` emits an
147162
// error itself when failing to evaluate, so emitting an additional fulfillment
148163
// error in that case is unnecessary noise. This may change in the future once
149164
// evaluation failures are allowed to impact selection, e.g. generic const
150165
// expressions in impl headers or `where`-clauses.
151-
152-
// FIXME(generic_const_exprs): Implement handling for generic
153-
// const expressions here.
154166
if let Some(_normalized) = self.evaluate_const(param_env, uv) {
155167
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
156168
} else {

compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ pub(crate) fn transform_instance<'tcx>(
343343
let upcast_ty = match tcx.trait_of_item(def_id) {
344344
Some(trait_id) => trait_object_ty(
345345
tcx,
346-
ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
346+
ty::Binder::dummy(ty::TraitRef::from_assoc_args(tcx, trait_id, instance.args)),
347347
),
348348
// drop_in_place won't have a defining trait, skip the upcast
349349
None => instance.args.type_at(0),
@@ -482,7 +482,7 @@ fn implemented_method<'tcx>(
482482
trait_method = trait_method_bound;
483483
method_id = instance.def_id();
484484
trait_id = tcx.trait_of_item(method_id)?;
485-
trait_ref = ty::EarlyBinder::bind(TraitRef::from_method(tcx, trait_id, instance.args));
485+
trait_ref = ty::EarlyBinder::bind(TraitRef::from_assoc_args(tcx, trait_id, instance.args));
486486
trait_id
487487
} else {
488488
return None;

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,16 @@ pub fn is_const_evaluatable<'tcx>(
8686
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
8787
}
8888
} else if tcx.features().min_generic_const_args() {
89-
// This is a sanity check to make sure that non-generics consts are checked to
90-
// be evaluatable in case they aren't cchecked elsewhere. This will NOT error
91-
// if the const uses generics, as desired.
89+
// `ConstEvaluatable` goals don't really need to exist under `mgca` as we can assume all
90+
// generic const args can be sucessfully evaluated as they have been checked at def site.
91+
//
92+
// The only reason we keep this around is so that wf checking of signatures is guaranteed
93+
// to wind up normalizing constants emitting errors if they are ill formed. The equivalent
94+
// check does not exist for types and results in diverging aliases not being normalized during
95+
// wfck sometimes.
96+
//
97+
// Regardless, the point being that the behaviour of this goal doesn't really matter so we just
98+
// always return `Ok` and evaluate for the CTFE side effect of emitting an error.
9299
crate::traits::evaluate_const(infcx, unexpanded_ct, param_env);
93100
Ok(())
94101
} else {

0 commit comments

Comments
 (0)