about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-05-21 17:47:23 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-05-24 11:49:33 -0700
commit24160171e48a277ef71e84e14fbffffe3c81438a (patch)
treee4d594acb224da13101b0146d9e785910021f412
parentfc45382c125d940822368e866588568d78551946 (diff)
downloadrust-24160171e48a277ef71e84e14fbffffe3c81438a.tar.gz
rust-24160171e48a277ef71e84e14fbffffe3c81438a.zip
Tweak macro parse errors when reaching EOF during macro call parse
- Add detail on origin of current parser when reaching EOF and stop
  saying "found <eof>" and point at the end of macro calls
- Handle empty `cfg_attr` attribute
- Reword empty `derive` attribute error
-rw-r--r--src/libfmt_macros/lib.rs4
-rw-r--r--src/librustc/traits/on_unimplemented.rs24
-rw-r--r--src/libsyntax/attr/mod.rs9
-rw-r--r--src/libsyntax/config.rs13
-rw-r--r--src/libsyntax/ext/base.rs6
-rw-r--r--src/libsyntax/ext/derive.rs7
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs9
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs2
-rw-r--r--src/libsyntax/parse/mod.rs12
-rw-r--r--src/libsyntax/parse/parser.rs91
-rw-r--r--src/libsyntax_ext/asm.rs6
-rw-r--r--src/libsyntax_ext/deriving/custom.rs2
-rw-r--r--src/test/ui/macros/format-parse-errors.stderr12
-rw-r--r--src/test/ui/malformed/malformed-derive-entry.rs12
-rw-r--r--src/test/ui/malformed/malformed-derive-entry.stderr12
-rw-r--r--src/test/ui/malformed/malformed-special-attrs.rs6
-rw-r--r--src/test/ui/malformed/malformed-special-attrs.stderr26
-rw-r--r--src/test/ui/parser/bad-macro-argument.rs4
-rw-r--r--src/test/ui/parser/bad-macro-argument.stderr8
-rw-r--r--src/test/ui/proc-macro/attr-invalid-exprs.rs2
-rw-r--r--src/test/ui/proc-macro/attr-invalid-exprs.stderr2
21 files changed, 176 insertions, 93 deletions
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 6fed8302160..c84d15b3adb 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -627,7 +627,7 @@ mod tests {
     use super::*;
 
     fn same(fmt: &'static str, p: &[Piece<'static>]) {
-        let parser = Parser::new(fmt, None, vec![], false);
+        let parser = Parser::new(fmt, None, vec![], false, None);
         assert!(parser.collect::<Vec<Piece<'static>>>() == p);
     }
 
@@ -643,7 +643,7 @@ mod tests {
     }
 
     fn musterr(s: &str) {
-        let mut p = Parser::new(s, None, vec![], false);
+        let mut p = Parser::new(s, None, vec![], false, None);
         p.next();
         assert!(!p.errors.is_empty());
     }
diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs
index f9ceeb5bfc0..1c17ace90c2 100644
--- a/src/librustc/traits/on_unimplemented.rs
+++ b/src/librustc/traits/on_unimplemented.rs
@@ -226,12 +226,12 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
         Ok(result)
     }
 
