diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/libsyntax/ext/asm.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 76 | ||||
| -rw-r--r-- | src/libsyntax/ext/bytes.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/concat.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/concat_idents.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/default.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/rand.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/zero.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/env.rs | 39 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 83 | ||||
| -rw-r--r-- | src/libsyntax/ext/format.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/ext/source_util.rs | 26 | ||||
| -rw-r--r-- | src/libsyntax/ext/trace_macros.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_parser.rs | 4 | ||||
| -rw-r--r-- | src/test/compile-fail/macros-nonfatal-errors.rs | 48 |
15 files changed, 245 insertions, 84 deletions
diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index e5145d37278..021f0d29d9e 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -59,9 +59,12 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) while continue_ { match state { Asm => { - let (s, style) = - expr_to_str(cx, p.parse_expr(), - "inline assembly must be a string literal."); + let (s, style) = match expr_to_str(cx, p.parse_expr(), + "inline assembly must be a string literal.") { + Some((s, st)) => (s, st), + // let compilation continue + None => return MacResult::dummy_expr(), + }; asm = s; asm_str_style = Some(style); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ef6d154c651..538562813b3 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -136,6 +136,17 @@ pub enum MacResult { MRAny(@AnyMacro), MRDef(MacroDef), } +impl MacResult { + /// Create an empty expression MacResult; useful for satisfying + /// type signatures after emitting a non-fatal error (which stop + /// compilation well before the validity (or otherwise)) of the + /// expression are checked. + pub fn dummy_expr() -> MacResult { + MRExpr(@ast::Expr { + id: ast::DUMMY_NODE_ID, node: ast::ExprLogLevel, span: codemap::DUMMY_SP + }) + } +} pub enum SyntaxExtension { // #[deriving] and such @@ -364,10 +375,27 @@ impl<'a> ExtCtxt<'a> { _ => self.bug("tried to pop without a push") } } + /// Emit `msg` attached to `sp`, and stop compilation immediately. + /// + /// `span_err` should be strongly prefered 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(&self, sp: Span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_fatal(sp, msg); } + + /// Emit `msg` attached to `sp`, without immediately stopping + /// compilation. + /// + /// Compilation will be stopped in the near future (at the end of + /// the macro expansion phase). pub fn span_err(&self, sp: Span, msg: &str) { self.print_backtrace(); self.parse_sess.span_diagnostic.span_err(sp, msg); @@ -402,53 +430,69 @@ impl<'a> ExtCtxt<'a> { } } -pub fn expr_to_str(cx: &ExtCtxt, expr: @ast::Expr, err_msg: &str) -> (@str, ast::StrStyle) { +/// Extract a string literal from `expr`, emitting `err_msg` if `expr` +/// is not a string literal. This does not stop compilation on error, +/// merely emits a non-fatal error and returns None. +pub fn expr_to_str(cx: &ExtCtxt, expr: @ast::Expr, + err_msg: &str) -> Option<(@str, ast::StrStyle)> { match expr.node { ast::ExprLit(l) => match l.node { - ast::LitStr(s, style) => (s, style), - _ => cx.span_fatal(l.span, err_msg) + ast::LitStr(s, style) => return Some((s, style)), + _ => cx.span_err(l.span, err_msg) }, - _ => cx.span_fatal(expr.span, err_msg) + _ => cx.span_err(expr.span, err_msg) } + None } +/// Non-fatally assert that `tts` is empty. Note that this function +/// returns even when `tts` is non-empty, macros that *need* to stop +/// compilation should call +/// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be +/// done as rarely as possible). pub fn check_zero_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree], name: &str) { if tts.len() != 0 { - cx.span_fatal(sp, format!("{} takes no arguments", name)); + cx.span_err(sp, format!("{} takes no arguments", name)); } } +/// Extract the string literal from the first token of `tts`. If this +/// is not a string literal, emit an error and return None. pub fn get_single_str_from_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree], name: &str) - -> @str { + -> Option<@str> { if tts.len() != 1 { - cx.span_fatal(sp, format!("{} takes 1 argument.", name)); - } - - match tts[0] { - ast::TTTok(_, token::LIT_STR(ident)) - | ast::TTTok(_, token::LIT_STR_RAW(ident, _)) => cx.str_of(ident), - _ => cx.span_fatal(sp, format!("{} requires a string.", name)), + cx.span_err(sp, format!("{} takes 1 argument.", name)); + } else { + match tts[0] { + ast::TTTok(_, token::LIT_STR(ident)) + | ast::TTTok(_, token::LIT_STR_RAW(ident, _)) => return Some(cx.str_of(ident)), + _ => cx.span_err(sp, format!("{} requires a string.", name)), + } } + None } +/// Extract comma-separated expressions from `tts`. If there is a +/// parsing error, emit a non-fatal error and return None. pub fn get_exprs_from_tts(cx: &ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> ~[@ast::Expr] { + tts: &[ast::TokenTree]) -> Option<~[@ast::Expr]> { let mut p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_owned()); let mut es = ~[]; while p.token != token::EOF { if es.len() != 0 && !p.eat(&token::COMMA) { - cx.span_fatal(sp, "expected token: `,`"); + cx.span_err(sp, "expected token: `,`"); + return None; } es.push(p.parse_expr()); } - es + Some(es) } // in order to have some notion of scoping for macros, diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index 945e7c0d666..0c9a23be558 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -20,7 +20,10 @@ use std::char; pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { // Gather all argument expressions - let exprs = get_exprs_from_tts(cx, sp, tts); + let exprs = match get_exprs_from_tts(cx, sp, tts) { + None => return MacResult::dummy_expr(), + Some(e) => e, + }; let mut bytes = ~[]; for expr in exprs.iter() { diff --git a/src/libsyntax/ext/concat.rs b/src/libsyntax/ext/concat.rs index 251492141c8..2a68674af95 100644 --- a/src/libsyntax/ext/concat.rs +++ b/src/libsyntax/ext/concat.rs @@ -18,7 +18,10 @@ use ext::build::AstBuilder; pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> base::MacResult { - let es = base::get_exprs_from_tts(cx, sp, tts); + let es = match base::get_exprs_from_tts(cx, sp, tts) { + Some(e) => e, + None => return base::MacResult::dummy_expr() + }; let mut accumulator = ~""; for e in es.move_iter() { let e = cx.expand_expr(e); diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 0d053bb1d12..9dcb5b4cb4c 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -23,12 +23,18 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) if i & 1 == 1 { match *e { ast::TTTok(_, token::COMMA) => (), - _ => cx.span_fatal(sp, "concat_idents! expecting comma.") + _ => { + cx.span_err(sp, "concat_idents! expecting comma."); + return MacResult::dummy_expr(); + } } } else { match *e { ast::TTTok(_, token::IDENT(ident,_)) => res_str.push_str(cx.str_of(ident)), - _ => cx.span_fatal(sp, "concat_idents! requires ident args.") + _ => { + cx.span_err(sp, "concat_idents! requires ident args."); + return MacResult::dummy_expr(); + } } } } diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index 0ae3c6f4593..088a221c965 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -70,8 +70,9 @@ fn default_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Exp } } StaticEnum(..) => { - cx.span_fatal(span, "`Default` cannot be derived for enums, \ - only structs") + cx.span_err(span, "`Default` cannot be derived for enums, only structs"); + // let compilation continue + cx.expr_uint(span, 0) } _ => cx.bug("Non-static method in `deriving(Default)`") }; diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index f065340bdc2..29023dea621 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -73,7 +73,9 @@ fn rand_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr { } StaticEnum(_, ref variants) => { if variants.is_empty() { - cx.span_fatal(span, "`Rand` cannot be derived for enums with no variants"); + cx.span_err(span, "`Rand` cannot be derived for enums with no variants"); + // let compilation continue + return cx.expr_uint(span, 0); } let variant_count = cx.expr_uint(span, variants.len()); diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs index 034a7970515..31020b4a562 100644 --- a/src/libsyntax/ext/deriving/zero.rs +++ b/src/libsyntax/ext/deriving/zero.rs @@ -86,8 +86,9 @@ fn zero_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr { } } StaticEnum(..) => { - cx.span_fatal(span, "`Zero` cannot be derived for enums, \ - only structs") + cx.span_err(span, "`Zero` cannot be derived for enums, only structs"); + // let compilation continue + cx.expr_uint(span, 0) } _ => cx.bug("Non-static method in `deriving(Zero)`") }; diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index d7409f6b112..a9b40ea7ec6 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -24,7 +24,10 @@ use std::os; pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { - let var = get_single_str_from_tts(cx, sp, tts, "option_env!"); + let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { + None => return MacResult::dummy_expr(), + Some(v) => v + }; let e = match os::getenv(var) { None => quote_expr!(cx, ::std::option::None::<&'static str>), @@ -35,24 +38,38 @@ pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { - let exprs = get_exprs_from_tts(cx, sp, tts); - - if exprs.len() == 0 { - cx.span_fatal(sp, "env! takes 1 or 2 arguments"); - } + let exprs = match get_exprs_from_tts(cx, sp, tts) { + Some([]) => { + cx.span_err(sp, "env! takes 1 or 2 arguments"); + return MacResult::dummy_expr(); + } + None => return MacResult::dummy_expr(), + Some(exprs) => exprs + }; - let (var, _var_str_style) = expr_to_str(cx, exprs[0], "expected string literal"); + let var = match expr_to_str(cx, exprs[0], "expected string literal") { + None => return MacResult::dummy_expr(), + Some((v, _style)) => v + }; let msg = match exprs.len() { 1 => format!("environment variable `{}` not defined", var).to_managed(), 2 => { - let (s, _style) = expr_to_str(cx, exprs[1], "expected string literal"); - s + match expr_to_str(cx, exprs[1], "expected string literal") { + None => return MacResult::dummy_expr(), + Some((s, _style)) => s + } + } + _ => { + cx.span_err(sp, "env! takes 1 or 2 arguments"); + return MacResult::dummy_expr(); } - _ => cx.span_fatal(sp, "env! takes 1 or 2 arguments") }; let e = match os::getenv(var) { - None => cx.span_fatal(sp, msg), + None => { + cx.span_err(sp, msg); + cx.expr_uint(sp, 0) + } Some(s) => cx.expr_str(sp, s.to_managed()) }; MRExpr(e) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b1b38d6dc90..a17478178eb 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -46,19 +46,24 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { // Token-tree macros: MacInvocTT(ref pth, ref tts, ctxt) => { if (pth.segments.len() > 1u) { - fld.cx.span_fatal( + fld.cx.span_err( pth.span, format!("expected macro name without module \ separators")); + // let compilation continue + return e; } let extname = &pth.segments[0].identifier; let extnamestr = ident_to_str(extname); // leaving explicit deref here to highlight unbox op: let marked_after = match fld.extsbox.find(&extname.name) { None => { - fld.cx.span_fatal( + fld.cx.span_err( pth.span, - format!("macro undefined: '{}'", extnamestr)) + format!("macro undefined: '{}'", extnamestr)); + + // let compilation continue + return e; } Some(&NormalTT(ref expandfun, exp_span)) => { fld.cx.bt_push(ExpnInfo { @@ -87,13 +92,14 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { MRExpr(e) => e, MRAny(any_macro) => any_macro.make_expr(), _ => { - fld.cx.span_fatal( + fld.cx.span_err( pth.span, format!( "non-expr macro in expr pos: {}", extnamestr ) - ) + ); + return e; } }; @@ -101,10 +107,11 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { mark_expr(expanded,fm) } _ => { - fld.cx.span_fatal( + fld.cx.span_err( pth.span, format!("'{}' is not a tt-style macro", extnamestr) - ) + ); + return e; } }; @@ -299,15 +306,20 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) let extnamestr = ident_to_str(extname); let fm = fresh_mark(); let expanded = match fld.extsbox.find(&extname.name) { - None => fld.cx.span_fatal(pth.span, - format!("macro undefined: '{}!'", extnamestr)), + None => { + fld.cx.span_err(pth.span, + format!("macro undefined: '{}!'", extnamestr)); + // let compilation continue + return SmallVector::zero(); + } Some(&NormalTT(ref expander, span)) => { if it.ident.name != parse::token::special_idents::invalid.name { - fld.cx.span_fatal(pth.span, - format!("macro {}! expects no ident argument, \ - given '{}'", extnamestr, - ident_to_str(&it.ident))); + fld.cx.span_err(pth.span, + format!("macro {}! expects no ident argument, \ + given '{}'", extnamestr, + ident_to_str(&it.ident))); + return SmallVector::zero(); } fld.cx.bt_push(ExpnInfo { call_site: it.span, @@ -324,9 +336,9 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) } Some(&IdentTT(ref expander, span)) => { if it.ident.name == parse::token::special_idents::invalid.name { - fld.cx.span_fatal(pth.span, - format!("macro {}! expects an ident argument", - extnamestr)); + fld.cx.span_err(pth.span, + format!("macro {}! expects an ident argument", extnamestr)); + return SmallVector::zero(); } fld.cx.bt_push(ExpnInfo { call_site: it.span, @@ -341,9 +353,10 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) let marked_ctxt = new_mark(fm,ctxt); expander.expand(fld.cx, it.span, it.ident, marked_tts, marked_ctxt) } - _ => fld.cx.span_fatal(it.span, - format!("{}! is not legal in item position", - extnamestr)) + _ => { + fld.cx.span_err(it.span, format!("{}! is not legal in item position", extnamestr)); + return SmallVector::zero(); + } }; let items = match expanded { @@ -353,8 +366,8 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) .collect() } MRExpr(_) => { - fld.cx.span_fatal(pth.span, format!("expr macro in item position: {}", - extnamestr)) + fld.cx.span_err(pth.span, format!("expr macro in item position: {}", extnamestr)); + return SmallVector::zero(); } MRAny(any_macro) => { any_macro.make_items().move_iter() @@ -418,12 +431,16 @@ fn load_extern_macros(crate: &ast::ViewItem, fld: &mut MacroExpander) { let lib = match DynamicLibrary::open(Some(&path)) { Ok(lib) => lib, + // this is fatal: there are almost certainly macros we need + // inside this crate, so continue would spew "macro undefined" + // errors Err(err) => fld.cx.span_fatal(crate.span, err) }; unsafe { let registrar: MacroCrateRegistrationFun = match lib.symbol(registrar) { Ok(registrar) => registrar, + // again fatal if we can't register macros Err(err) => fld.cx.span_fatal(crate.span, err) }; registrar(|name, extension| { @@ -454,14 +471,15 @@ pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> { _ => return expand_non_macro_stmt(s, fld) }; if (pth.segments.len() > 1u) { - fld.cx.span_fatal(pth.span, - "expected macro name without module separators"); + fld.cx.span_err(pth.span, "expected macro name without module separators"); + return SmallVector::zero(); } let extname = &pth.segments[0].identifier; let extnamestr = ident_to_str(extname); let marked_after = match fld.extsbox.find(&extname.name) { None => { - fld.cx.span_fatal(pth.span, format!("macro undefined: '{}'", extnamestr)) + fld.cx.span_err(pth.span, format!("macro undefined: '{}'", extnamestr)); + return SmallVector::zero(); } Some(&NormalTT(ref expandfun, exp_span)) => { @@ -493,26 +511,27 @@ pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> { } } MRAny(any_macro) => any_macro.make_stmt(), - _ => fld.cx.span_fatal( - pth.span, - format!("non-stmt macro in stmt pos: {}", extnamestr)) + _ => { + fld.cx.span_err(pth.span, + format!("non-stmt macro in stmt pos: {}", extnamestr)); + return SmallVector::zero(); + } }; mark_stmt(expanded,fm) } _ => { - fld.cx.span_fatal(pth.span, - format!("'{}' is not a tt-style macro", - extnamestr)) + fld.cx.span_err(pth.span, format!("'{}' is not a tt-style macro", extnamestr)); + return SmallVector::zero(); } }; // Keep going, outside-in. let fully_expanded = fld.fold_stmt(marked_after); if fully_expanded.is_empty() { - fld.cx.span_fatal(pth.span, - "macro didn't expand to a statement"); + fld.cx.span_err(pth.span, "macro didn't expand to a statement"); + return SmallVector::zero(); } fld.cx.bt_pop(); let fully_expanded: SmallVector<@Stmt> = fully_expanded.move_iter() diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 9ae13ddeb02..ff6db43a292 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -748,8 +748,11 @@ pub fn expand_args(ecx: &mut ExtCtxt, sp: Span, // Be sure to recursively expand macros just in case the format string uses // a macro to build the format expression. let expr = cx.ecx.expand_expr(efmt); - let (fmt, _) = expr_to_str(cx.ecx, expr, - "format argument must be a string literal."); + let fmt = match expr_to_str(cx.ecx, expr, + "format argument must be a string literal.") { + Some((fmt, _)) => fmt, + None => return MacResult::dummy_expr() + }; let mut err = false; parse::parse_error::cond.trap(|m| { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 3e781451b08..711f8ff11ee 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -79,7 +79,10 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // unhygienically. pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { - let file = get_single_str_from_tts(cx, sp, tts, "include!"); + let file = match get_single_str_from_tts(cx, sp, tts, "include!") { + Some(f) => f, + None => return MacResult::dummy_expr(), + }; // The file will be added to the code map by the parser let mut p = parse::new_sub_parser_from_file(cx.parse_sess(), @@ -94,12 +97,15 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // include_str! : read the given file, insert it as a literal string expr pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { - let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); + let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { + Some(f) => f, + None => return MacResult::dummy_expr() + }; let file = res_rel_file(cx, sp, &Path::new(file)); let bytes = match io::result(|| File::open(&file).read_to_end()) { Err(e) => { - cx.span_fatal(sp, format!("couldn't read {}: {}", - file.display(), e.desc)); + cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e.desc)); + return MacResult::dummy_expr(); } Ok(bytes) => bytes, }; @@ -114,7 +120,8 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) base::MRExpr(cx.expr_str(sp, src)) } None => { - cx.span_fatal(sp, format!("{} wasn't a utf-8 file", file.display())); + cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display())); + return MacResult::dummy_expr(); } } } @@ -124,12 +131,15 @@ pub fn expand_include_bin(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) { use std::at_vec; - let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); + let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") { + Some(f) => f, + None => return MacResult::dummy_expr() + }; let file = res_rel_file(cx, sp, &Path::new(file)); match io::result(|| File::open(&file).read_to_end()) { Err(e) => { - cx.span_fatal(sp, format!("couldn't read {}: {}", - file.display(), e.desc)); + cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e.desc)); + return MacResult::dummy_expr(); } Ok(bytes) => { let bytes = at_vec::to_managed_move(bytes); diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 679e9a5098e..83c6c6a1762 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -33,7 +33,8 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt, } else if rust_parser.is_keyword(keywords::False) { cx.set_trace_macros(false); } else { - cx.span_fatal(sp, "trace_macros! only accepts `true` or `false`") + cx.span_err(sp, "trace_macros! only accepts `true` or `false`"); + return base::MacResult::dummy_expr(); } rust_parser.bump(); diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 514b8e6af99..1080291179b 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -183,8 +183,8 @@ pub fn nameize(p_s: @ParseSess, ms: &[Matcher], res: &[@NamedMatch]) node: MatchNonterminal(ref bind_name, _, idx), span: sp } => { if ret_val.contains_key(bind_name) { - p_s.span_diagnostic.span_fatal(sp, ~"Duplicated bind name: "+ - ident_to_str(bind_name)) + p_s.span_diagnostic.span_fatal(sp, + "Duplicated bind name: "+ ident_to_str(bind_name)) } ret_val.insert(*bind_name, res[idx]); } diff --git a/src/test/compile-fail/macros-nonfatal-errors.rs b/src/test/compile-fail/macros-nonfatal-errors.rs new file mode 100644 index 00000000000..475faa75704 --- /dev/null +++ b/src/test/compile-fail/macros-nonfatal-errors.rs @@ -0,0 +1,48 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// test that errors in a (selection) of macros don't kill compilation +// immediately, so that we get more errors listed at a time. + +#[feature(asm)]; + +#[deriving(Default, //~ ERROR + Rand, //~ ERROR + Zero)] //~ ERROR +enum CantDeriveThose {} + +fn main() { + doesnt_exist!(); //~ ERROR + + bytes!(invalid); //~ ERROR + + asm!(invalid); //~ ERROR + + concat_idents!("not", "idents"); //~ ERROR + + option_env!(invalid); //~ ERROR + env!(invalid); //~ ERROR + env!(foo, abr, baz); //~ ERROR + env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); //~ ERROR + + foo::blah!(); //~ ERROR + + format!(); //~ ERROR + format!(invalid); //~ ERROR + + include!(invalid); //~ ERROR + + include_str!(invalid); //~ ERROR + include_str!("i'd be quite surprised if a file with this name existed"); //~ ERROR + include_bin!(invalid); //~ ERROR + include_bin!("i'd be quite surprised if a file with this name existed"); //~ ERROR + + trace_macros!(invalid); //~ ERROR +} |
