Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand: nix all fatal errors #70074

Merged
merged 18 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/librustc_builtin_macros/cmdline_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use rustc_ast::ast::{self, AttrItem, AttrStyle};
use rustc_ast::attr::mk_attr;
use rustc_ast::token;
use rustc_expand::panictry;
use rustc_session::parse::ParseSess;
use rustc_span::FileName;

Expand All @@ -16,7 +15,13 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
);

let start_span = parser.token.span;
let AttrItem { path, args } = panictry!(parser.parse_attr_item());
let AttrItem { path, args } = match parser.parse_attr_item() {
Ok(ai) => ai,
Err(mut err) => {
err.emit();
continue;
}
};
let end_span = parser.token.span;
if parser.token != token::Eof {
parse_sess.span_diagnostic.span_err(start_span.to(end_span), "invalid crate attribute");
Expand Down
24 changes: 11 additions & 13 deletions src/librustc_builtin_macros/source_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust;
use rustc_expand::base::{self, *};
use rustc_expand::module::DirectoryOwnership;
use rustc_expand::panictry;
use rustc_parse::{self, new_parser_from_file, parser::Parser};
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
use rustc_span::symbol::Symbol;
Expand Down Expand Up @@ -126,7 +125,7 @@ pub fn expand_include<'cx>(
}
impl<'a> base::MacResult for ExpandResult<'a> {
fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
let r = panictry!(self.p.parse_expr());
let r = base::parse_expr(&mut self.p)?;
if self.p.token != token::Eof {
self.p.sess.buffer_lint(
&INCOMPLETE_INCLUDE,
Expand All @@ -141,18 +140,17 @@ pub fn expand_include<'cx>(
fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
let mut ret = SmallVec::new();
while self.p.token != token::Eof {
match panictry!(self.p.parse_item()) {
Some(item) => ret.push(item),
None => {
match self.p.parse_item() {
Err(mut err) => {
err.emit();
break;
}
Ok(Some(item)) => ret.push(item),
Ok(None) => {
let token = pprust::token_to_string(&self.p.token);
self.p
.sess
.span_diagnostic
.span_fatal(
self.p.token.span,
&format!("expected item, found `{}`", token),
)
.raise();
let msg = format!("expected item, found `{}`", token);
self.p.struct_span_err(self.p.token.span, &msg).emit();
break;
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/librustc_builtin_macros/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ pub fn expand_test_or_bench(
return vec![];
}

let item = if let Annotatable::Item(i) = item {
i
} else {
cx.parse_sess
.span_diagnostic
.span_fatal(
item.span(),
let item = match item {
Annotatable::Item(i) => i,
other => {
cx.struct_span_err(
other.span(),
"`#[test]` attribute is only allowed on non associated functions",
)
.raise();
.emit();
return vec![other];
}
};

if let ast::ItemKind::MacCall(_) = item.kind {
Expand Down
20 changes: 10 additions & 10 deletions src/librustc_builtin_macros/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,14 +345,14 @@ fn is_test_case(i: &ast::Item) -> bool {

fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
test_attr.meta_item_list().map(|meta_list| {
if meta_list.len() != 1 {
sd.span_fatal(test_attr.span, "`#![test_runner(..)]` accepts exactly 1 argument")
.raise()
}
match meta_list[0].meta_item() {
Some(meta_item) if meta_item.is_word() => meta_item.path.clone(),
_ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise(),
}
})
let meta_list = test_attr.meta_item_list()?;
let span = test_attr.span;
match &*meta_list {
[single] => match single.meta_item() {
Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
_ => sd.struct_span_err(span, "`test_runner` argument must be a path").emit(),
},
_ => sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit(),
}
None
}
69 changes: 33 additions & 36 deletions src/librustc_expand/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_parse::{self, parser, MACRO_ARGUMENTS};
use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition;
Expand Down Expand Up @@ -296,16 +296,26 @@ where
}

pub trait ProcMacro {
fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt<'_>, span: Span, ts: TokenStream) -> TokenStream;
fn expand<'cx>(
&self,
ecx: &'cx mut ExtCtxt<'_>,
span: Span,
ts: TokenStream,
) -> Result<TokenStream, ErrorReported>;
}

impl<F> ProcMacro for F
where
F: Fn(TokenStream) -> TokenStream,
{
fn expand<'cx>(&self, _ecx: &'cx mut ExtCtxt<'_>, _span: Span, ts: TokenStream) -> TokenStream {
fn expand<'cx>(
&self,
_ecx: &'cx mut ExtCtxt<'_>,
_span: Span,
ts: TokenStream,
) -> Result<TokenStream, ErrorReported> {
// FIXME setup implicit context in TLS before calling self.
(*self)(ts)
Ok((*self)(ts))
}
}

Expand All @@ -316,7 +326,7 @@ pub trait AttrProcMacro {
span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> TokenStream;
) -> Result<TokenStream, ErrorReported>;
}

impl<F> AttrProcMacro for F
Expand All @@ -329,9 +339,9 @@ where
_span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> TokenStream {
) -> Result<TokenStream, ErrorReported> {
// FIXME setup implicit context in TLS before calling self.
(*self)(annotation, annotated)
Ok((*self)(annotation, annotated))
}
}

Expand Down Expand Up @@ -1004,31 +1014,9 @@ impl<'a> ExtCtxt<'a> {
self.current_expansion.id.expansion_cause()
}

pub fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
self.parse_sess.span_diagnostic.struct_span_warn(sp, msg)
}
pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
self.parse_sess.span_diagnostic.struct_span_err(sp, msg)
}
pub fn struct_span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
self.parse_sess.span_diagnostic.struct_span_fatal(sp, msg)
}

/// Emit `msg` attached to `sp`, and stop compilation immediately.
///
/// `span_err` should be strongly preferred where-ever possible:
/// this should *only* be used when:
///
/// - continuing has a high risk of flow-on errors (e.g., errors in
/// declaring a macro would cause all uses of that macro to
/// complain about "undefined macro"), or
/// - there is literally nothing else that can be done (however,
/// in most cases one can construct a dummy expression/item to
/// substitute; we never hit resolve/type-checking so the dummy
/// value doesn't have to match anything)
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.parse_sess.span_diagnostic.span_fatal(sp, msg).raise();
}

/// Emit `msg` attached to `sp`, without immediately stopping
/// compilation.
Expand All @@ -1038,9 +1026,6 @@ impl<'a> ExtCtxt<'a> {
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.parse_sess.span_diagnostic.span_err(sp, msg);
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code);
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.parse_sess.span_diagnostic.span_warn(sp, msg);
}
Expand Down Expand Up @@ -1168,6 +1153,18 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str)
}
}