-    fn verify(&self,
-              tcx: TyCtxt<'a, 'gcx, 'tcx>,
-              trait_def_id: DefId,
-              span: Span)
-              -> Result<(), ErrorReported>
-    {
+    fn verify(
+        &self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        trait_def_id: DefId,
+        span: Span,
+    ) -> Result<(), ErrorReported> {
         let name = tcx.item_name(trait_def_id);
         let generics = tcx.generics_of(trait_def_id);
         let parser = Parser::new(&self.0, None, vec![], false);
@@ -272,12 +272,12 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
         result
     }
 
-    pub fn format(&self,
-                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                  trait_ref: ty::TraitRef<'tcx>,
-                  options: &FxHashMap<String, String>)
-                  -> String
-    {
+    pub fn format(
+        &self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        trait_ref: ty::TraitRef<'tcx>,
+        options: &FxHashMap<String, String>,
+    ) -> String {
         let name = tcx.item_name(trait_ref.def_id);
         let trait_str = tcx.def_path_str(trait_ref.def_id);
         let generics = tcx.generics_of(trait_ref.def_id);
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 2f75a8c9db5..48948e4d0d7 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -278,7 +278,14 @@ impl Attribute {
     pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     {
-        let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
+        let mut parser = Parser::new(
+            sess,
+            self.tokens.clone(),
+            None,
+            false,
+            false,
+            Some("attribute"),
+        );
         let result = f(&mut parser)?;
         if parser.token != token::Eof {
             parser.unexpected()?;
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index c82936afa3d..ca047dc66cb 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -94,6 +94,17 @@ impl<'a> StripUnconfigured<'a> {
         if !attr.check_name(sym::cfg_attr) {
             return vec![attr];
         }
+        if attr.tokens.len() == 0 {
+            self.sess.span_diagnostic.struct_span_err(attr.span, "bad `cfg_attr` attribute")
+                .span_label(attr.span, "missing condition and attribute")
+                .note("`cfg_attr` must be of the form: \
+                       `#[cfg_attr(condition, attribute)]`")
+                .note("for more information, visit \
+                       <https://doc.rust-lang.org/reference/conditional-compilation.html\
+                       #the-cfg_attr-attribute>")
+                .emit();
+            return vec![];
+        }
 
         let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
             parser.expect(&token::OpenDelim(token::Paren))?;
@@ -117,7 +128,7 @@ impl<'a> StripUnconfigured<'a> {
             Ok(result) => result,
             Err(mut e) => {
                 e.emit();
-                return Vec::new();
+                return vec![];
             }
         };
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index f1a20d54065..ef7317e0038 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -850,7 +850,11 @@ impl<'a> ExtCtxt<'a> {
     }
 
     pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> {
-        parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect())
+        parse::stream_to_parser(
+            self.parse_sess,
+            tts.iter().cloned().collect(),
+            Some("macro arguments"),
+        )
     }
     pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() }
     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 6e789c4c708..bbdda4932f1 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -17,8 +17,11 @@ pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) ->
             return true;
         }
         if !attr.is_meta_item_list() {
-            cx.span_err(attr.span,
-                        "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`");
+            cx.struct_span_err(attr.span, "bad `derive` attribute")
+                .span_label(attr.span, "missing traits to be derived")
+                .note("`derive` must be of the form: \
+                       `#[derive(Trait1, Trait2, ...)]`")
+                .emit();
             return false;
         }
 
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index fa1f85c0e7b..02e986c9e75 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -658,7 +658,14 @@ pub fn parse(
     recurse_into_modules: bool,
 ) -> NamedParseResult {
     // Create a parser that can be used for the "black box" parts.
-    let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true);
+    let mut parser = Parser::new(
+        sess,
+        tts,
+        directory,
+        recurse_into_modules,
+        true,
+        Some("macro arguments"),
+    );
 
     // A queue of possible matcher positions. We initialize it with the matcher position in which
     // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 37c49112dca..2debd8f048b 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -172,7 +172,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
                     path: Cow::from(cx.current_expansion.module.directory.as_path()),
                     ownership: cx.current_expansion.directory_ownership,
                 };
-                let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false);
+                let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None);
                 p.root_module_name = cx.current_expansion.module.mod_path.last()
                     .map(|id| id.as_str().to_string());
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1073fc6f3ab..ece6137e881 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -236,7 +236,7 @@ fn maybe_source_file_to_parser(
 ) -> Result<Parser<'_>, Vec<Diagnostic>> {
     let end_pos = source_file.end_pos;
     let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?;
