Skip to content

Commit 8cba0a9

Browse files
authored
Rollup merge of #66183 - Centril:empty-vis-trait-decl, r=petrochenkov
*Syntactically* permit visibilities on trait items & enum variants Fixes #65041 Suppose we have `$vis trait_item` or `$vis enum_variant` and `$vis` is a `:vis` macro fragment. Before this PR, this would fail to parse. This is now instead allowed as per language team consensus in #65041 (comment). (See added tests for elaboration.) Moreover, we now also permit visibility modifiers on trait items & enum variants *syntactically* but reject them with semantic checks (in `ast_validation`): ```rust #[cfg(FALSE)] trait Foo { pub fn bar(); } // OK #[cfg(FALSE)] enum E { pub U } // OK ```
2 parents 083b5a0 + 9a88364 commit 8cba0a9

25 files changed

+184
-109
lines changed

src/librustc_parse/parser/diagnostics.rs

-20
Original file line numberDiff line numberDiff line change
@@ -1189,26 +1189,6 @@ impl<'a> Parser<'a> {
11891189
}
11901190
}
11911191

1192-
/// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
1193-
pub(super) fn eat_bad_pub(&mut self) {
1194-
// When `unclosed_delims` is populated, it means that the code being parsed is already
1195-
// quite malformed, which might mean that, for example, a pub struct definition could be
1196-
// parsed as being a trait item, which is invalid and this error would trigger
1197-
// unconditionally, resulting in misleading diagnostics. Because of this, we only attempt
1198-
// this nice to have recovery for code that is otherwise well formed.
1199-
if self.token.is_keyword(kw::Pub) && self.unclosed_delims.is_empty() {
1200-
match self.parse_visibility(false) {
1201-
Ok(vis) => {
1202-
self.diagnostic()
1203-
.struct_span_err(vis.span, "unnecessary visibility qualifier")
1204-
.span_label(vis.span, "`pub` not permitted here")
1205-
.emit();
1206-
}
1207-
Err(mut err) => err.emit(),
1208-
}
1209-
}
1210-
}
1211-
12121192
/// Eats tokens until we can be relatively sure we reached the end of the
12131193
/// statement. This is something of a best-effort heuristic.
12141194
///

src/librustc_parse/parser/item.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Parser, PathStyle};
1+
use super::{Parser, PathStyle, FollowedByType};
22
use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim};
33

