Skip to content

Commit d3a8524

Browse files
committed
Auto merge of rust-lang#129137 - camelid:lazy-def-macro-const, r=BoxyUwU
Fix anon const def-creation when macros are involved Fixes rust-lang#128016. Ever since rust-lang#125915, some `ast::AnonConst`s turn into `hir::ConstArgKind::Path`s, which don't have associated `DefId`s. To deal with the fact that we don't have resolution information in `DefCollector`, we decided to implement a process where if the anon const *appeared* to be trivial (i.e., `N` or `{ N }`), we would avoid creating a def for it in `DefCollector`. If later, in AST lowering, we realized it turned out to be a unit struct literal, or we were lowering it to something that didn't use `hir::ConstArg`, we'd create its def there. However, let's say we have a macro `m!()` that expands to a reference to a free constant `FOO`. If we use `m!()` in the body of an anon const (e.g., `Foo<{ m!() }>`), then in def collection, it appears to be a nontrivial anon const and we create a def. But the macro expands to something that looks like a trivial const arg, but is not, so in AST lowering we "fix" the mistake we assumed def collection made and create a def for it. This causes a duplicate definition ICE. The long-term fix for this is to delay the creation of defs for all expression-like nodes until AST lowering (see rust-lang#128844 for an incomplete attempt at this). This would avoid issues like this one that are caused by hacky workarounds. However, doing this uncovers a pre-existing bug with opaque types that is quite involved to fix (see rust-lang#129023). In the meantime, this PR fixes the bug by delaying def creation for anon consts whose bodies are macro invocations until after we expand the macro and know what is inside it. This is accomplished by adding information to create the anon const's def to the data in `Resolver.invocation_parents`. r? `@BoxyUwU`
2 parents adaff53 + e0bd011 commit d3a8524

37 files changed

+182
-246
lines changed

