Skip to content

Commit 4eee955

Browse files
committed
Auto merge of #66669 - petrochenkov:tup2attr, r=matthewjasper
Fix some issues with attributes on unnamed fields Fixes #66487 Fixes #66555
2 parents c9bacb7 + f1359c6 commit 4eee955

File tree

6 files changed

+55
-13
lines changed

6 files changed

+55
-13
lines changed

src/librustc_resolve/build_reduced_graph.rs

+3
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
746746

747747
// Record field names for error reporting.
748748
let field_names = struct_def.fields().iter().map(|field| {
749+
// NOTE: The field may be an expansion placeholder, but expansion sets correct
750+
// visibilities for unnamed field placeholders specifically, so the constructor
751+
// visibility should still be determined correctly.
749752
let field_vis = self.resolve_visibility(&field.vis);
750753
if ctor_vis.is_at_least(field_vis, &*self.r) {
751754
ctor_vis = field_vis;

src/librustc_resolve/def_collector.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,16 @@ impl<'a> DefCollector<'a> {
8080
}
8181

8282
fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
83+
let index = |this: &Self| index.unwrap_or_else(|| {
84+
let node_id = NodeId::placeholder_from_expn_id(this.expansion);
85+
this.definitions.placeholder_field_index(node_id)
86+
});
87+
8388
if field.is_placeholder {
89+
self.definitions.set_placeholder_field_index(field.id, index(self));
8490
self.visit_macro_invoc(field.id);
8591
} else {
86-
let name = field.ident.map(|ident| ident.name)
87-
.or_else(|| index.map(sym::integer))
88-
.unwrap_or_else(|| {
89-
let node_id = NodeId::placeholder_from_expn_id(self.expansion);
90-
sym::integer(self.definitions.placeholder_field_index(node_id))
91-
});
92+
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
9293
let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
9394
self.with_parent(def, |this| visit::walk_struct_field(this, field));
9495
}
@@ -190,9 +191,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
190191
// and every such attribute expands into a single field after it's resolved.
191192
for (index, field) in data.fields().iter().enumerate() {
192193
self.collect_field(field, Some(index));
193-
if field.is_placeholder && field.ident.is_none() {
194-
self.definitions.set_placeholder_field_index(field.id, index);
195-
}
196194
}
197195
}
198196

src/libsyntax_expand/expand.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ macro_rules! ast_fragments {
8686
// mention some macro variable from those arguments even if it's not used.
8787
#[cfg_attr(bootstrap, allow(unused_macros))]
8888
macro _repeating($flat_map_ast_elt) {}
89-
placeholder(AstFragmentKind::$Kind, *id).$make_ast()
89+
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
9090
})),)?)*
9191
_ => panic!("unexpected AST fragment kind")
9292
}
@@ -275,6 +275,23 @@ pub enum InvocationKind {
275275
},
276276
}
277277

278+
impl InvocationKind {
279+
fn placeholder_visibility(&self) -> Option<ast::Visibility> {
280+
// HACK: For unnamed fields placeholders should have the same visibility as the actual
281+
// fields because for tuple structs/variants resolve determines visibilities of their
282+
// constructor using these field visibilities before attributes on them are are expanded.
283+
// The assumption is that the attribute expansion cannot change field visibilities,
284+
// and it holds because only inert attributes are supported in this position.
285+
match self {
286+
InvocationKind::Attr { item: Annotatable::StructField(field), .. } |
287+
InvocationKind::Derive { item: Annotatable::StructField(field), .. } |
288+
InvocationKind::DeriveContainer { item: Annotatable::StructField(field), .. }
289+
if field.ident.is_none() => Some(field.vis.clone()),
290+
_ => None,
291+
}
292+
}
293+
}
294+
278295
impl Invocation {
279296
pub fn span(&self) -> Span {
280297
match &self.kind {
@@ -931,6 +948,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
931948
_ => None,
932949
};
933950
let expn_id = ExpnId::fresh(expn_data);
951+
let vis = kind.placeholder_visibility();
934952
self.invocations.push(Invocation {
935953
kind,
936954
fragment_kind,
@@ -940,7 +958,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
940958
..self.cx.current_expansion.clone()
941959
},
942960
});
943-
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id))
961+
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
944962
}
945963

946964
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {

src/libsyntax_expand/placeholders.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use smallvec::{smallvec, SmallVec};
1212

1313
use rustc_data_structures::fx::FxHashMap;
1414

15-
pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
15+
pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visibility>)
16+
-> AstFragment {
1617
fn mac_placeholder() -> ast::Mac {
1718
ast::Mac {
1819
path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
@@ -26,7 +27,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
2627
let ident = ast::Ident::invalid();
2728
let attrs = Vec::new();
2829
let generics = ast::Generics::default();
29-
let vis = dummy_spanned(ast::VisibilityKind::Inherited);
30+
let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited));
3031
let span = DUMMY_SP;
3132
let expr_placeholder = || P(ast::Expr {
3233
id, span,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Duplicate non-builtin attributes can be used on unnamed fields.
2+
3+
// check-pass
4+
5+
struct S (
6+
#[rustfmt::skip]
7+
#[rustfmt::skip]
8+
u8
9+
);
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Unnamed fields don't lose their visibility due to non-builtin attributes on them.
2+
3+
// check-pass
4+
5+
mod m {
6+
pub struct S(#[rustfmt::skip] pub u8);
7+
}
8+
9+
fn main() {
10+
m::S(0);
11+
}

0 commit comments

Comments
 (0)