mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-06 12:18:33 +00:00
expand: Fully preserve visibilities on unnamed fields with attributes
This commit is contained in:
parent
37bb0c7fa6
commit
f1359c61d3
@ -746,6 +746,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||||||
|
|
||||||
// Record field names for error reporting.
|
// Record field names for error reporting.
|
||||||
let field_names = struct_def.fields().iter().map(|field| {
|
let field_names = struct_def.fields().iter().map(|field| {
|
||||||
|
// NOTE: The field may be an expansion placeholder, but expansion sets correct
|
||||||
|
// visibilities for unnamed field placeholders specifically, so the constructor
|
||||||
|
// visibility should still be determined correctly.
|
||||||
let field_vis = self.resolve_visibility(&field.vis);
|
let field_vis = self.resolve_visibility(&field.vis);
|
||||||
if ctor_vis.is_at_least(field_vis, &*self.r) {
|
if ctor_vis.is_at_least(field_vis, &*self.r) {
|
||||||
ctor_vis = field_vis;
|
ctor_vis = field_vis;
|
||||||
|
@ -86,7 +86,7 @@ macro_rules! ast_fragments {
|
|||||||
// mention some macro variable from those arguments even if it's not used.
|
// mention some macro variable from those arguments even if it's not used.
|
||||||
#[cfg_attr(bootstrap, allow(unused_macros))]
|
#[cfg_attr(bootstrap, allow(unused_macros))]
|
||||||
macro _repeating($flat_map_ast_elt) {}
|
macro _repeating($flat_map_ast_elt) {}
|
||||||
placeholder(AstFragmentKind::$Kind, *id).$make_ast()
|
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
|
||||||
})),)?)*
|
})),)?)*
|
||||||
_ => panic!("unexpected AST fragment kind")
|
_ => panic!("unexpected AST fragment kind")
|
||||||
}
|
}
|
||||||
@ -275,6 +275,23 @@ pub enum InvocationKind {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InvocationKind {
|
||||||
|
fn placeholder_visibility(&self) -> Option<ast::Visibility> {
|
||||||
|
// HACK: For unnamed fields placeholders should have the same visibility as the actual
|
||||||
|
// fields because for tuple structs/variants resolve determines visibilities of their
|
||||||
|
// constructor using these field visibilities before attributes on them are are expanded.
|
||||||
|
// The assumption is that the attribute expansion cannot change field visibilities,
|
||||||
|
// and it holds because only inert attributes are supported in this position.
|
||||||
|
match self {
|
||||||
|
InvocationKind::Attr { item: Annotatable::StructField(field), .. } |
|
||||||
|
InvocationKind::Derive { item: Annotatable::StructField(field), .. } |
|
||||||
|
InvocationKind::DeriveContainer { item: Annotatable::StructField(field), .. }
|
||||||
|
if field.ident.is_none() => Some(field.vis.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Invocation {
|
impl Invocation {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
@ -931,6 +948,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let expn_id = ExpnId::fresh(expn_data);
|
let expn_id = ExpnId::fresh(expn_data);
|
||||||
|
let vis = kind.placeholder_visibility();
|
||||||
self.invocations.push(Invocation {
|
self.invocations.push(Invocation {
|
||||||
kind,
|
kind,
|
||||||
fragment_kind,
|
fragment_kind,
|
||||||
@ -940,7 +958,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||||||
..self.cx.current_expansion.clone()
|
..self.cx.current_expansion.clone()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id))
|
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
|
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
|
||||||
|
@ -12,7 +12,8 @@ use smallvec::{smallvec, SmallVec};
|
|||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
|
||||||
pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visibility>)
|
||||||
|
-> AstFragment {
|
||||||
fn mac_placeholder() -> ast::Mac {
|
fn mac_placeholder() -> ast::Mac {
|
||||||
ast::Mac {
|
ast::Mac {
|
||||||
path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
|
path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
|
||||||
@ -26,7 +27,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||||||
let ident = ast::Ident::invalid();
|
let ident = ast::Ident::invalid();
|
||||||
let attrs = Vec::new();
|
let attrs = Vec::new();
|
||||||
let generics = ast::Generics::default();
|
let generics = ast::Generics::default();
|
||||||
let vis = dummy_spanned(ast::VisibilityKind::Inherited);
|
let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited));
|
||||||
let span = DUMMY_SP;
|
let span = DUMMY_SP;
|
||||||
let expr_placeholder = || P(ast::Expr {
|
let expr_placeholder = || P(ast::Expr {
|
||||||
id, span,
|
id, span,
|
||||||
|
11
src/test/ui/attributes/unnamed-field-attributes-vis.rs
Normal file
11
src/test/ui/attributes/unnamed-field-attributes-vis.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Unnamed fields don't lose their visibility due to non-builtin attributes on them.
|
||||||
|
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
mod m {
|
||||||
|
pub struct S(#[rustfmt::skip] pub u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
m::S(0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user