compiler/rustc_ast/src/ast.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -1188,14 +1188,7 @@ impl Expr {
11881188
///
11891189
/// Does not ensure that the path resolves to a const param, the caller should check this.
11901190
pub fn is_potential_trivial_const_arg(&self) -> bool {
1191-
let this = if let ExprKind::Block(block, None) = &self.kind
1192-
&& let [stmt] = block.stmts.as_slice()
1193-
&& let StmtKind::Expr(expr) = &stmt.kind
1194-
{
1195-
expr
1196-
} else {
1197-
self
1198-
};
1191+
let this = self.maybe_unwrap_block();
11991192

12001193
if let ExprKind::Path(None, path) = &this.kind
12011194
&& path.is_potential_trivial_const_arg()
@@ -1206,6 +1199,17 @@ impl Expr {
12061199
}
12071200
}
12081201

1202+
pub fn maybe_unwrap_block(&self) -> &Expr {
1203+
if let ExprKind::Block(block, None) = &self.kind
1204+
&& let [stmt] = block.stmts.as_slice()
1205+
&& let StmtKind::Expr(expr) = &stmt.kind
1206+
{
1207+
expr
1208+
} else {
1209+
self
1210+
}
1211+
}
1212+
12091213
pub fn to_bound(&self) -> Option<GenericBound> {
12101214
match &self.kind {
12111215
ExprKind::Path(None, path) => Some(GenericBound::Trait(

compiler/rustc_ast_lowering/src/asm.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
220220
let parent_def_id = self.current_def_id_parent;
221221
let node_id = self.next_node_id();
222222
// HACK(min_generic_const_args): see lower_anon_const
223-
if !self.tcx.features().const_arg_path
224-
|| !expr.is_potential_trivial_const_arg()
225-
{
223+
if !expr.is_potential_trivial_const_arg() {
226224
self.create_def(
227225
parent_def_id,
228226
node_id,

compiler/rustc_ast_lowering/src/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
387387
let node_id = self.next_node_id();
388388

389389
// HACK(min_generic_const_args): see lower_anon_const
390-
if !self.tcx.features().const_arg_path || !arg.is_potential_trivial_const_arg() {
390+
if !arg.is_potential_trivial_const_arg() {
391391
// Add a definition for the in-band const def.
392392
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
393393
}

compiler/rustc_ast_lowering/src/lib.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -2335,7 +2335,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23352335
span: Span,
23362336
) -> &'hir hir::ConstArg<'hir> {
23372337
let ct_kind = match res {
2338-
Res::Def(DefKind::ConstParam, _) if self.tcx.features().const_arg_path => {
2338+
Res::Def(DefKind::ConstParam, _) => {
23392339
let qpath = self.lower_qpath(
23402340
ty_id,
23412341
&None,
@@ -2410,8 +2410,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24102410
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
24112411
debug!("res={:?}", maybe_res);
24122412
// FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
2413-
if self.tcx.features().const_arg_path
2414-
&& let Some(res) = maybe_res
2413+
if let Some(res) = maybe_res
24152414
&& let Res::Def(DefKind::ConstParam, _) = res
24162415
&& let ExprKind::Path(qself, path) = &expr.kind
24172416
{
@@ -2442,7 +2441,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24422441
/// See [`hir::ConstArg`] for when to use this function vs
24432442
/// [`Self::lower_anon_const_to_const_arg`].
24442443
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
2445-
if self.tcx.features().const_arg_path && c.value.is_potential_trivial_const_arg() {
2444+
if c.value.is_potential_trivial_const_arg() {
24462445
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
24472446
// Over there, we guess if this is a bare param and only create a def if
24482447
// we think it's not. However we may can guess wrong (see there for example)

compiler/rustc_feature/src/unstable.rs

-2
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,6 @@ declare_features! (
193193
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
194194
/// Allows identifying the `compiler_builtins` crate.
195195
(internal, compiler_builtins, "1.13.0", None),
196-
/// Gating for a new desugaring of const arguments of usages of const parameters
197-
(internal, const_arg_path, "1.81.0", None),
198196
/// Allows writing custom MIR
199197
(internal, custom_mir, "1.65.0", None),
200198
/// Outputs useful `assert!` messages

compiler/rustc_middle/src/ty/consts.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -295,20 +295,12 @@ impl<'tcx> Const<'tcx> {
295295
_ => expr,
296296
};
297297

298-
if let hir::ExprKind::Path(
299-
qpath @ hir::QPath::Resolved(
300-
_,
301-
&hir::Path { res: Res::Def(DefKind::ConstParam, _), .. },
302-
),
303-
) = expr.kind
298+
if let hir::ExprKind::Path(hir::QPath::Resolved(
299+
_,
300+
&hir::Path { res: Res::Def(DefKind::ConstParam, _), .. },
301+
)) = expr.kind
304302
{
305-
if tcx.features().const_arg_path {
306-
span_bug!(
307-
expr.span,
308-
"try_from_lit: received const param which shouldn't be possible"
309-
);
310-
}
311-
return Some(Const::from_param(tcx, qpath, expr.hir_id));
303+
span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible");
312304
};
313305

314306
let lit_input = match expr.kind {

compiler/rustc_resolve/src/def_collector.rs

+80-40
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,37 @@ use rustc_span::symbol::{kw, sym, Symbol};
1212
use rustc_span::Span;
1313
use tracing::debug;
1414

15-
use crate::{ImplTraitContext, Resolver};
15+
use crate::{ImplTraitContext, InvocationParent, PendingAnonConstInfo, Resolver};
1616

1717
pub(crate) fn collect_definitions(
1818
resolver: &mut Resolver<'_, '_>,
1919
fragment: &AstFragment,
2020
expansion: LocalExpnId,
2121
) {
22-
let (parent_def, impl_trait_context, in_attr) = resolver.invocation_parents[&expansion];
23-
let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr };
22+
let InvocationParent { parent_def, pending_anon_const_info, impl_trait_context, in_attr } =
23+
resolver.invocation_parents[&expansion];
24+
let mut visitor = DefCollector {
25+
resolver,
26+
parent_def,
27+
pending_anon_const_info,
28+
expansion,
29+
impl_trait_context,
30+
in_attr,
31+
};
2432
fragment.visit_with(&mut visitor);
2533
}
2634

2735
/// Creates `DefId`s for nodes in the AST.
2836
struct DefCollector<'a, 'ra, 'tcx> {
2937
resolver: &'a mut Resolver<'ra, 'tcx>,
3038
parent_def: LocalDefId,
39+
/// If we have an anon const that consists of a macro invocation, e.g. `Foo<{ m!() }>`,
40+
/// we need to wait until we know what the macro expands to before we create the def for
41+
/// the anon const. That's because we lower some anon consts into `hir::ConstArgKind::Path`,
42+
/// which don't have defs.
43+
///
44+
/// See `Self::visit_anon_const()`.
45+
pending_anon_const_info: Option<PendingAnonConstInfo>,
3146
impl_trait_context: ImplTraitContext,
3247
in_attr: bool,
3348
expansion: LocalExpnId,
@@ -111,10 +126,16 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
111126

112127
fn visit_macro_invoc(&mut self, id: NodeId) {
113128
let id = id.placeholder_to_expn_id();
114-
let old_parent = self
115-
.resolver
116-
.invocation_parents
117-
.insert(id, (self.parent_def, self.impl_trait_context, self.in_attr));
129+
let pending_anon_const_info = self.pending_anon_const_info.take();
130+
let old_parent = self.resolver.invocation_parents.insert(
131+
id,
132+
InvocationParent {
133+
parent_def: self.parent_def,
134+
pending_anon_const_info,
135+
impl_trait_context: self.impl_trait_context,
136+
in_attr: self.in_attr,
137+
},
138+
);
118139
assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
119140
}
120141
}
@@ -326,46 +347,65 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
326347
}
327348

328349
fn visit_anon_const(&mut self, constant: &'a AnonConst) {
329-
if self.resolver.tcx.features().const_arg_path
330-
&& constant.value.is_potential_trivial_const_arg()
331-
{
332-
// HACK(min_generic_const_args): don't create defs for anon consts if we think they will
333-
// later be turned into ConstArgKind::Path's. because this is before resolve is done, we
334-
// may accidentally identify a construction of a unit struct as a param and not create a
335-
// def. we'll then create a def later in ast lowering in this case. the parent of nested
336-
// items will be messed up, but that's ok because there can't be any if we're just looking
337-
// for bare idents.
338-
visit::walk_anon_const(self, constant)
339-
} else {
340-
let def =
341-
self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
342-
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
350+
// HACK(min_generic_const_args): don't create defs for anon consts if we think they will
351+
// later be turned into ConstArgKind::Path's. because this is before resolve is done, we
352+
// may accidentally identify a construction of a unit struct as a param and not create a
353+
// def. we'll then create a def later in ast lowering in this case. the parent of nested
354+
// items will be messed up, but that's ok because there can't be any if we're just looking
355+
// for bare idents.
356+
357+
if matches!(constant.value.maybe_unwrap_block().kind, ExprKind::MacCall(..)) {
358+
// See self.pending_anon_const_info for explanation
359+
self.pending_anon_const_info =
360+
Some(PendingAnonConstInfo { id: constant.id, span: constant.value.span });
361+
return visit::walk_anon_const(self, constant);
362+
} else if constant.value.is_potential_trivial_const_arg() {
363+
return visit::walk_anon_const(self, constant);
343364
}
365+
366+
let def = self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
367+
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
344368
}
345369

346370
fn visit_expr(&mut self, expr: &'a Expr) {
347-
let parent_def = match expr.kind {
348-
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
349-
ExprKind::Closure(..) | ExprKind::Gen(..) => {
350-
self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
351-
}
352-
ExprKind::ConstBlock(ref constant) => {
353-
for attr in &expr.attrs {
354-
visit::walk_attribute(self, attr);
355-
}
356-
let def = self.create_def(
357-
constant.id,
358-
kw::Empty,
359-
DefKind::InlineConst,
360-
constant.value.span,
361-
);
362-
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
363-
return;
371+
if matches!(expr.kind, ExprKind::MacCall(..)) {
372+
return self.visit_macro_invoc(expr.id);
373+
}
374+
375+
let grandparent_def = if let Some(pending_anon) = self.pending_anon_const_info.take() {
376+
// See self.pending_anon_const_info for explanation
377+
if !expr.is_potential_trivial_const_arg() {
378+
self.create_def(pending_anon.id, kw::Empty, DefKind::AnonConst, pending_anon.span)
379+
} else {
380+
self.parent_def
364381
}
365-
_ => self.parent_def,
382+
} else {
383+
self.parent_def
366384
};
367385

368-
self.with_parent(parent_def, |this| visit::walk_expr(this, expr));
386+
self.with_parent(grandparent_def, |this| {
387+
let parent_def = match expr.kind {
388+
ExprKind::Closure(..) | ExprKind::Gen(..) => {
389+
this.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
390+
}
391+
ExprKind::ConstBlock(ref constant) => {
392+
for attr in &expr.attrs {
393+
visit::walk_attribute(this, attr);
394+
}
395+
let def = this.create_def(
396+
constant.id,
397+
kw::Empty,
398+
DefKind::InlineConst,
399+
constant.value.span,
400+
);
401+
this.with_parent(def, |this| visit::walk_anon_const(this, constant));
402+
return;
403+
}
404+
_ => this.parent_def,
405+
};
406+
407+
this.with_parent(parent_def, |this| visit::walk_expr(this, expr))
408+
})
369409
}
370410

371411
fn visit_ty(&mut self, ty: &'a Ty) {

compiler/rustc_resolve/src/lib.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,29 @@ impl<'ra> ParentScope<'ra> {
171171
}
172172
}
173173

174+
#[derive(Copy, Debug, Clone)]
175+
struct InvocationParent {
176+
parent_def: LocalDefId,
177+
pending_anon_const_info: Option<PendingAnonConstInfo>,
178+
impl_trait_context: ImplTraitContext,
179+
in_attr: bool,
180+
}
181+
182+
impl InvocationParent {
183+
const ROOT: Self = Self {
184+
parent_def: CRATE_DEF_ID,
185+
pending_anon_const_info: None,
186+
impl_trait_context: ImplTraitContext::Existential,
187+
in_attr: false,
188+
};
189+
}
190+
191+
#[derive(Copy, Debug, Clone)]
192+
struct PendingAnonConstInfo {
193+
id: NodeId,
194+
span: Span,
195+
}
196+
174197
#[derive(Copy, Debug, Clone)]
175198
enum ImplTraitContext {
176199
Existential,
@@ -1144,7 +1167,7 @@ pub struct Resolver<'ra, 'tcx> {
11441167
/// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
11451168
/// we know what parent node that fragment should be attached to thanks to this table,
11461169
/// and how the `impl Trait` fragments were introduced.
1147-
invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext, bool /*in_attr*/)>,
1170+
invocation_parents: FxHashMap<LocalExpnId, InvocationParent>,
11481171

11491172
/// Some way to know that we are in a *trait* impl in `visit_assoc_item`.
11501173
/// FIXME: Replace with a more general AST map (together with some other fields).
@@ -1382,8 +1405,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
13821405
node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed);
13831406

13841407
let mut invocation_parents = FxHashMap::default();
1385-
invocation_parents
1386-
.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential, false));
1408+
invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT);
13871409

13881410
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = tcx
13891411
.sess

compiler/rustc_resolve/src/macros.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ use crate::errors::{
4242
use crate::imports::Import;
4343
use crate::Namespace::*;
4444
use crate::{
45-
BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, MacroData, ModuleKind,
46-
ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError,
47-
Resolver, ScopeSet, Segment, ToNameBinding, Used,
45+
BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, InvocationParent, MacroData,
46+
ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
47+
ResolutionError, Resolver, ScopeSet, Segment, ToNameBinding, Used,
4848
};
4949

5050
type Res = def::Res<NodeId>;
@@ -183,7 +183,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
183183
}
184184

185185
fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId {
186-
self.invocation_parents[&id].0
186+
self.invocation_parents[&id].parent_def
187187
}
188188

189189
fn resolve_dollar_crates(&mut self) {
@@ -303,12 +303,12 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
303303
.invocation_parents
304304
.get(&invoc_id)
305305
.or_else(|| self.invocation_parents.get(&eager_expansion_root))
306-
.filter(|&&(mod_def_id, _, in_attr)| {
306+
.filter(|&&InvocationParent { parent_def: mod_def_id, in_attr, .. }| {
307307
in_attr
308308
&& invoc.fragment_kind == AstFragmentKind::Expr
309309
&& self.tcx.def_kind(mod_def_id) == DefKind::Mod
310310
})
311-
.map(|&(mod_def_id, ..)| mod_def_id);
311+
.map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id);
312312
let (ext, res) = self.smart_resolve_macro_path(
313313
path,
314314
kind,
@@ -951,7 +951,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
951951
let node_id = self
952952
.invocation_parents
953953
.get(&parent_scope.expansion)
954-
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]);
954+
.map_or(ast::CRATE_NODE_ID, |parent| {
955+
self.def_id_to_node_id[parent.parent_def]
956+
});
955957
self.lint_buffer.buffer_lint(
956958
LEGACY_DERIVE_HELPERS,
957959
node_id,

compiler/rustc_span/src/symbol.rs

-1
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,6 @@ symbols! {
599599
conservative_impl_trait,
600600
console,
601601
const_allocate,
602-
const_arg_path,
603602
const_async_blocks,
604603
const_closures,
605604
const_compare_raw_pointers,

tests/ui-fulldeps/stable-mir/check_instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn test_stable_mir() -> ControlFlow<()> {
3535
// Get all items and split generic vs monomorphic items.
3636
let (generic, mono): (Vec<_>, Vec<_>) =
3737
items.into_iter().partition(|item| item.requires_monomorphization());
38-
assert_eq!(mono.len(), 4, "Expected 3 mono functions");
38+
assert_eq!(mono.len(), 3, "Expected 3 mono functions");
3939
assert_eq!(generic.len(), 2, "Expected 2 generic functions");
4040

4141
// For all monomorphic items, get the correspondent instances.

0 commit comments

Comments
 (0)