auto merge of #11644 : huonw/rust/less-fatality, r=cmr
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.
This commit is contained in:
commit
7c33df0dbb
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)`")
|
||||
};
|
||||
|
@ -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());
|
||||
|
@ -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)`")
|
||||
};
|
||||
|
@ -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);
|
||||
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
|
||||
};
|
||||
|
||||
if exprs.len() == 0 {
|
||||
cx.span_fatal(sp, "env! takes 1 or 2 arguments");
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -47,19 +47,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 {
|
||||
@ -88,13 +93,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;
|
||||
}
|
||||
};
|
||||
|
||||
@ -102,10 +108,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;
|
||||
}
|
||||
};
|
||||
|
||||
@ -294,15 +301,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,
|
||||
@ -319,9 +331,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,
|
||||
@ -336,9 +348,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 {
|
||||
@ -348,8 +361,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()
|
||||
@ -412,12 +425,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| {
|
||||
@ -448,14 +465,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)) => {
|
||||
@ -487,26 +505,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()
|
||||
|
@ -755,8 +755,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| {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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]);
|
||||
}
|
||||
|
48
src/test/compile-fail/macros-nonfatal-errors.rs
Normal file
48
src/test/compile-fail/macros-nonfatal-errors.rs
Normal file
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user