From 24160171e48a277ef71e84e14fbffffe3c81438a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 May 2019 17:47:23 -0700 Subject: [PATCH 1/5] 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 " and point at the end of macro calls - Handle empty `cfg_attr` attribute - Reword empty `derive` attribute error --- src/libfmt_macros/lib.rs | 4 +- src/librustc/traits/on_unimplemented.rs | 24 ++--- src/libsyntax/attr/mod.rs | 9 +- src/libsyntax/config.rs | 13 ++- src/libsyntax/ext/base.rs | 6 +- src/libsyntax/ext/derive.rs | 7 +- src/libsyntax/ext/tt/macro_parser.rs | 9 +- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/parse/mod.rs | 12 ++- src/libsyntax/parse/parser.rs | 91 ++++++++++++------- src/libsyntax_ext/asm.rs | 6 +- src/libsyntax_ext/deriving/custom.rs | 2 +- src/test/ui/macros/format-parse-errors.stderr | 12 +-- .../ui/malformed/malformed-derive-entry.rs | 12 +-- .../malformed/malformed-derive-entry.stderr | 12 ++- .../ui/malformed/malformed-special-attrs.rs | 6 +- .../malformed/malformed-special-attrs.stderr | 26 ++++-- src/test/ui/parser/bad-macro-argument.rs | 4 + src/test/ui/parser/bad-macro-argument.stderr | 8 ++ src/test/ui/proc-macro/attr-invalid-exprs.rs | 2 +- .../ui/proc-macro/attr-invalid-exprs.stderr | 2 +- 21 files changed, 176 insertions(+), 93 deletions(-) create mode 100644 src/test/ui/parser/bad-macro-argument.rs create mode 100644 src/test/ui/parser/bad-macro-argument.stderr diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 6fed83021609d..c84d15b3adb8c 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::>>() == 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 f9ceeb5bfc01b..1c17ace90c2fb 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 - { + pub fn format( + &self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_ref: ty::TraitRef<'tcx>, + options: &FxHashMap, + ) -> 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 2f75a8c9db57e..48948e4d0d79c 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 c82936afa3d9f..ca047dc66cb16 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 \ + ") + .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 f1a20d5406574..ef7317e00389a 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 6e789c4c7086b..bbdda4932f117 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) -> 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 fa1f85c0e7b57..02e986c9e75b6 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 37c49112dcaac..2debd8f048bc3 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 1073fc6f3ab4d..ece6137e881b8 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -236,7 +236,7 @@ fn maybe_source_file_to_parser( ) -> Result, Vec> { 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) -> 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 11c566b65e50a..38aa5091f9898 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, last_unexpected_token_span: Option, + /// 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>, - recurse_into_file_modules: bool, - desugar_doc_comments: bool) - -> Self { + pub fn new( + sess: &'a ParseSess, + tokens: TokenStream, + directory: Option>, + 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 b8e89c3ecf876..704665e0a84d6 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 e73110717e979..975d96951dc55 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 b634cf2d9944c..fd4f93091944c 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 `` - --> $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 `` - --> $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 74d22102c664d..1a87cd2d11cb5 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 f546f74220a1c..aa1334d21a86a 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 f91c6bedb2b21..5f1c4795a89b0 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 `` +#[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 8c23424087c04..483ecf7338734 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 `` +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 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 0000000000000..4b6d23890653d --- /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 0000000000000..3cd8accb66294 --- /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 c609cae90240c..fab98f0ce5ebe 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 `` + //~^ 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 5d2fb59ff1f66..49fe0bd0fcfe2 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 `` +error: expected expression, found end of macro arguments --> $DIR/attr-invalid-exprs.rs:11:13 | LL | let _ = #[no_output] "Hello, world!"; From 5c5fa775e568bc42f876aa7efcb386b404906df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 May 2019 22:17:53 -0700 Subject: [PATCH 2/5] review comments --- src/libfmt_macros/lib.rs | 4 +- src/libsyntax/config.rs | 2 +- src/libsyntax/ext/base.rs | 8 +-- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/lib.rs | 2 + src/libsyntax/parse/diagnostics.rs | 56 +++++++++++++++++- src/libsyntax/parse/mod.rs | 6 +- src/libsyntax/parse/parser.rs | 57 +++---------------- .../malformed/malformed-special-attrs.stderr | 2 +- .../parser/{ => macro}/bad-macro-argument.rs | 0 .../{ => macro}/bad-macro-argument.stderr | 0 11 files changed, 73 insertions(+), 66 deletions(-) rename src/test/ui/parser/{ => macro}/bad-macro-argument.rs (100%) rename src/test/ui/parser/{ => macro}/bad-macro-argument.stderr (100%) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index c84d15b3adb8c..6fed83021609d 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, None); + let parser = Parser::new(fmt, None, vec![], false); assert!(parser.collect::>>() == p); } @@ -643,7 +643,7 @@ mod tests { } fn musterr(s: &str) { - let mut p = Parser::new(s, None, vec![], false, None); + let mut p = Parser::new(s, None, vec![], false); p.next(); assert!(!p.errors.is_empty()); } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ca047dc66cb16..5ccec05dda20b 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -98,7 +98,7 @@ impl<'a> StripUnconfigured<'a> { 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)]`") + `#[cfg_attr(condition, attribute, other_attribute, ...)]`") .note("for more information, visit \ ") diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ef7317e00389a..dbec379e76995 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -11,7 +11,7 @@ use crate::parse::{self, parser, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; -use crate::ThinVec; +use crate::{ThinVec, MACRO_ARGUMENTS}; use crate::tokenstream::{self, TokenStream}; use errors::{DiagnosticBuilder, DiagnosticId}; @@ -850,11 +850,7 @@ 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(), - Some("macro arguments"), - ) + parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect(), 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/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 02e986c9e75b6..e55226b8579bd 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -664,7 +664,7 @@ pub fn parse( directory, recurse_into_modules, true, - Some("macro arguments"), + crate::MACRO_ARGUMENTS, ); // A queue of possible matcher positions. We initialize it with the matcher position in which diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 5eda975bc9ee4..4229121b3d075 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -31,6 +31,8 @@ pub use rustc_data_structures::thin_vec::ThinVec; use ast::AttrId; use syntax_pos::edition::Edition; +const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); + // A variant of 'try!' that panics on an Err. This is used as a crutch on the // way towards a non-panic!-prone parser. It should be used for fatal parsing // errors; eventually we plan to convert all code using panictry to just use diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 8ac5beb21b530..8174367ca4531 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -13,7 +13,7 @@ use crate::symbol::kw; use crate::ThinVec; use errors::{Applicability, DiagnosticBuilder}; use log::debug; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; pub trait RecoverQPath: Sized + 'static { const PATH_STYLE: PathStyle = PathStyle::Expr; @@ -201,7 +201,7 @@ impl<'a> Parser<'a> { let mut path = ast::Path { segments: Vec::new(), - span: syntax_pos::DUMMY_SP, + span: DUMMY_SP, }; self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; path.span = ty_span.to(self.prev_span); @@ -267,6 +267,58 @@ impl<'a> Parser<'a> { } } + /// Create a `DiagnosticBuilder` for an unexpected token `t` and try to recover if it is a + /// closing delimiter. + pub fn unexpected_try_recover( + &mut self, + t: &token::Token, + ) -> PResult<'a, bool /* recovered */> { + let token_str = pprust::token_to_string(t); + let this_token_str = self.this_token_descr(); + let (prev_sp, sp) = match (&self.token, self.subparser_name) { + // 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.subparser_name) { + (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, + Ok(recovered) => { + return Ok(recovered); + } + } + let cm = self.sess.source_map(); + 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(sp, label_exp); + } + _ => { + err.span_label(prev_sp, label_exp); + err.span_label(sp, "unexpected token"); + } + } + Err(err) + } + /// Consume alternative await syntaxes like `await `, `await? `, `await()` /// and `await { }`. crate fn parse_incorrect_await_syntax( diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ece6137e881b8..fc76987c17530 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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) -> Parser<'_> { - stream_to_parser(sess, tts.into_iter().collect(), Some("macro arguments")) + stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS) } @@ -331,9 +331,9 @@ pub fn maybe_file_to_stream( pub fn stream_to_parser<'a>( sess: &'a ParseSess, stream: TokenStream, - is_subparser: Option<&'static str>, + subparser_name: Option<&'static str>, ) -> Parser<'a> { - Parser::new(sess, stream, None, true, false, is_subparser) + Parser::new(sess, stream, None, true, false, subparser_name) } /// 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 38aa5091f9898..77b41aaa117f7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -233,8 +233,8 @@ pub struct Parser<'a> { /// error. crate unclosed_delims: Vec, last_unexpected_token_span: Option, - /// If `true`, this `Parser` is not parsing Rust code but rather a macro call. - is_subparser: Option<&'static str>, + /// If present, this `Parser` is not parsing Rust code but rather a macro call. + crate subparser_name: Option<&'static str>, } impl<'a> Drop for Parser<'a> { @@ -541,7 +541,7 @@ impl<'a> Parser<'a> { directory: Option>, recurse_into_file_modules: bool, desugar_doc_comments: bool, - is_subparser: Option<&'static str>, + subparser_name: Option<&'static str>, ) -> Self { let mut parser = Parser { sess, @@ -572,7 +572,7 @@ impl<'a> Parser<'a> { max_angle_bracket_count: 0, unclosed_delims: Vec::new(), last_unexpected_token_span: None, - is_subparser, + subparser_name, }; let tok = parser.next_tok(); @@ -636,56 +636,13 @@ impl<'a> Parser<'a> { } /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. - pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> { + pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> { if self.expected_tokens.is_empty() { if self.token == *t { self.bump(); Ok(false) } else { - let token_str = pprust::token_to_string(t); - let this_token_str = self.this_token_descr(); - 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, - Ok(recovered) => { - return Ok(recovered); - } - } - let cm = self.sess.source_map(); - 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(sp, label_exp); - } - _ => { - err.span_label(prev_sp, label_exp); - err.span_label(sp, "unexpected token"); - } - } - Err(err) + self.unexpected_try_recover(t) } } else { self.expect_one_of(slice::from_ref(t), &[]) @@ -2644,7 +2601,7 @@ impl<'a> Parser<'a> { } Err(mut err) => { self.cancel(&mut err); - let (span, msg) = match (&self.token, self.is_subparser) { + let (span, msg) = match (&self.token, self.subparser_name) { (&token::Token::Eof, Some(origin)) => { let sp = self.sess.source_map().next_point(self.span); (sp, format!( "expected expression, found end of {}", origin)) diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr index 483ecf7338734..ad8015bf385a5 100644 --- a/src/test/ui/malformed/malformed-special-attrs.stderr +++ b/src/test/ui/malformed/malformed-special-attrs.stderr @@ -4,7 +4,7 @@ error: bad `cfg_attr` attribute LL | #[cfg_attr] | ^^^^^^^^^^^ missing condition and attribute | - = note: `cfg_attr` must be of the form: `#[cfg_attr(condition, attribute)]` + = note: `cfg_attr` must be of the form: `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: expected `(`, found `=` diff --git a/src/test/ui/parser/bad-macro-argument.rs b/src/test/ui/parser/macro/bad-macro-argument.rs similarity index 100% rename from src/test/ui/parser/bad-macro-argument.rs rename to src/test/ui/parser/macro/bad-macro-argument.rs diff --git a/src/test/ui/parser/bad-macro-argument.stderr b/src/test/ui/parser/macro/bad-macro-argument.stderr similarity index 100% rename from src/test/ui/parser/bad-macro-argument.stderr rename to src/test/ui/parser/macro/bad-macro-argument.stderr From a2f853a69108faab4d45a55cc4f6633a4a517c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 May 2019 23:13:31 -0700 Subject: [PATCH 3/5] Fix rebase --- src/libsyntax/parse/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index fc76987c17530..f7a7aba9ecbaa 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -347,10 +347,12 @@ pub fn stream_to_parser<'a>( /// The main usage of this function is outside of rustc, for those who uses /// libsyntax as a library. Please do not remove this function while refactoring /// just because it is not used in rustc codebase! -pub fn stream_to_parser_with_base_dir<'a>(sess: &'a ParseSess, - stream: TokenStream, - base_dir: Directory<'a>) -> Parser<'a> { - Parser::new(sess, stream, Some(base_dir), true, false) +pub fn stream_to_parser_with_base_dir<'a>( + sess: &'a ParseSess, + stream: TokenStream, + base_dir: Directory<'a>, +) -> Parser<'a> { + Parser::new(sess, stream, Some(base_dir), true, false, None) } /// A sequence separator. From da57ac38a669573ab693546775eb3ee5dc5b3fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 May 2019 23:16:46 -0700 Subject: [PATCH 4/5] Move diagnostic logic out of parser --- src/libsyntax/parse/diagnostics.rs | 19 +++++++++++++++++++ src/libsyntax/parse/parser.rs | 20 +------------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 8174367ca4531..e93c0bdb8336a 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -614,4 +614,23 @@ impl<'a> Parser<'a> { } } + crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + let (span, msg) = match (&self.token, self.subparser_name) { + (&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(span, "expected expression"); + err + } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 77b41aaa117f7..56951ae08012a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2601,25 +2601,7 @@ impl<'a> Parser<'a> { } Err(mut err) => { self.cancel(&mut err); - let (span, msg) = match (&self.token, self.subparser_name) { - (&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(span, "expected expression"); - return Err(err); + return Err(self.expected_expression_found()); } } } From ee7593e0ac83a1b18e7489b852952cd21e2a6947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 May 2019 15:17:32 -0700 Subject: [PATCH 5/5] Revert changes that belong to separate PR --- src/libsyntax/config.rs | 13 +------------ src/libsyntax/ext/derive.rs | 7 ++----- src/libsyntax/parse/diagnostics.rs | 2 +- .../ui/malformed/malformed-derive-entry.rs | 2 +- .../malformed/malformed-derive-entry.stderr | 6 ++---- .../ui/malformed/malformed-special-attrs.rs | 6 +++--- .../malformed/malformed-special-attrs.stderr | 19 ++++++------------- 7 files changed, 16 insertions(+), 39 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 5ccec05dda20b..c82936afa3d9f 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -94,17 +94,6 @@ 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, other_attribute, ...)]`") - .note("for more information, visit \ - ") - .emit(); - return vec![]; - } let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { parser.expect(&token::OpenDelim(token::Paren))?; @@ -128,7 +117,7 @@ impl<'a> StripUnconfigured<'a> { Ok(result) => result, Err(mut e) => { e.emit(); - return vec![]; + return Vec::new(); } }; diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index bbdda4932f117..6e789c4c7086b 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -17,11 +17,8 @@ pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> return true; } if !attr.is_meta_item_list() { - 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(); + cx.span_err(attr.span, + "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`"); return false; } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index e93c0bdb8336a..810acc9cc923e 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -618,7 +618,7 @@ impl<'a> Parser<'a> { let (span, msg) = match (&self.token, self.subparser_name) { (&token::Token::Eof, Some(origin)) => { let sp = self.sess.source_map().next_point(self.span); - (sp, format!( "expected expression, found end of {}", origin)) + (sp, format!("expected expression, found end of {}", origin)) } _ => (self.span, format!( "expected expression, found {}", diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs index 1a87cd2d11cb5..36cc58f7e268e 100644 --- a/src/test/ui/malformed/malformed-derive-entry.rs +++ b/src/test/ui/malformed/malformed-derive-entry.rs @@ -7,7 +7,7 @@ struct Test2; #[derive()] //~ WARNING empty trait list struct Test3; -#[derive] //~ ERROR bad `derive` attribute +#[derive] //~ ERROR attribute must be of the form `#[derive(Trait1, Trait2, ...)]` 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 aa1334d21a86a..0dc18f6811117 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -16,13 +16,11 @@ warning: empty trait list in `derive` LL | #[derive()] | ^^^^^^^^^^^ -error: bad `derive` attribute +error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]` --> $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 5f1c4795a89b0..4d00755aea09d 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 bad `cfg_attr` attribute +#[cfg_attr] //~ ERROR expected `(`, found end of attribute struct S1; #[cfg_attr = ""] //~ ERROR expected `(`, found `=` struct S2; -#[derive] //~ ERROR bad `derive` attribute +#[derive] //~ ERROR attribute must be of the form struct S3; -#[derive = ""] //~ ERROR bad `derive` attribute +#[derive = ""] //~ ERROR attribute must be of the form 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 ad8015bf385a5..a93f03589e383 100644 --- a/src/test/ui/malformed/malformed-special-attrs.stderr +++ b/src/test/ui/malformed/malformed-special-attrs.stderr @@ -1,11 +1,8 @@ -error: bad `cfg_attr` attribute +error: expected `(`, found end of 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, other_attribute, ...)]` - = note: for more information, visit + | ^ expected `(` error: expected `(`, found `=` --> $DIR/malformed-special-attrs.rs:4:12 @@ -13,21 +10,17 @@ error: expected `(`, found `=` LL | #[cfg_attr = ""] | ^ expected `(` -error: bad `derive` attribute +error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]` --> $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: bad `derive` attribute +error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]` --> $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