]> git.lizzy.rs Git - rust.git/commitdiff
syntax::ext: replace span_fatal with span_err in many places.
authorHuon Wilson <dbau.pp+github@gmail.com>
Fri, 17 Jan 2014 14:53:10 +0000 (01:53 +1100)
committerHuon Wilson <dbau.pp+github@gmail.com>
Fri, 17 Jan 2014 15:03:04 +0000 (02:03 +1100)
This means that compilation continues for longer, and so we can see more
errors per compile. This is mildly more user-friendly because it stops
users having to run rustc n times to see n macro errors: just run it
once to see all of them.

15 files changed:
src/libsyntax/ext/asm.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/bytes.rs
src/libsyntax/ext/concat.rs
src/libsyntax/ext/concat_idents.rs
src/libsyntax/ext/deriving/default.rs
src/libsyntax/ext/deriving/rand.rs
src/libsyntax/ext/deriving/zero.rs
src/libsyntax/ext/env.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/format.rs
src/libsyntax/ext/source_util.rs
src/libsyntax/ext/trace_macros.rs
src/libsyntax/ext/tt/macro_parser.rs
src/test/compile-fail/macros-nonfatal-errors.rs [new file with mode: 0644]

index e5145d37278712c5d0ff2183d61b7d5d6ec11a57..021f0d29d9e237e61f0438cff1aa345d5b60fe09 100644 (file)
@@ -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);
             }
index ef6d154c651a3655d8eb06de161dc59046fd73c4..538562813b3bbdd73e58a0742a324b18ef353a7d 100644 (file)
@@ -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 @@ pub fn bt_pop(&mut self) {
             _ => 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 @@ pub fn ident_of(&self, st: &str) -> ast::Ident {
     }
 }
 
-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,
index 945e7c0d66693e988193ed916a0506626d0c6272..0c9a23be558c857b68d3f92724d165d6b7a1b247 100644 (file)
 
 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() {
index 251492141c8fd9a5fc4ecf3c41b7ddfbc53fcfb3..2a68674af952ca4f6e59011d298115b80248bb8d 100644 (file)
 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);
index 0d053bb1d12ca41ea6bf6bd038a0f4d8b76c1328..9dcb5b4cb4c2a49814f728bdb4f2fb27f4eb3219 100644 (file)
@@ -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();
+                }
             }
         }
     }
index 0ae3c6f45933b363cf8723b15f2d10386c39ce79..088a221c965eb75f36c36edc1732c4b96d8413da 100644 (file)
@@ -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)`")
     };
index f065340bdc2527ffdef386938fd0e5d9ccd0e14f..29023dea6211fd80df02729479eb5cfe4b58c74b 100644 (file)
@@ -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());
index 034a7970515ddc743964f5d91f37c132f1a67137..31020b4a56224dc2784b4cdc2805431789a5c842 100644 (file)
@@ -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)`")
     };
index d7409f6b11220d3ad342efa74f915c30cbe18ae2..a9b40ea7ec63844043e1f86bd9e0e8a70825f73b 100644 (file)
 
 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)
index b1b38d6dc90f24528da78373c3e93a441382daec..a17478178eb50e91a306066311631c9e797941a6 100644 (file)
@@ -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()
index 9ae13ddeb0266f04c76ab1926c88eabefecfb8de..ff6db43a29211e016603fc4859c9a64c21bdffa2 100644 (file)
@@ -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| {
index 3e781451b081cab8d52f73f9eec364ca11c698e7..711f8ff11ee63548838b01ae0bf2ab704235106f 100644 (file)
@@ -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);
index 679e9a5098eb1c6d4db524b523b9f4d25a365878..83c6c6a1762351142c7a3d5a812c93f50d688908 100644 (file)
@@ -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();
index 514b8e6af99e0d64c6d2ea54f404649f1770edf1..1080291179b550e6bbab1596c0878f95dd6e9541 100644 (file)
@@ -183,8 +183,8 @@ fn n_rec(p_s: @ParseSess, m: &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 (file)
index 0000000..475faa7
--- /dev/null
@@ -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
+}