diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 3f84979ac05e7..b72c2f91543b7 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -8,7 +8,6 @@ use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree} use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_parse::nt_to_tokenstream; -use rustc_parse::parser::ForceCollect; use rustc_span::{Span, DUMMY_SP}; const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread; @@ -114,24 +113,22 @@ impl MultiItemModifier for ProcMacroDerive { let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); let mut parser = rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive")); - let mut items = vec![]; - loop { - match parser.parse_item(ForceCollect::No) { - Ok(None) => break, - Ok(Some(item)) => { - if is_stmt { - items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item)))); - } else { - items.push(Annotatable::Item(item)); - } - } - Err(mut err) => { - err.emit(); - break; + let items = parser + .parse_items(&token::Eof) + .unwrap_or_else(|mut e| { + e.emit(); + Vec::new() + }) + .into_iter() + .map(|item| { + if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(span, item))) + } else { + Annotatable::Item(item) } - } - } + }) + .collect(); // fail if there have been errors emitted if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2ce63d011f438..ff403a02c4ef6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -54,7 +54,11 @@ impl<'a> Parser<'a> { ) -> PResult<'a, (Vec, Vec>, Span)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; + let items = self.parse_items(term)?; + Ok((attrs, items, lo.to(self.prev_token.span))) + } + pub fn parse_items(&mut self, term: &TokenKind) -> PResult<'a, Vec>> { let mut items = vec![]; while let Some(item) = self.parse_item(ForceCollect::No)? { items.push(item); @@ -71,7 +75,7 @@ impl<'a> Parser<'a> { } } - Ok((attrs, items, lo.to(self.prev_token.span))) + Ok(items) } } diff --git a/src/test/ui/proc-macro/auxiliary/derive-bad.rs b/src/test/ui/proc-macro/auxiliary/derive-bad.rs index 90bb9b1baf2b7..4d260748b695e 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-bad.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-bad.rs @@ -11,3 +11,8 @@ use proc_macro::TokenStream; pub fn derive_a(_input: TokenStream) -> TokenStream { "struct A { inner }".parse().unwrap() } + +#[proc_macro_derive(B)] +pub fn derive_b(_input: TokenStream) -> TokenStream { + "const _: () = (); { HEY! }".parse().unwrap() +} diff --git a/src/test/ui/proc-macro/derive-bad.rs b/src/test/ui/proc-macro/derive-bad.rs index cb5188b5fb43f..015fc2b7ea0aa 100644 --- a/src/test/ui/proc-macro/derive-bad.rs +++ b/src/test/ui/proc-macro/derive-bad.rs @@ -8,4 +8,9 @@ extern crate derive_bad; //~| ERROR expected `:`, found `}` struct A; //~ ERROR the name `A` is defined multiple times +#[derive(B)] +//~^ ERROR proc-macro derive produced unparseable tokens +//~| ERROR expected item, found `{` +struct B; + fn main() {} diff --git a/src/test/ui/proc-macro/derive-bad.stderr b/src/test/ui/proc-macro/derive-bad.stderr index ae48141fb3133..7cd3175ac57ca 100644 --- a/src/test/ui/proc-macro/derive-bad.stderr +++ b/src/test/ui/proc-macro/derive-bad.stderr @@ -23,6 +23,20 @@ LL | struct A; | = note: `A` must be defined only once in the type namespace of this module -error: aborting due to 3 previous errors +error: expected item, found `{` + --> $DIR/derive-bad.rs:11:10 + | +LL | #[derive(B)] + | ^ expected item + | + = note: this error originates in the derive macro `B` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: proc-macro derive produced unparseable tokens + --> $DIR/derive-bad.rs:11:10 + | +LL | #[derive(B)] + | ^ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0428`.