about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-11-07 11:26:36 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2019-11-11 06:33:09 +0100
commit9a88364525a4660dbd6f6a371b3b25199f5bbe4a (patch)
tree36a46f60d870ddf657e871e22f8b7ef4564d0fef
parente2fa9527d44522b900c739cc82faa734f877bcda (diff)
downloadrust-9a88364525a4660dbd6f6a371b3b25199f5bbe4a.tar.gz
rust-9a88364525a4660dbd6f6a371b3b25199f5bbe4a.zip
syntactically allow visibility on trait item & enum variant
-rw-r--r--src/librustc_parse/parser/diagnostics.rs20
-rw-r--r--src/librustc_parse/parser/item.rs18
-rw-r--r--src/librustc_parse/parser/mod.rs8
-rw-r--r--src/librustc_passes/ast_validation.rs6
-rw-r--r--src/libsyntax/ast.rs50
-rw-r--r--src/libsyntax/mut_visit.rs46
-rw-r--r--src/libsyntax/print/pprust/tests.rs1
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/libsyntax_expand/build.rs4
-rw-r--r--src/libsyntax_expand/mbe/macro_parser.rs4
-rw-r--r--src/libsyntax_expand/placeholders.rs3
-rw-r--r--src/test/ui/ast-json/ast-json-output.stdout2
-rw-r--r--src/test/ui/issues/issue-28433.stderr9
-rw-r--r--src/test/ui/issues/issue-60075.rs2
-rw-r--r--src/test/ui/issues/issue-60075.stderr2
-rw-r--r--src/test/ui/parser/issue-32446.stderr4
-rw-r--r--src/test/ui/parser/issue-65041-empty-vis-matcher-in-enum.rs28
-rw-r--r--src/test/ui/parser/issue-65041-empty-vis-matcher-in-trait.rs28
-rw-r--r--src/test/ui/parser/macro/trait-non-item-macros.rs2
-rw-r--r--src/test/ui/parser/macro/trait-non-item-macros.stderr4
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs4
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr31
-rw-r--r--src/test/ui/parser/trait-pub-assoc-const.stderr5
-rw-r--r--src/test/ui/parser/trait-pub-assoc-ty.stderr5
-rw-r--r--src/test/ui/parser/trait-pub-method.stderr5
25 files changed, 184 insertions, 109 deletions
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 38eae008537..1b465f326c0 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -1187,26 +1187,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
-    pub(super) fn eat_bad_pub(&mut self) {
-        // When `unclosed_delims` is populated, it means that the code being parsed is already
-        // quite malformed, which might mean that, for example, a pub struct definition could be
-        // parsed as being a trait item, which is invalid and this error would trigger
-        // unconditionally, resulting in misleading diagnostics. Because of this, we only attempt
-        // this nice to have recovery for code that is otherwise well formed.
-        if self.token.is_keyword(kw::Pub) && self.unclosed_delims.is_empty() {
-            match self.parse_visibility(false) {
-                Ok(vis) => {
-                    self.diagnostic()
-                        .struct_span_err(vis.span, "unnecessary visibility qualifier")
-                        .span_label(vis.span, "`pub` not permitted here")
-                        .emit();
-                }
-                Err(mut err) => err.emit(),
-            }
-        }
-    }
-
     /// Eats tokens until we can be relatively sure we reached the end of the
     /// statement. This is something of a best-effort heuristic.
     ///
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 3e21436d313..f183b6c8fbc 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1,4 +1,4 @@
-use super::{Parser, PathStyle};
+use super::{Parser, PathStyle, FollowedByType};
 use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim};
 
 use crate::maybe_whole;
