Skip to content

Commit 3a95d63

Browse files
committed
Introduce tcx.anon_const_kind query
1 parent 6e23095 commit 3a95d63

File tree

11 files changed

+86
-46
lines changed

11 files changed

+86
-46
lines changed

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
}
@@ -1828,3 +1829,27 @@ fn const_param_default<'tcx>(
18281829
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
18291830
ty::EarlyBinder::bind(ct)
18301831
}
1832+
1833+
fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
1834+
let hir_id = tcx.local_def_id_to_hir_id(def);
1835+
let const_arg_id = tcx.parent_hir_id(hir_id);
1836+
match tcx.hir_node(const_arg_id) {
1837+
hir::Node::ConstArg(_) => {
1838+
if tcx.features().generic_const_exprs() {
1839+
ty::AnonConstKind::GCEConst
1840+
} else if tcx.features().min_generic_const_args() {
1841+
ty::AnonConstKind::MCGConst
1842+
} else if let hir::Node::Expr(hir::Expr {
1843+
kind: hir::ExprKind::Repeat(_, repeat_count),
1844+
..
1845+
}) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
1846+
&& repeat_count.hir_id == const_arg_id
1847+
{
1848+
ty::AnonConstKind::RepeatExprCount
1849+
} else {
1850+
ty::AnonConstKind::MCGConst
1851+
}
1852+
}
1853+
_ => ty::AnonConstKind::NonTypeSystem,
1854+
}
1855+
}

compiler/rustc_hir_analysis/src/collect/generics_of.rs

+30-41
Original file line numberDiff line numberDiff line change
@@ -104,19 +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) = 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) =>
120128
{
121129
// If the def_id we are calling generics_of on is an anon ct default i.e:
122130
//
@@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
160168
has_self: generics.has_self,
161169
has_late_bound_regions: generics.has_late_bound_regions,
162170
};
163-
} else {
164-
// HACK(eddyb) this provides the correct generics when
165-
// `feature(generic_const_expressions)` is enabled, so that const expressions
166-
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
167-
//
168-
// Note that we do not supply the parent generics when using
169-
// `min_const_generics`.
170-
Some(parent_did)
171171
}
172-
} else {
173-
let parent_node = tcx.parent_hir_node(hir_id);
174-
let parent_node = match parent_node {
175-
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
176-
_ => parent_node,
177-
};
178-
match parent_node {
179-
// HACK(eddyb) this provides the correct generics for repeat
180-
// expressions' count (i.e. `N` in `[x; N]`), and explicit
181-
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
182-
// as they shouldn't be able to cause query cycle errors.
183-
Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. })
184-
if ct.anon_const_hir_id() == Some(hir_id) =>
185-
{
186-
Some(parent_did)
187-
}
188-
Node::TyPat(_) => Some(parent_did),
189-
// Field default values inherit the ADT's generics.
190-
Node::Field(_) => Some(parent_did),
191-
_ => 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)
192179
}
180+
// Default to no generic parameters for other kinds of anon consts
181+
ty::AnonConstKind::NonTypeSystem => None,
193182
}
194183
}
195184
Node::ConstBlock(_)

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

+1
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ provide! { tcx, def_id, other, cdata,
423423
doc_link_traits_in_scope => {
424424
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
425425
}
426+
anon_const_kind => { table }
426427
}
427428

428429
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
@@ -478,6 +478,7 @@ define_tables! {
478478
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
479479
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
480480
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
481+
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
481482
}
482483

483484
#[derive(TyEncodable, TyDecodable)]

compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ trivial! {
311311
rustc_middle::ty::Asyncness,
312312
rustc_middle::ty::AsyncDestructor,
313313
rustc_middle::ty::BoundVariableKind,
314+
rustc_middle::ty::AnonConstKind,
314315
rustc_middle::ty::DeducedParamAttrs,
315316
rustc_middle::ty::Destructor,
316317
rustc_middle::ty::fast_reject::SimplifiedType,

compiler/rustc_middle/src/query/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2576,6 +2576,12 @@ rustc_queries! {
25762576
desc { "estimating codegen size of `{}`", key }
25772577
cache_on_disk_if { true }
25782578
}
2579+
2580+
query anon_const_kind(def_id: DefId) -> ty::AnonConstKind {
2581+
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
2582+
cache_on_disk_if { def_id.is_local() }
2583+
separate_provide_extern
2584+
}
25792585
}
25802586

25812587
rustc_with_all_queries! { 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::walk::TypeWalker;
77
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
88

@@ -259,3 +259,11 @@ impl<'tcx> Const<'tcx> {
259259
TypeWalker::new(self.into())
260260
}
261261
}
262+
263+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
264+
pub enum AnonConstKind {
265+
GCEConst,
266+
MCGConst,
267+
RepeatExprCount,
268+
NonTypeSystem,
269+
}

compiler/rustc_middle/src/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ pub use self::closure::{
6464
place_to_string_for_capture,
6565
};
6666
pub use self::consts::{
67-
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind,
68-
Value,
67+
AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
68+
ValTree, ValTreeKind, Value,
6969
};
7070
pub use self::context::{
7171
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,

compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! {
6868
ty::AsyncDestructor,
6969
ty::AssocItemContainer,
7070
ty::Asyncness,
71+
ty::AnonConstKind,
7172
ty::DeducedParamAttrs,
7273
ty::Destructor,
7374
ty::Generics,

compiler/rustc_trait_selection/src/traits/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,8 @@ pub fn try_evaluate_const<'tcx>(
553553
//
554554
// FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
555555
// instead of having this logic here
556-
let (args, typing_env) = if tcx.features().generic_const_exprs()
556+
let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst
557+
&& let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def)
557558
&& uv.has_non_region_infer()
558559
{
559560
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
@@ -582,7 +583,10 @@ pub fn try_evaluate_const<'tcx>(
582583
(args, typing_env)
583584
}
584585
}
585-
} else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
586+
} else if tcx.def_kind(uv.def) == DefKind::AnonConst
587+
&& let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def)
588+
&& uv.has_non_region_infer()
589+
{
586590
// FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
587591
//
588592
// Diagnostics will sometimes replace the identity args of anon consts in
@@ -599,6 +603,7 @@ pub fn try_evaluate_const<'tcx>(
599603

600604
let args = GenericArgs::identity_for_item(tcx, uv.def);
601605
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
606+
602607
(args, typing_env)
603608
} else {
604609
// FIXME: This codepath is reachable under `associated_const_equality` and in the

0 commit comments

Comments
 (0)