44
use crate::maybe_whole;
@@ -87,7 +87,7 @@ impl<'a> Parser<'a> {
8787

8888
let lo = self.token.span;
8989

90-
let vis = self.parse_visibility(false)?;
90+
let vis = self.parse_visibility(FollowedByType::No)?;
9191

9292
if self.eat_keyword(kw::Use) {
9393
// USE ITEM
@@ -696,7 +696,7 @@ impl<'a> Parser<'a> {
696696
mut attrs: Vec<Attribute>,
697697
) -> PResult<'a, ImplItem> {
698698
let lo = self.token.span;
699-
let vis = self.parse_visibility(false)?;
699+
let vis = self.parse_visibility(FollowedByType::No)?;
700700
let defaultness = self.parse_defaultness();
701701
let (name, kind, generics) = if self.eat_keyword(kw::Type) {
702702
let (name, ty, generics) = self.parse_type_alias()?;
@@ -883,7 +883,7 @@ impl<'a> Parser<'a> {
883883
mut attrs: Vec<Attribute>,
884884
) -> PResult<'a, TraitItem> {
885885
let lo = self.token.span;
886-
self.eat_bad_pub();
886+
let vis = self.parse_visibility(FollowedByType::No)?;
887887
let (name, kind, generics) = if self.eat_keyword(kw::Type) {
888888
self.parse_trait_item_assoc_ty()?
889889
} else if self.is_const_item() {
@@ -899,6 +899,7 @@ impl<'a> Parser<'a> {
899899
id: DUMMY_NODE_ID,
900900
ident: name,
901901
attrs,
902+
vis,
902903
generics,
903904
kind,
904905
span: lo.to(self.prev_span),
@@ -1129,7 +1130,7 @@ impl<'a> Parser<'a> {
11291130

11301131
let attrs = self.parse_outer_attributes()?;
11311132
let lo = self.token.span;
1132-
let visibility = self.parse_visibility(false)?;
1133+
let visibility = self.parse_visibility(FollowedByType::No)?;
11331134

11341135
// FOREIGN STATIC ITEM
11351136
// Treat `const` as `static` for error recovery, but don't add it to expected tokens.
@@ -1339,7 +1340,7 @@ impl<'a> Parser<'a> {
13391340
let variant_attrs = self.parse_outer_attributes()?;
13401341
let vlo = self.token.span;
13411342

1342-
self.eat_bad_pub();
1343+
let vis = self.parse_visibility(FollowedByType::No)?;
13431344
let ident = self.parse_ident()?;
13441345

13451346
let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
@@ -1366,6 +1367,7 @@ impl<'a> Parser<'a> {
13661367

13671368
let vr = ast::Variant {
13681369
ident,
1370+
vis,
13691371
id: DUMMY_NODE_ID,
13701372
attrs: variant_attrs,
13711373
data: struct_def,
@@ -1519,7 +1521,7 @@ impl<'a> Parser<'a> {
15191521
self.parse_paren_comma_seq(|p| {
15201522
let attrs = p.parse_outer_attributes()?;
15211523
let lo = p.token.span;
1522-
let vis = p.parse_visibility(true)?;
1524+
let vis = p.parse_visibility(FollowedByType::Yes)?;
15231525
let ty = p.parse_ty()?;
15241526
Ok(StructField {
15251527
span: lo.to(ty.span),
@@ -1537,7 +1539,7 @@ impl<'a> Parser<'a> {
15371539
fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
15381540
let attrs = self.parse_outer_attributes()?;
15391541
let lo = self.token.span;
1540-
let vis = self.parse_visibility(false)?;
1542+
let vis = self.parse_visibility(FollowedByType::No)?;
15411543
self.parse_single_struct_field(lo, vis, attrs)
15421544
}
15431545

src/librustc_parse/parser/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,8 @@ impl SeqSep {
348348
}
349349
}
350350

351+
pub enum FollowedByType { Yes, No }
352+
351353
impl<'a> Parser<'a> {
352354
pub fn new(
353355
sess: &'a ParseSess,
@@ -1120,7 +1122,7 @@ impl<'a> Parser<'a> {
11201122
/// If the following element can't be a tuple (i.e., it's a function definition), then
11211123
/// it's not a tuple struct field), and the contents within the parentheses isn't valid,
11221124
/// so emit a proper diagnostic.
1123-
pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
1125+
pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
11241126
maybe_whole!(self, NtVis, |x| x);
11251127

11261128
self.expected_tokens.push(TokenType::Keyword(kw::Crate));
@@ -1175,7 +1177,9 @@ impl<'a> Parser<'a> {
11751177
id: ast::DUMMY_NODE_ID,
11761178
};
11771179
return Ok(respan(lo.to(self.prev_span), vis));
1178-
} else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct.
1180+
} else if let FollowedByType::No = fbt {
1181+
// Provide this diagnostic if a type cannot follow;
1182+
// in particular, if this is not a tuple struct.
11791183
self.recover_incorrect_vis_restriction()?;
11801184
// Emit diagnostic, but continue with public visibility.
11811185
}

src/librustc_passes/ast_validation.rs

+6
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
529529
}
530530
ItemKind::Enum(ref def, _) => {
531531
for variant in &def.variants {
532+
self.invalid_visibility(&variant.vis, None);
532533
for field in variant.data.fields() {
533534
self.invalid_visibility(&field.vis, None);
534535
}
@@ -751,6 +752,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
751752
}
752753
visit::walk_impl_item(self, ii);
753754
}
755+
756+
fn visit_trait_item(&mut self, ti: &'a TraitItem) {
757+
self.invalid_visibility(&ti.vis, None);
758+
visit::walk_trait_item(self, ti);
759+
}
754760
}
755761

756762
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {

src/libsyntax/ast.rs

+29-21
Original file line numberDiff line numberDiff line change
@@ -982,12 +982,12 @@ pub struct Arm {
982982
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
983983
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
984984
pub struct Field {
985+
pub attrs: ThinVec<Attribute>,
986+
pub id: NodeId,
987+
pub span: Span,
985988
pub ident: Ident,
986989
pub expr: P<Expr>,
987-
pub span: Span,
988990
pub is_shorthand: bool,
989-
pub attrs: ThinVec<Attribute>,
990-
pub id: NodeId,
991991
pub is_placeholder: bool,
992992
}
993993

@@ -1567,12 +1567,14 @@ pub struct FnSig {
15671567
/// signature) or provided (meaning it has a default implementation).
15681568
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
15691569
pub struct TraitItem {
1570+
pub attrs: Vec<Attribute>,
15701571
pub id: NodeId,
1572+
pub span: Span,
1573+
pub vis: Visibility,
15711574
pub ident: Ident,
1572-
pub attrs: Vec<Attribute>,
1575+
15731576
pub generics: Generics,
15741577
pub kind: TraitItemKind,
1575-
pub span: Span,
15761578
/// See `Item::tokens` for what this is.
15771579
pub tokens: Option<TokenStream>,
15781580
}
@@ -1588,14 +1590,15 @@ pub enum TraitItemKind {
15881590
/// Represents anything within an `impl` block.
15891591
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
15901592
pub struct ImplItem {
1593+
pub attrs: Vec<Attribute>,
15911594
pub id: NodeId,
1592-
pub ident: Ident,
1595+
pub span: Span,
15931596
pub vis: Visibility,
1597+
pub ident: Ident,
1598+
15941599
pub defaultness: Defaultness,
1595-
pub attrs: Vec<Attribute>,
15961600
pub generics: Generics,
15971601
pub kind: ImplItemKind,
1598-
pub span: Span,
15991602
/// See `Item::tokens` for what this is.
16001603
pub tokens: Option<TokenStream>,
16011604
}
@@ -2174,22 +2177,24 @@ pub struct GlobalAsm {
21742177
pub struct EnumDef {
21752178
pub variants: Vec<Variant>,
21762179
}
2177-
21782180
/// Enum variant.
21792181
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
21802182
pub struct Variant {
2181-
/// Name of the variant.
2182-
pub ident: Ident,
21832183
/// Attributes of the variant.
21842184
pub attrs: Vec<Attribute>,
21852185
/// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
21862186
pub id: NodeId,
2187+
/// Span
2188+
pub span: Span,
2189+
/// The visibility of the variant. Syntactically accepted but not semantically.
2190+
pub vis: Visibility,
2191+
/// Name of the variant.
2192+
pub ident: Ident,
2193+
21872194
/// Fields and constructor id of the variant.
21882195
pub data: VariantData,
21892196
/// Explicit discriminant, e.g., `Foo = 1`.
21902197
pub disr_expr: Option<AnonConst>,
2191-
/// Span
2192-
pub span: Span,
21932198
/// Is a macro placeholder
21942199
pub is_placeholder: bool,
21952200
}
@@ -2368,12 +2373,13 @@ impl VisibilityKind {
23682373
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
23692374
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
23702375
pub struct StructField {
2376+
pub attrs: Vec<Attribute>,
2377+
pub id: NodeId,
23712378
pub span: Span,
2372-
pub ident: Option<Ident>,
23732379
pub vis: Visibility,
2374-
pub id: NodeId,
2380+
pub ident: Option<Ident>,
2381+
23752382
pub ty: P<Ty>,
2376-
pub attrs: Vec<Attribute>,
23772383
pub is_placeholder: bool,
23782384
}
23792385

@@ -2417,12 +2423,13 @@ impl VariantData {
24172423
/// The name might be a dummy name in case of anonymous items.
24182424
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
24192425
pub struct Item {
2420-
pub ident: Ident,
24212426
pub attrs: Vec<Attribute>,
24222427
pub id: NodeId,
2423-
pub kind: ItemKind,
2424-
pub vis: Visibility,
24252428
pub span: Span,
2429+
pub vis: Visibility,
2430+
pub ident: Ident,
2431+
2432+
pub kind: ItemKind,
24262433

24272434
/// Original tokens this item was parsed from. This isn't necessarily
24282435
/// available for all items, although over time more and more items should
@@ -2579,12 +2586,13 @@ impl ItemKind {
25792586

25802587
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
25812588
pub struct ForeignItem {
2582-
pub ident: Ident,
25832589
pub attrs: Vec<Attribute>,
2584-
pub kind: ForeignItemKind,
25852590
pub id: NodeId,
25862591
pub span: Span,
25872592
pub vis: Visibility,
2593+
pub ident: Ident,
2594+
2595+
pub kind: ForeignItemKind,
25882596
}
25892597

25902598
/// An item within an `extern` block.

src/libsyntax/mut_visit.rs

+24-22
Original file line numberDiff line numberDiff line change
@@ -472,16 +472,17 @@ pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis:
472472
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
473473
}
474474

475-
pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, vis: &mut T)
475+
pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, visitor: &mut T)
476476
-> SmallVec<[Variant; 1]>
477477
{
478-
let Variant { ident, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
479-
vis.visit_ident(ident);
480-
visit_attrs(attrs, vis);
481-
vis.visit_id(id);
482-
vis.visit_variant_data(data);
483-
visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr));
484-
vis.visit_span(span);
478+
let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
479+
visitor.visit_ident(ident);
480+
visitor.visit_vis(vis);
481+
visit_attrs(attrs, visitor);
482+
visitor.visit_id(id);
483+
visitor.visit_variant_data(data);
484+
visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
485+
visitor.visit_span(span);
485486
smallvec![variant]
486487
}
487488

@@ -916,32 +917,33 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
916917
}
917918
}
918919

919-
pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, vis: &mut T)
920+
pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, visitor: &mut T)
920921
-> SmallVec<[TraitItem; 1]>
921922
{
922-
let TraitItem { id, ident, attrs, generics, kind, span, tokens: _ } = &mut item;
923-
vis.visit_id(id);
924-
vis.visit_ident(ident);
925-
visit_attrs(attrs, vis);
926-
vis.visit_generics(generics);
923+
let TraitItem { id, ident, vis, attrs, generics, kind, span, tokens: _ } = &mut item;
924+
visitor.visit_id(id);
925+
visitor.visit_ident(ident);
926+
visitor.visit_vis(vis);
927+
visit_attrs(attrs, visitor);
928+
visitor.visit_generics(generics);
927929
match kind {
928930
TraitItemKind::Const(ty, default) => {
929-
vis.visit_ty(ty);
930-
visit_opt(default, |default| vis.visit_expr(default));
931+
visitor.visit_ty(ty);
932+
visit_opt(default, |default| visitor.visit_expr(default));
931933
}
932934
TraitItemKind::Method(sig, body) => {
933-
visit_fn_sig(sig, vis);
934-
visit_opt(body, |body| vis.visit_block(body));
935+
visit_fn_sig(sig, visitor);
936+
visit_opt(body, |body| visitor.visit_block(body));
935937
}
936938
TraitItemKind::Type(bounds, default) => {
937-
visit_bounds(bounds, vis);
938-
visit_opt(default, |default| vis.visit_ty(default));
939+
visit_bounds(bounds, visitor);
940+
visit_opt(default, |default| visitor.visit_ty(default));
939941
}
940942
TraitItemKind::Macro(mac) => {
941-
vis.visit_mac(mac);
943+
visitor.visit_mac(mac);
942944
}
943945
}
944-
vis.visit_span(span);
946+
visitor.visit_span(span);
945947

946948
smallvec![item]
947949
}

src/libsyntax/print/pprust/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ fn test_variant_to_string() {
5050

5151
let var = ast::Variant {
5252
ident,
53+
vis: source_map::respan(syntax_pos::DUMMY_SP, ast::VisibilityKind::Inherited),
5354
attrs: Vec::new(),
5455
id: ast::DUMMY_NODE_ID,
5556
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),

src/libsyntax/visit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant)
310310
where V: Visitor<'a>,
311311
{
312312
visitor.visit_ident(variant.ident);
313+
visitor.visit_vis(&variant.vis);
313314
visitor.visit_variant_data(&variant.data);
314315
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
315316
walk_list!(visitor, visit_attribute, &variant.attrs);
@@ -581,6 +582,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
581582
}
582583

583584
pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) {
585+
visitor.visit_vis(&trait_item.vis);
584586
visitor.visit_ident(trait_item.ident);
585587
walk_list!(visitor, visit_attribute, &trait_item.attrs);
586588
visitor.visit_generics(&trait_item.generics);

0 commit comments

Comments
 (0)