Skip to content

Commit 8f55245

Browse files
authored
Rollup merge of rust-lang#64457 - petrochenkov:macunfield, r=matthewjasper
def_collector: Do not ICE on attributes on unnamed fields The primary issue here is that the expansion infra needs to visit a field in isolation, and fields don't know their own indices during expansion, so they have to be kept in some other place (e.g. `struct Definitions`). Fixes rust-lang#64385
2 parents b35ebac + c681cf7 commit 8f55245

File tree

3 files changed

+38
-21
lines changed

3 files changed

+38
-21
lines changed

src/librustc/hir/map/def_collector.rs

+27-21
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl<'a> DefCollector<'a> {
3131
self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
3232
}
3333

34-
pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
34+
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
3535
let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
3636
f(self);
3737
self.parent_def = orig_parent_def;
@@ -74,6 +74,22 @@ impl<'a> DefCollector<'a> {
7474
})
7575
}
7676

77+
fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
78+
if field.is_placeholder {
79+
self.visit_macro_invoc(field.id);
80+
} else {
81+
let name = field.ident.map(|ident| ident.name)
82+
.or_else(|| index.map(sym::integer))
83+
.unwrap_or_else(|| {
84+
let node_id = NodeId::placeholder_from_expn_id(self.expansion);
85+
sym::integer(self.definitions.placeholder_field_indices[&node_id])
86+
})
87+
.as_interned_str();
88+
let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
89+
self.with_parent(def, |this| visit::walk_struct_field(this, field));
90+
}
91+
}
92+
7793
pub fn visit_macro_invoc(&mut self, id: NodeId) {
7894
self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
7995
}
@@ -170,17 +186,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
170186
}
171187

172188
fn visit_variant_data(&mut self, data: &'a VariantData) {
189+
// The assumption here is that non-`cfg` macro expansion cannot change field indices.
190+
// It currently holds because only inert attributes are accepted on fields,
191+
// and every such attribute expands into a single field after it's resolved.
173192
for (index, field) in data.fields().iter().enumerate() {
174-
if field.is_placeholder {
175-
self.visit_macro_invoc(field.id);
176-
continue;
193+
self.collect_field(field, Some(index));
194+
if field.is_placeholder && field.ident.is_none() {
195+
self.definitions.placeholder_field_indices.insert(field.id, index);
177196
}
178-
let name = field.ident.map(|ident| ident.name)
179-
.unwrap_or_else(|| sym::integer(index));
180-
let def = self.create_def(field.id,
181-
DefPathData::ValueNs(name.as_interned_str()),
182-
field.span);
183-
self.with_parent(def, |this| visit::walk_struct_field(this, field));
184197
}
185198
}
186199

@@ -338,16 +351,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
338351
}
339352
}
340353

341-
fn visit_struct_field(&mut self, sf: &'a StructField) {
342-
if sf.is_placeholder {
343-
self.visit_macro_invoc(sf.id)
344-
} else {
345-
let name = sf.ident.map(|ident| ident.name)
346-
.unwrap_or_else(|| panic!("don't know the field number in this context"));
347-
let def = self.create_def(sf.id,
348-
DefPathData::ValueNs(name.as_interned_str()),
349-
sf.span);
350-
self.with_parent(def, |this| visit::walk_struct_field(this, sf));
351-
}
354+
// This method is called only when we are visiting an individual field
355+
// after expanding an attribute on it.
356+
fn visit_struct_field(&mut self, field: &'a StructField) {
357+
self.collect_field(field, None);
352358
}
353359
}

src/librustc/hir/map/definitions.rs

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ pub struct Definitions {
104104
/// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
105105
/// we know what parent node that fragment should be attached to thanks to this table.
106106
invocation_parents: FxHashMap<ExpnId, DefIndex>,
107+
/// Indices of unnamed struct or variant fields with unresolved attributes.
108+
pub(super) placeholder_field_indices: NodeMap<usize>,
107109
}
108110

109111
/// A unique identifier that we can use to lookup a definition
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// check-pass
2+
3+
struct S(
4+
#[rustfmt::skip] u8,
5+
u16,
6+
#[rustfmt::skip] u32,
7+
);
8+
9+
fn main() {}

0 commit comments

Comments
 (0)