/// Parse an expression. On error, emit it, advancing to `Eof`, and return `None`.
pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> {
match p.parse_expr() {
Ok(e) => return Some(e),
Err(mut err) => err.emit(),
}
while p.token != token::Eof {
p.bump();
}
None
}

/// Interpreting `tts` as a comma-separated sequence of expressions,
/// expect exactly one string literal, or emit an error and return `None`.
pub fn get_single_str_from_tts(
Expand All @@ -1181,7 +1178,7 @@ pub fn get_single_str_from_tts(
cx.span_err(sp, &format!("{} takes 1 argument", name));
return None;
}
let ret = panictry!(p.parse_expr());
let ret = parse_expr(&mut p)?;
let _ = p.eat(&token::Comma);

if p.token != token::Eof {
Expand All @@ -1190,8 +1187,8 @@ pub fn get_single_str_from_tts(
expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s.to_string())
}

/// Extracts comma-separated expressions from `tts`. If there is a
/// parsing error, emit a non-fatal error and return `None`.
/// Extracts comma-separated expressions from `tts`.
/// On error, emit it, and return `None`.
pub fn get_exprs_from_tts(
cx: &mut ExtCtxt<'_>,
sp: Span,
Expand All @@ -1200,7 +1197,7 @@ pub fn get_exprs_from_tts(
let mut p = cx.new_parser_from_tts(tts);
let mut es = Vec::new();
while p.token != token::Eof {
let expr = panictry!(p.parse_expr());
let expr = parse_expr(&mut p)?;

// Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
Expand Down
16 changes: 12 additions & 4 deletions src/librustc_expand/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ ast_fragments! {
}

impl AstFragmentKind {
fn dummy(self, span: Span) -> AstFragment {
crate fn dummy(self, span: Span) -> AstFragment {
self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
}

Expand Down Expand Up @@ -682,7 +682,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
InvocationKind::Bang { mac, .. } => match ext {
SyntaxExtensionKind::Bang(expander) => {
self.gate_proc_macro_expansion_kind(span, fragment_kind);
let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens());
let tok_result = match expander.expand(self.cx, span, mac.args.inner_tokens()) {
Err(_) => return ExpandResult::Ready(fragment_kind.dummy(span)),
Ok(ts) => ts,
};
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
}
SyntaxExtensionKind::LegacyBang(expander) => {
Expand All @@ -709,8 +712,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
if let MacArgs::Eq(..) = attr_item.args {
self.cx.span_err(span, "key-value macro attributes are not supported");
}
let tok_result =
expander.expand(self.cx, span, attr_item.args.inner_tokens(), tokens);
let inner_tokens = attr_item.args.inner_tokens();
let tok_result = match expander.expand(self.cx, span, inner_tokens, tokens) {
Err(_) => return ExpandResult::Ready(fragment_kind.dummy(span)),
Ok(ts) => ts,
};
self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span)
}
SyntaxExtensionKind::LegacyAttr(expander) => {
Expand Down Expand Up @@ -1139,6 +1145,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// macros are expanded before any lint passes so this warning has to be hardcoded
if attr.has_name(sym::derive) {
self.cx
.parse_sess()
.span_diagnostic
.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations")
.note("this may become a hard error in a future release")
.emit();
Expand Down
19 changes: 0 additions & 19 deletions src/librustc_expand/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,6 @@

extern crate proc_macro as pm;

// 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
// normal try.
#[macro_export]
macro_rules! panictry {
($e:expr) => {{
use rustc_errors::FatalError;
use std::result::Result::{Err, Ok};
match $e {
Ok(e) => e,
Err(mut e) => {
e.emit();
FatalError.raise()
}
}
}};
}

mod placeholders;
mod proc_macro_server;

Expand Down
Loading