-    let mut parser = stream_to_parser(sess, stream);
+    let mut parser = stream_to_parser(sess, stream, None);
     parser.unclosed_delims = unclosed_delims;
     if parser.token == token::Eof && parser.span.is_dummy() {
         parser.span = Span::new(end_pos, end_pos, parser.span.ctxt());
@@ -248,7 +248,7 @@ fn maybe_source_file_to_parser(
 // must preserve old name for now, because quote! from the *existing*
 // compiler expands into it
 pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> {
-    stream_to_parser(sess, tts.into_iter().collect())
+    stream_to_parser(sess, tts.into_iter().collect(), Some("macro arguments"))
 }
 
 
@@ -328,8 +328,12 @@ pub fn maybe_file_to_stream(
 }
 
 /// Given stream and the `ParseSess`, produces a parser.
-pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> {
-    Parser::new(sess, stream, None, true, false)
+pub fn stream_to_parser<'a>(
+    sess: &'a ParseSess,
+    stream: TokenStream,
+    is_subparser: Option<&'static str>,
+) -> Parser<'a> {
+    Parser::new(sess, stream, None, true, false, is_subparser)
 }
 
 /// Given stream, the `ParseSess` and the base directory, produces a parser.
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 11c566b65e5..38aa5091f98 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -51,7 +51,7 @@ use crate::symbol::{kw, sym, Symbol};
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
 use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{
-    Span, MultiSpan, BytePos, FileName,
+    BytePos, DUMMY_SP, FileName, MultiSpan, Span,
     hygiene::CompilerDesugaringKind,
 };
 use log::{debug, trace};
@@ -233,6 +233,8 @@ pub struct Parser<'a> {
     /// error.
     crate unclosed_delims: Vec<UnmatchedBrace>,
     last_unexpected_token_span: Option<Span>,
+    /// If `true`, this `Parser` is not parsing Rust code but rather a macro call.
+    is_subparser: Option<&'static str>,
 }
 
 impl<'a> Drop for Parser<'a> {
@@ -309,7 +311,7 @@ impl TokenCursor {
                 self.frame = frame;
                 continue
             } else {
-                return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP }
+                return TokenAndSpan { tok: token::Eof, sp: DUMMY_SP }
             };
 
             match self.frame.last_token {
@@ -533,17 +535,19 @@ enum TokenExpectType {
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(sess: &'a ParseSess,
-               tokens: TokenStream,
-               directory: Option<Directory<'a>>,
-               recurse_into_file_modules: bool,
-               desugar_doc_comments: bool)
-               -> Self {
+    pub fn new(
+        sess: &'a ParseSess,
+        tokens: TokenStream,
+        directory: Option<Directory<'a>>,
+        recurse_into_file_modules: bool,
+        desugar_doc_comments: bool,
+        is_subparser: Option<&'static str>,
+    ) -> Self {
         let mut parser = Parser {
             sess,
             token: token::Whitespace,
-            span: syntax_pos::DUMMY_SP,
-            prev_span: syntax_pos::DUMMY_SP,
+            span: DUMMY_SP,
+            prev_span: DUMMY_SP,
             meta_var_span: None,
             prev_token_kind: PrevTokenKind::Other,
             restrictions: Restrictions::empty(),
@@ -568,6 +572,7 @@ impl<'a> Parser<'a> {
             max_angle_bracket_count: 0,
             unclosed_delims: Vec::new(),
             last_unexpected_token_span: None,
+            is_subparser,
         };
 
         let tok = parser.next_tok();
@@ -639,16 +644,28 @@ impl<'a> Parser<'a> {
             } else {
                 let token_str = pprust::token_to_string(t);
                 let this_token_str = self.this_token_descr();
-                let mut err = self.fatal(&format!("expected `{}`, found {}",
-                                                  token_str,
-                                                  this_token_str));
-
-                let sp = if self.token == token::Token::Eof {
-                    // EOF, don't want to point at the following char, but rather the last token
-                    self.prev_span
-                } else {
-                    self.sess.source_map().next_point(self.prev_span)
+                let (prev_sp, sp) = match (&self.token, self.is_subparser) {
+                    // Point at the end of the macro call when reaching end of macro arguments.
+                    (token::Token::Eof, Some(_)) => {
+                        let sp = self.sess.source_map().next_point(self.span);
+                        (sp, sp)
+                    }
+                    // We don't want to point at the following span after DUMMY_SP.
+                    // This happens when the parser finds an empty TokenStream.
+                    _ if self.prev_span == DUMMY_SP => (self.span, self.span),
+                    // EOF, don't want to point at the following char, but rather the last token.
+                    (token::Token::Eof, None) => (self.prev_span, self.span),
+                    _ => (self.sess.source_map().next_point(self.prev_span), self.span),
                 };
+                let msg = format!(
+                    "expected `{}`, found {}",
+                    token_str,
+                    match (&self.token, self.is_subparser) {
+                        (token::Token::Eof, Some(origin)) => format!("end of {}", origin),
+                        _ => this_token_str,
+                    },
+                );
+                let mut err = self.struct_span_err(sp, &msg);
                 let label_exp = format!("expected `{}`", token_str);
                 match self.recover_closing_delimiter(&[t.clone()], err) {
                     Err(e) => err = e,
@@ -657,15 +674,15 @@ impl<'a> Parser<'a> {
                     }
                 }
                 let cm = self.sess.source_map();
-                match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
+                match (cm.lookup_line(prev_sp.lo()), cm.lookup_line(sp.lo())) {
                     (Ok(ref a), Ok(ref b)) if a.line == b.line => {
                         // When the spans are in the same line, it means that the only content
                         // between them is whitespace, point only at the found token.
-                        err.span_label(self.span, label_exp);
+                        err.span_label(sp, label_exp);
                     }
                     _ => {
-                        err.span_label(sp, label_exp);
-                        err.span_label(self.span, "unexpected token");
+                        err.span_label(prev_sp, label_exp);
+                        err.span_label(sp, "unexpected token");
                     }
                 }
                 Err(err)
@@ -812,7 +829,7 @@ impl<'a> Parser<'a> {
                     //   |                   expected one of 8 possible tokens here
                     err.span_label(self.span, label_exp);
                 }
-                _ if self.prev_span == syntax_pos::DUMMY_SP => {
+                _ if self.prev_span == DUMMY_SP => {
                     // Account for macro context where the previous span might not be
                     // available to avoid incorrect output (#54841).
                     err.span_label(self.span, "unexpected token");
@@ -2041,7 +2058,7 @@ impl<'a> Parser<'a> {
             path = self.parse_path(PathStyle::Type)?;
             path_span = path_lo.to(self.prev_span);
         } else {
-            path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
+            path = ast::Path { segments: Vec::new(), span: DUMMY_SP };
             path_span = self.span.to(self.span);
         }
 
@@ -2627,16 +2644,24 @@ impl<'a> Parser<'a> {
                         }
                         Err(mut err) => {
                             self.cancel(&mut err);
-                            let msg = format!("expected expression, found {}",
-                                              self.this_token_descr());
-                            let mut err = self.fatal(&msg);
+                            let (span, msg) = match (&self.token, self.is_subparser) {
+                                (&token::Token::Eof, Some(origin)) => {
+                                    let sp = self.sess.source_map().next_point(self.span);
+                                    (sp, format!( "expected expression, found end of {}", origin))
+                                }
+                                _ => (self.span, format!(
+                                    "expected expression, found {}",
+                                    self.this_token_descr(),
+                                )),
+                            };
+                            let mut err = self.struct_span_err(span, &msg);
                             let sp = self.sess.source_map().start_point(self.span);
                             if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow()
                                 .get(&sp)
                             {
                                 self.sess.expr_parentheses_needed(&mut err, *sp, None);
                             }
-                            err.span_label(self.span, "expected expression");
+                            err.span_label(span, "expected expression");
                             return Err(err);
                         }
                     }
@@ -5592,7 +5617,7 @@ impl<'a> Parser<'a> {
                 where_clause: WhereClause {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
-                    span: syntax_pos::DUMMY_SP,
+                    span: DUMMY_SP,
                 },
                 span: span_lo.to(self.prev_span),
             })
@@ -5838,7 +5863,7 @@ impl<'a> Parser<'a> {
         let mut where_clause = WhereClause {
             id: ast::DUMMY_NODE_ID,
             predicates: Vec::new(),
-            span: syntax_pos::DUMMY_SP,
+            span: DUMMY_SP,
         };
 
         if !self.eat_keyword(kw::Where) {
@@ -7005,7 +7030,7 @@ impl<'a> Parser<'a> {
                             Ident::with_empty_ctxt(sym::warn_directory_ownership)),
                         tokens: TokenStream::empty(),
                         is_sugared_doc: false,
-                        span: syntax_pos::DUMMY_SP,
+                        span: DUMMY_SP,
                     };
                     attr::mark_known(&attr);
                     attrs.push(attr);
@@ -7013,7 +7038,7 @@ impl<'a> Parser<'a> {
                 Ok((id, ItemKind::Mod(module), Some(attrs)))
             } else {
                 let placeholder = ast::Mod {
-                    inner: syntax_pos::DUMMY_SP,
+                    inner: DUMMY_SP,
                     items: Vec::new(),
                     inline: false
                 };
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index b8e89c3ecf8..704665e0a84 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -138,7 +138,11 @@ fn parse_inline_asm<'a>(
                 if p2.token != token::Eof {
                     let mut extra_tts = p2.parse_all_token_trees()?;
                     extra_tts.extend(tts[first_colon..].iter().cloned());
-                    p = parse::stream_to_parser(cx.parse_sess, extra_tts.into_iter().collect());
+                    p = parse::stream_to_parser(
+                        cx.parse_sess,
+                        extra_tts.into_iter().collect(),
+                        Some("inline assembly"),
+                    );
                 }
 
                 asm = s;
diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs
index e73110717e9..975d96951dc 100644
--- a/src/libsyntax_ext/deriving/custom.rs
+++ b/src/libsyntax_ext/deriving/custom.rs
@@ -89,7 +89,7 @@ impl MultiItemModifier for ProcMacroDerive {
         let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
         let msg = "proc-macro derive produced unparseable tokens";
 
-        let mut parser = parse::stream_to_parser(ecx.parse_sess, stream);
+        let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
         let mut items = vec![];
 
         loop {
diff --git a/src/test/ui/macros/format-parse-errors.stderr b/src/test/ui/macros/format-parse-errors.stderr
index b634cf2d994..fd4f9309194 100644
--- a/src/test/ui/macros/format-parse-errors.stderr
+++ b/src/test/ui/macros/format-parse-errors.stderr
@@ -12,17 +12,17 @@ error: expected expression, found keyword `struct`
 LL |     format!(struct);
    |             ^^^^^^ expected expression
 
-error: expected expression, found `<eof>`
-  --> $DIR/format-parse-errors.rs:4:23
+error: expected expression, found end of macro arguments
+  --> $DIR/format-parse-errors.rs:4:24
    |
 LL |     format!("s", name =);
-   |                       ^ expected expression
+   |                        ^ expected expression
 
-error: expected `=`, found `<eof>`
-  --> $DIR/format-parse-errors.rs:5:29
+error: expected `=`, found end of macro arguments
+  --> $DIR/format-parse-errors.rs:5:32
    |
 LL |     format!("s", foo = foo, bar);
-   |                             ^^^ expected `=`
+   |                                ^ expected `=`
 
 error: expected expression, found keyword `struct`
   --> $DIR/format-parse-errors.rs:6:24
diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs
index 74d22102c66..1a87cd2d11c 100644
--- a/src/test/ui/malformed/malformed-derive-entry.rs
+++ b/src/test/ui/malformed/malformed-derive-entry.rs
@@ -1,17 +1,13 @@
-#[derive(Copy(Bad))]
-//~^ ERROR expected one of `)`, `,`, or `::`, found `(`
+#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(`
 struct Test1;
 
-#[derive(Copy="bad")]
-//~^ ERROR expected one of `)`, `,`, or `::`, found `=`
+#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=`
 struct Test2;
 
-#[derive()]
-//~^ WARNING empty trait list
+#[derive()] //~ WARNING empty trait list
 struct Test3;
 
-#[derive]
-//~^ ERROR attribute must be of the form
+#[derive] //~ ERROR bad `derive` attribute
 struct Test4;
 
 fn main() {}
diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr
index f546f74220a..aa1334d21a8 100644
--- a/src/test/ui/malformed/malformed-derive-entry.stderr
+++ b/src/test/ui/malformed/malformed-derive-entry.stderr
@@ -5,22 +5,24 @@ LL | #[derive(Copy(Bad))]
    |              ^ expected one of `)`, `,`, or `::` here
 
 error: expected one of `)`, `,`, or `::`, found `=`
-  --> $DIR/malformed-derive-entry.rs:5:14
+  --> $DIR/malformed-derive-entry.rs:4:14
    |
 LL | #[derive(Copy="bad")]
    |              ^ expected one of `)`, `,`, or `::` here
 
 warning: empty trait list in `derive`
-  --> $DIR/malformed-derive-entry.rs:9:1
+  --> $DIR/malformed-derive-entry.rs:7:1
    |
 LL | #[derive()]
    | ^^^^^^^^^^^
 
-error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
-  --> $DIR/malformed-derive-entry.rs:13:1
+error: bad `derive` attribute
+  --> $DIR/malformed-derive-entry.rs:10:1
    |
 LL | #[derive]
-   | ^^^^^^^^^
+   | ^^^^^^^^^ missing traits to be derived
+   |
+   = note: `derive` must be of the form: `#[derive(Trait1, Trait2, ...)]`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/malformed/malformed-special-attrs.rs b/src/test/ui/malformed/malformed-special-attrs.rs
index f91c6bedb2b..5f1c4795a89 100644
--- a/src/test/ui/malformed/malformed-special-attrs.rs
+++ b/src/test/ui/malformed/malformed-special-attrs.rs
@@ -1,13 +1,13 @@
-#[cfg_attr] //~ ERROR expected `(`, found `<eof>`
+#[cfg_attr] //~ ERROR bad `cfg_attr` attribute
 struct S1;
 
 #[cfg_attr = ""] //~ ERROR expected `(`, found `=`
 struct S2;
 
-#[derive] //~ ERROR attribute must be of the form
+#[derive] //~ ERROR bad `derive` attribute
 struct S3;
 
-#[derive = ""] //~ ERROR attribute must be of the form
+#[derive = ""] //~ ERROR bad `derive` attribute
 struct S4;
 
 fn main() {}
diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr
index 8c23424087c..483ecf73387 100644
--- a/src/test/ui/malformed/malformed-special-attrs.stderr
+++ b/src/test/ui/malformed/malformed-special-attrs.stderr
@@ -1,25 +1,33 @@
-error: expected `(`, found `<eof>`
+error: bad `cfg_attr` attribute
+  --> $DIR/malformed-special-attrs.rs:1:1
+   |
+LL | #[cfg_attr]
+   | ^^^^^^^^^^^ missing condition and attribute
+   |
+   = note: `cfg_attr` must be of the form: `#[cfg_attr(condition, attribute)]`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: expected `(`, found `=`
   --> $DIR/malformed-special-attrs.rs:4:12
    |
-LL | #[cfg_attr]
-   | - expected `(`
-...
 LL | #[cfg_attr = ""]
-   |            ^ unexpected token
+   |            ^ expected `(`
 
-error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
+error: bad `derive` attribute
   --> $DIR/malformed-special-attrs.rs:7:1
    |
 LL | #[derive]
-   | ^^^^^^^^^
+   | ^^^^^^^^^ missing traits to be derived
+   |
+   = note: `derive` must be of the form: `#[derive(Trait1, Trait2, ...)]`
 
-error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
+error: bad `derive` attribute
   --> $DIR/malformed-special-attrs.rs:10:1
    |
 LL | #[derive = ""]
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ missing traits to be derived
+   |
+   = note: `derive` must be of the form: `#[derive(Trait1, Trait2, ...)]`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/parser/bad-macro-argument.rs b/src/test/ui/parser/bad-macro-argument.rs
new file mode 100644
index 00000000000..4b6d2389065
--- /dev/null
+++ b/src/test/ui/parser/bad-macro-argument.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let message = "world";
+    println!("Hello, {}", message/); //~ ERROR expected expression
+}
diff --git a/src/test/ui/parser/bad-macro-argument.stderr b/src/test/ui/parser/bad-macro-argument.stderr
new file mode 100644
index 00000000000..3cd8accb662
--- /dev/null
+++ b/src/test/ui/parser/bad-macro-argument.stderr
@@ -0,0 +1,8 @@
+error: expected expression, found end of macro arguments
+  --> $DIR/bad-macro-argument.rs:3:35
+   |
+LL |     println!("Hello, {}", message/);
+   |                                   ^ expected expression
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/proc-macro/attr-invalid-exprs.rs b/src/test/ui/proc-macro/attr-invalid-exprs.rs
index c609cae9024..fab98f0ce5e 100644
--- a/src/test/ui/proc-macro/attr-invalid-exprs.rs
+++ b/src/test/ui/proc-macro/attr-invalid-exprs.rs
@@ -9,7 +9,7 @@ use attr_stmt_expr::{duplicate, no_output};
 
 fn main() {
     let _ = #[no_output] "Hello, world!";
-    //~^ ERROR expected expression, found `<eof>`
+    //~^ ERROR expected expression, found end of macro arguments
 
     let _ = #[duplicate] "Hello, world!";
     //~^ ERROR macro expansion ignores token `,` and any following
diff --git a/src/test/ui/proc-macro/attr-invalid-exprs.stderr b/src/test/ui/proc-macro/attr-invalid-exprs.stderr
index 5d2fb59ff1f..49fe0bd0fcf 100644
--- a/src/test/ui/proc-macro/attr-invalid-exprs.stderr
+++ b/src/test/ui/proc-macro/attr-invalid-exprs.stderr
@@ -1,4 +1,4 @@
-error: expected expression, found `<eof>`
+error: expected expression, found end of macro arguments
   --> $DIR/attr-invalid-exprs.rs:11:13
    |
 LL |     let _ = #[no_output] "Hello, world!";