@@ -93,7 +93,7 @@ impl<'a> Parser<'a> {
 
         let lo = self.token.span;
 
-        let vis = self.parse_visibility(false)?;
+        let vis = self.parse_visibility(FollowedByType::No)?;
 
         if self.eat_keyword(kw::Use) {
             // USE ITEM
@@ -706,7 +706,7 @@ impl<'a> Parser<'a> {
         mut attrs: Vec<Attribute>,
     ) -> PResult<'a, ImplItem> {
         let lo = self.token.span;
-        let vis = self.parse_visibility(false)?;
+        let vis = self.parse_visibility(FollowedByType::No)?;
         let defaultness = self.parse_defaultness();
         let (name, kind, generics) = if let Some(type_) = self.eat_type() {
             let (name, alias, generics) = type_?;
@@ -896,7 +896,7 @@ impl<'a> Parser<'a> {
         mut attrs: Vec<Attribute>,
     ) -> PResult<'a, TraitItem> {
         let lo = self.token.span;
-        self.eat_bad_pub();
+        let vis = self.parse_visibility(FollowedByType::No)?;
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
             self.parse_trait_item_assoc_ty()?
         } else if self.is_const_item() {
@@ -912,6 +912,7 @@ impl<'a> Parser<'a> {
             id: DUMMY_NODE_ID,
             ident: name,
             attrs,
+            vis,
             generics,
             kind,
             span: lo.to(self.prev_span),
@@ -1142,7 +1143,7 @@ impl<'a> Parser<'a> {
 
         let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
-        let visibility = self.parse_visibility(false)?;
+        let visibility = self.parse_visibility(FollowedByType::No)?;
 
         // FOREIGN STATIC ITEM
         // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
@@ -1370,7 +1371,7 @@ impl<'a> Parser<'a> {
             let variant_attrs = self.parse_outer_attributes()?;
             let vlo = self.token.span;
 
-            self.eat_bad_pub();
+            let vis = self.parse_visibility(FollowedByType::No)?;
             let ident = self.parse_ident()?;
 
             let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
@@ -1397,6 +1398,7 @@ impl<'a> Parser<'a> {
 
             let vr = ast::Variant {
                 ident,
+                vis,
                 id: DUMMY_NODE_ID,
                 attrs: variant_attrs,
                 data: struct_def,
@@ -1550,7 +1552,7 @@ impl<'a> Parser<'a> {
         self.parse_paren_comma_seq(|p| {
             let attrs = p.parse_outer_attributes()?;
             let lo = p.token.span;
-            let vis = p.parse_visibility(true)?;
+            let vis = p.parse_visibility(FollowedByType::Yes)?;
             let ty = p.parse_ty()?;
             Ok(StructField {
                 span: lo.to(ty.span),
@@ -1568,7 +1570,7 @@ impl<'a> Parser<'a> {
     fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
         let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
-        let vis = self.parse_visibility(false)?;
+        let vis = self.parse_visibility(FollowedByType::No)?;
         self.parse_single_struct_field(lo, vis, attrs)
     }
 
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index a491d91e20f..29536146a9b 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -346,6 +346,8 @@ impl SeqSep {
     }
 }
 
+pub enum FollowedByType { Yes, No }
+
 impl<'a> Parser<'a> {
     pub fn new(
         sess: &'a ParseSess,
@@ -1116,7 +1118,7 @@ impl<'a> Parser<'a> {
     /// If the following element can't be a tuple (i.e., it's a function definition), then
     /// it's not a tuple struct field), and the contents within the parentheses isn't valid,
     /// so emit a proper diagnostic.
-    pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
+    pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
         maybe_whole!(self, NtVis, |x| x);
 
         self.expected_tokens.push(TokenType::Keyword(kw::Crate));
@@ -1171,7 +1173,9 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                 };
                 return Ok(respan(lo.to(self.prev_span), vis));
-            } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct.
+            } else if let FollowedByType::No = fbt {
+                // Provide this diagnostic if a type cannot follow;
+                // in particular, if this is not a tuple struct.
                 self.recover_incorrect_vis_restriction()?;
                 // Emit diagnostic, but continue with public visibility.
             }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index ec5572914d8..e43212a8f29 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -524,6 +524,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Enum(ref def, _) => {
                 for variant in &def.variants {
+                    self.invalid_visibility(&variant.vis, None);
                     for field in variant.data.fields() {
                         self.invalid_visibility(&field.vis, None);
                     }
@@ -754,6 +755,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         }
         visit::walk_impl_item(self, ii);
     }
+
+    fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+        self.invalid_visibility(&ti.vis, None);
+        visit::walk_trait_item(self, ti);
+    }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 170d089d4bb..550520790b5 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -961,12 +961,12 @@ pub struct Arm {
 /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Field {
+    pub attrs: ThinVec<Attribute>,
+    pub id: NodeId,
+    pub span: Span,
     pub ident: Ident,
     pub expr: P<Expr>,
-    pub span: Span,
     pub is_shorthand: bool,
-    pub attrs: ThinVec<Attribute>,
-    pub id: NodeId,
     pub is_placeholder: bool,
 }
 
@@ -1515,12 +1515,14 @@ pub struct FnSig {
 /// signature) or provided (meaning it has a default implementation).
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct TraitItem {
+    pub attrs: Vec<Attribute>,
     pub id: NodeId,
+    pub span: Span,
+    pub vis: Visibility,
     pub ident: Ident,
-    pub attrs: Vec<Attribute>,
+
     pub generics: Generics,
     pub kind: TraitItemKind,
-    pub span: Span,
     /// See `Item::tokens` for what this is.
     pub tokens: Option<TokenStream>,
 }
@@ -1536,14 +1538,15 @@ pub enum TraitItemKind {
 /// Represents anything within an `impl` block.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct ImplItem {
+    pub attrs: Vec<Attribute>,
     pub id: NodeId,
-    pub ident: Ident,
+    pub span: Span,
     pub vis: Visibility,
+    pub ident: Ident,
+
     pub defaultness: Defaultness,
-    pub attrs: Vec<Attribute>,
     pub generics: Generics,
     pub kind: ImplItemKind,
-    pub span: Span,
     /// See `Item::tokens` for what this is.
     pub tokens: Option<TokenStream>,
 }
@@ -2101,22 +2104,24 @@ pub struct GlobalAsm {
 pub struct EnumDef {
     pub variants: Vec<Variant>,
 }
-
 /// Enum variant.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Variant {
-    /// Name of the variant.
-    pub ident: Ident,
     /// Attributes of the variant.
     pub attrs: Vec<Attribute>,
     /// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
     pub id: NodeId,
+    /// Span
+    pub span: Span,
+    /// The visibility of the variant. Syntactically accepted but not semantically.
+    pub vis: Visibility,
+    /// Name of the variant.
+    pub ident: Ident,
+
     /// Fields and constructor id of the variant.
     pub data: VariantData,
     /// Explicit discriminant, e.g., `Foo = 1`.
     pub disr_expr: Option<AnonConst>,
-    /// Span
-    pub span: Span,
     /// Is a macro placeholder
     pub is_placeholder: bool,
 }
@@ -2295,12 +2300,13 @@ impl VisibilityKind {
 /// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct StructField {
+    pub attrs: Vec<Attribute>,
+    pub id: NodeId,
     pub span: Span,
-    pub ident: Option<Ident>,
     pub vis: Visibility,
-    pub id: NodeId,
+    pub ident: Option<Ident>,
+
     pub ty: P<Ty>,
-    pub attrs: Vec<Attribute>,
     pub is_placeholder: bool,
 }
 
@@ -2344,12 +2350,13 @@ impl VariantData {
 /// The name might be a dummy name in case of anonymous items.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Item {
-    pub ident: Ident,
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
-    pub kind: ItemKind,
-    pub vis: Visibility,
     pub span: Span,
+    pub vis: Visibility,
+    pub ident: Ident,
+
+    pub kind: ItemKind,
 
     /// Original tokens this item was parsed from. This isn't necessarily
     /// available for all items, although over time more and more items should
@@ -2518,12 +2525,13 @@ impl ItemKind {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct ForeignItem {
-    pub ident: Ident,
     pub attrs: Vec<Attribute>,
-    pub kind: ForeignItemKind,
     pub id: NodeId,
     pub span: Span,
     pub vis: Visibility,
+    pub ident: Ident,
+
+    pub kind: ForeignItemKind,
 }
 
 /// An item within an `extern` block.
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 376323a83ea..d79571ccf26 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -472,16 +472,17 @@ pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis:
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
-pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, vis: &mut T)
+pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, visitor: &mut T)
     -> SmallVec<[Variant; 1]>
 {
-    let Variant { ident, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
-    vis.visit_ident(ident);
-    visit_attrs(attrs, vis);
-    vis.visit_id(id);
-    vis.visit_variant_data(data);
-    visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr));
-    vis.visit_span(span);
+    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visit_attrs(attrs, visitor);
+    visitor.visit_id(id);
+    visitor.visit_variant_data(data);
+    visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
+    visitor.visit_span(span);
     smallvec![variant]
 }
 
@@ -920,32 +921,33 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
     }
 }
 
-pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, vis: &mut T)
+pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, visitor: &mut T)
     -> SmallVec<[TraitItem; 1]>
 {
-    let TraitItem { id, ident, attrs, generics, kind, span, tokens: _ } = &mut item;
-    vis.visit_id(id);
-    vis.visit_ident(ident);
-    visit_attrs(attrs, vis);
-    vis.visit_generics(generics);
+    let TraitItem { id, ident, vis, attrs, generics, kind, span, tokens: _ } = &mut item;
+    visitor.visit_id(id);
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visit_attrs(attrs, visitor);
+    visitor.visit_generics(generics);
     match kind {
         TraitItemKind::Const(ty, default) => {
-            vis.visit_ty(ty);
-            visit_opt(default, |default| vis.visit_expr(default));
+            visitor.visit_ty(ty);
+            visit_opt(default, |default| visitor.visit_expr(default));
         }
         TraitItemKind::Method(sig, body) => {
-            visit_fn_sig(sig, vis);
-            visit_opt(body, |body| vis.visit_block(body));
+            visit_fn_sig(sig, visitor);
+            visit_opt(body, |body| visitor.visit_block(body));
         }
         TraitItemKind::Type(bounds, default) => {
-            visit_bounds(bounds, vis);
-            visit_opt(default, |default| vis.visit_ty(default));
+            visit_bounds(bounds, visitor);
+            visit_opt(default, |default| visitor.visit_ty(default));
         }
         TraitItemKind::Macro(mac) => {
-            vis.visit_mac(mac);
+            visitor.visit_mac(mac);
         }
     }
-    vis.visit_span(span);
+    visitor.visit_span(span);
 
     smallvec![item]
 }
diff --git a/src/libsyntax/print/pprust/tests.rs b/src/libsyntax/print/pprust/tests.rs
index 2c6dd0fb1c6..d7725acb5d4 100644
--- a/src/libsyntax/print/pprust/tests.rs
+++ b/src/libsyntax/print/pprust/tests.rs
@@ -50,6 +50,7 @@ fn test_variant_to_string() {
 
         let var = ast::Variant {
             ident,
+            vis: source_map::respan(syntax_pos::DUMMY_SP, ast::VisibilityKind::Inherited),
             attrs: Vec::new(),
             id: ast::DUMMY_NODE_ID,
             data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index ea2dc357e6e..1fad6af0f5b 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -314,6 +314,7 @@ pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant)
     where V: Visitor<'a>,
 {
     visitor.visit_ident(variant.ident);
+    visitor.visit_vis(&variant.vis);
     visitor.visit_variant_data(&variant.data);
     walk_list!(visitor, visit_anon_const, &variant.disr_expr);
     walk_list!(visitor, visit_attribute, &variant.attrs);
@@ -585,6 +586,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
 }
 
 pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) {
+    visitor.visit_vis(&trait_item.vis);
     visitor.visit_ident(trait_item.ident);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
     visitor.visit_generics(&trait_item.generics);
diff --git a/src/libsyntax_expand/build.rs b/src/libsyntax_expand/build.rs
index 105ffe3ee8a..7fe37f377a8 100644
--- a/src/libsyntax_expand/build.rs
+++ b/src/libsyntax_expand/build.rs
@@ -582,12 +582,13 @@ impl<'a> ExtCtxt<'a> {
     }
 
     pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
+        let vis_span = span.shrink_to_lo();
         let fields: Vec<_> = tys.into_iter().map(|ty| {
             ast::StructField {
                 span: ty.span,
                 ty,
                 ident: None,
-                vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited),
+                vis: respan(vis_span, ast::VisibilityKind::Inherited),
                 attrs: Vec::new(),
                 id: ast::DUMMY_NODE_ID,
                 is_placeholder: false,
@@ -606,6 +607,7 @@ impl<'a> ExtCtxt<'a> {
             disr_expr: None,
             id: ast::DUMMY_NODE_ID,
             ident,
+            vis: respan(vis_span, ast::VisibilityKind::Inherited),
             span,
             is_placeholder: false,
         }
diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs
index 0dcb2c39fdc..bf7960f9066 100644
--- a/src/libsyntax_expand/mbe/macro_parser.rs
+++ b/src/libsyntax_expand/mbe/macro_parser.rs
@@ -77,7 +77,7 @@ use TokenTreeOrTokenTreeSlice::*;
 use crate::mbe::{self, TokenTree};
 
 use rustc_parse::Directory;
-use rustc_parse::parser::{Parser, PathStyle};
+use rustc_parse::parser::{Parser, PathStyle, FollowedByType};
 use syntax::ast::{Ident, Name};
 use syntax::print::pprust;
 use syntax::sess::ParseSess;
@@ -933,7 +933,7 @@ fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a,
         }
         sym::path => token::NtPath(p.parse_path(PathStyle::Type)?),
         sym::meta => token::NtMeta(p.parse_attr_item()?),
-        sym::vis => token::NtVis(p.parse_visibility(true)?),
+        sym::vis => token::NtVis(p.parse_visibility(FollowedByType::Yes)?),
         sym::lifetime => if p.check_lifetime() {
             token::NtLifetime(p.expect_lifetime().ident)
         } else {
diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index e595888dae7..36a09700076 100644
--- a/src/libsyntax_expand/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -53,7 +53,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
             tokens: None,
         })]),
         AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::TraitItem {
-            id, span, ident, attrs, generics,
+            id, span, ident, vis, attrs, generics,
             kind: ast::TraitItemKind::Macro(mac_placeholder()),
             tokens: None,
         }]),
@@ -150,6 +150,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
                 id,
                 ident,
                 span,
+                vis,
                 is_placeholder: true,
             }
         ])
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 64c9f693115..b299fc55841 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
+{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
diff --git a/src/test/ui/issues/issue-28433.stderr b/src/test/ui/issues/issue-28433.stderr
index 851bc5dfbdd..9f5f6333602 100644
--- a/src/test/ui/issues/issue-28433.stderr
+++ b/src/test/ui/issues/issue-28433.stderr
@@ -1,14 +1,15 @@
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
   --> $DIR/issue-28433.rs:2:5
    |
 LL |     pub Duck,
-   |     ^^^ `pub` not permitted here
+   |     ^^^ `pub` not permitted here because it's implied
 
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
   --> $DIR/issue-28433.rs:5:5
    |
 LL |     pub(crate) Dove
-   |     ^^^^^^^^^^ `pub` not permitted here
+   |     ^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0449`.
diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs
index 1f53a927932..7d3fc83786e 100644
--- a/src/test/ui/issues/issue-60075.rs
+++ b/src/test/ui/issues/issue-60075.rs
@@ -4,7 +4,7 @@ trait T {
     fn qux() -> Option<usize> {
         let _ = if true {
         });
-//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+//~^ ERROR expected one of `async`
 //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
 //~| ERROR expected identifier, found `;`
         Some(4)
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index 39e3ad7b6b4..e0b15130c33 100644
--- a/src/test/ui/issues/issue-60075.stderr
+++ b/src/test/ui/issues/issue-60075.stderr
@@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
 LL |         });
    |          ^ expected one of `.`, `;`, `?`, `else`, or an operator
 
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;`
   --> $DIR/issue-60075.rs:6:11
    |
 LL |     fn qux() -> Option<usize> {
diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr
index ab37dd7c39d..70256a59231 100644
--- a/src/test/ui/parser/issue-32446.stderr
+++ b/src/test/ui/parser/issue-32446.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `...`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...`
   --> $DIR/issue-32446.rs:4:11
    |
 LL | trait T { ... }
-   |           ^^^ expected one of 7 possible tokens
+   |           ^^^ expected one of 9 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-65041-empty-vis-matcher-in-enum.rs b/src/test/ui/parser/issue-65041-empty-vis-matcher-in-enum.rs
new file mode 100644
index 00000000000..ef89e31d842
--- /dev/null
+++ b/src/test/ui/parser/issue-65041-empty-vis-matcher-in-enum.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+// Here we check that a `:vis` macro matcher subsititued for the empty visibility
+// (`VisibilityKind::Inherited`) is accepted when used before an enum variant.
+
+fn main() {}
+
+macro_rules! mac_variant {
+    ($vis:vis MARKER) => {
+        enum Enum {
+            $vis Unit,
+
+            $vis Tuple(u8, u16),
+
+            $vis Struct { f: u8 },
+        }
+    }
+}
+
+mac_variant!(MARKER);
+
+// We also accept visibilities on variants syntactically but not semantically.
+#[cfg(FALSE)]
+enum E {
+    pub U,
+    pub(crate) T(u8),
+    pub(super) T { f: String }
+}
diff --git a/src/test/ui/parser/issue-65041-empty-vis-matcher-in-trait.rs b/src/test/ui/parser/issue-65041-empty-vis-matcher-in-trait.rs
new file mode 100644
index 00000000000..b08767b210b
--- /dev/null
+++ b/src/test/ui/parser/issue-65041-empty-vis-matcher-in-trait.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+// Here we check that a `:vis` macro matcher subsititued for the empty visibility
+// (`VisibilityKind::Inherited`) is accepted when used before an item in a trait.
+
+fn main() {}
+
+macro_rules! mac_in_trait {
+    ($vis:vis MARKER) => {
+        $vis fn beta() {}
+
+        $vis const GAMMA: u8;
+
+        $vis type Delta;
+    }
+}
+
+trait Alpha {
+    mac_in_trait!(MARKER);
+}
+
+// We also accept visibilities on items in traits syntactically but not semantically.
+#[cfg(FALSE)]
+trait Foo {
+    pub fn bar();
+    pub(crate) type baz;
+    pub(super) const QUUX: u8;
+}
diff --git a/src/test/ui/parser/macro/trait-non-item-macros.rs b/src/test/ui/parser/macro/trait-non-item-macros.rs
index 958c90b7c0a..5021886bf98 100644
--- a/src/test/ui/parser/macro/trait-non-item-macros.rs
+++ b/src/test/ui/parser/macro/trait-non-item-macros.rs
@@ -1,6 +1,6 @@
 macro_rules! bah {
     ($a:expr) => ($a)
-    //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
+    //~^ ERROR expected one of `async`
 }
 
 trait bar {
diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr
index dd97a3afa99..0a433ab278e 100644
--- a/src/test/ui/parser/macro/trait-non-item-macros.stderr
+++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2`
   --> $DIR/trait-non-item-macros.rs:2:19
    |
 LL |     ($a:expr) => ($a)
-   |                   ^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+   |                   ^^ expected one of 8 possible tokens
 ...
 LL |     bah!(2);
    |     -------- in this macro invocation
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
index 79547195411..9f3d78d584d 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
@@ -1,7 +1,9 @@
 trait T {
+//~^ ERROR `main` function not found in crate `missing_close_brace_in_trait`
     fn foo(&self);
 
-pub(crate) struct Bar<T>(); //~ ERROR expected one of
+pub(crate) struct Bar<T>();
+//~^ ERROR expected one of
 
 impl T for Bar<usize> {
 fn foo(&self) {}
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
index 1bd8e445fad..cbaf9315e85 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
@@ -1,5 +1,5 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/missing-close-brace-in-trait.rs:10:66
+  --> $DIR/missing-close-brace-in-trait.rs:12:66
    |
 LL | trait T {
    |         - un-closed delimiter
@@ -7,19 +7,24 @@ LL | trait T {
 LL | fn main() {}
    |                                                                  ^
 
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found keyword `pub`
-  --> $DIR/missing-close-brace-in-trait.rs:4:1
+error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
+  --> $DIR/missing-close-brace-in-trait.rs:5:12
    |
-LL | trait T {
-   |         - unclosed delimiter
-LL |     fn foo(&self);
-   |                   -
-   |                   |
-   |                   expected one of 7 possible tokens
-   |                   help: `}` may belong here
-LL | 
 LL | pub(crate) struct Bar<T>();
-   | ^^^ unexpected token
+   |            ^^^^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+
+error[E0601]: `main` function not found in crate `missing_close_brace_in_trait`
+  --> $DIR/missing-close-brace-in-trait.rs:1:1
+   |
+LL | / trait T {
+LL | |
+LL | |     fn foo(&self);
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |_________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-trait.rs`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/parser/trait-pub-assoc-const.stderr b/src/test/ui/parser/trait-pub-assoc-const.stderr
index 817692cc82c..efd09a0364e 100644
--- a/src/test/ui/parser/trait-pub-assoc-const.stderr
+++ b/src/test/ui/parser/trait-pub-assoc-const.stderr
@@ -1,8 +1,9 @@
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
   --> $DIR/trait-pub-assoc-const.rs:2:5
    |
 LL |     pub const Foo: u32;
-   |     ^^^ `pub` not permitted here
+   |     ^^^ `pub` not permitted here because it's implied
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0449`.
diff --git a/src/test/ui/parser/trait-pub-assoc-ty.stderr b/src/test/ui/parser/trait-pub-assoc-ty.stderr
index 400be6af22a..e76373f5c5f 100644
--- a/src/test/ui/parser/trait-pub-assoc-ty.stderr
+++ b/src/test/ui/parser/trait-pub-assoc-ty.stderr
@@ -1,8 +1,9 @@
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
   --> $DIR/trait-pub-assoc-ty.rs:2:5
    |
 LL |     pub type Foo;
-   |     ^^^ `pub` not permitted here
+   |     ^^^ `pub` not permitted here because it's implied
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0449`.
diff --git a/src/test/ui/parser/trait-pub-method.stderr b/src/test/ui/parser/trait-pub-method.stderr
index b3617a4aa9b..0e3fe027cb5 100644
--- a/src/test/ui/parser/trait-pub-method.stderr
+++ b/src/test/ui/parser/trait-pub-method.stderr
@@ -1,8 +1,9 @@
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
   --> $DIR/trait-pub-method.rs:2:5
    |
 LL |     pub fn foo();
-   |     ^^^ `pub` not permitted here
+   |     ^^^ `pub` not permitted here because it's implied
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0449`.