Skip to content

Commit 99f8380

Browse files
committed
auto merge of #12370 : rcxdude/rust/macro_fix, r=alexcrichton
Closes #11692. Instead of returning the original expression, a dummy expression (with identical span) is returned. This prevents infinite loops of failed expansions as well as odd double error messages in certain situations. This is a slightly better fix than #12197, because it does not produce a double error and also fixes a few other cases where an infinite loop could happen. This does not fix the other issue in #11692 (non-builtin macros not being recognised when expanded inside macros), which I think should be moved into a separate issue.
2 parents d2f265d + 0bdfd0f commit 99f8380

File tree

11 files changed

+53
-28
lines changed

11 files changed

+53
-28
lines changed

src/libsyntax/ext/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
6464
"inline assembly must be a string literal.") {
6565
Some((s, st)) => (s, st),
6666
// let compilation continue
67-
None => return MacResult::dummy_expr(),
67+
None => return MacResult::dummy_expr(sp),
6868
};
6969
asm = s;
7070
asm_str_style = Some(style);

src/libsyntax/ext/base.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ pub trait AnyMacro {
101101
fn make_stmt(&self) -> @ast::Stmt;
102102
}
103103

104+
104105
pub enum MacResult {
105106
MRExpr(@ast::Expr),
106107
MRItem(@ast::Item),
@@ -112,10 +113,15 @@ impl MacResult {
112113
/// type signatures after emitting a non-fatal error (which stop
113114
/// compilation well before the validity (or otherwise)) of the
114115
/// expression are checked.
115-
pub fn dummy_expr() -> MacResult {
116-
MRExpr(@ast::Expr {
117-
id: ast::DUMMY_NODE_ID, node: ast::ExprLogLevel, span: codemap::DUMMY_SP
118-
})
116+
pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr {
117+
@ast::Expr {
118+
id: ast::DUMMY_NODE_ID,
119+
node: ast::ExprLogLevel,
120+
span: sp
121+
}
122+
}
123+
pub fn dummy_expr(sp: codemap::Span) -> MacResult {
124+
MRExpr(MacResult::raw_dummy_expr(sp))
119125
}
120126
}
121127

src/libsyntax/ext/bytes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::char;
2121
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
2222
// Gather all argument expressions
2323
let exprs = match get_exprs_from_tts(cx, sp, tts) {
24-
None => return MacResult::dummy_expr(),
24+
None => return MacResult::dummy_expr(sp),
2525
Some(e) => e,
2626
};
2727
let mut bytes = ~[];

src/libsyntax/ext/concat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
2121
tts: &[ast::TokenTree]) -> base::MacResult {
2222
let es = match base::get_exprs_from_tts(cx, sp, tts) {
2323
Some(e) => e,
24-
None => return base::MacResult::dummy_expr()
24+
None => return base::MacResult::dummy_expr(sp)
2525
};
2626
let mut accumulator = ~"";
2727
for e in es.move_iter() {

src/libsyntax/ext/concat_idents.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
2525
ast::TTTok(_, token::COMMA) => (),
2626
_ => {
2727
cx.span_err(sp, "concat_idents! expecting comma.");
28-
return MacResult::dummy_expr();
28+
return MacResult::dummy_expr(sp);
2929
}
3030
}
3131
} else {
@@ -35,7 +35,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
3535
}
3636
_ => {
3737
cx.span_err(sp, "concat_idents! requires ident args.");
38-
return MacResult::dummy_expr();
38+
return MacResult::dummy_expr(sp);
3939
}
4040
}
4141
}

src/libsyntax/ext/env.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::os;
2626
pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
2727
-> base::MacResult {
2828
let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
29-
None => return MacResult::dummy_expr(),
29+
None => return MacResult::dummy_expr(sp),
3030
Some(v) => v
3131
};
3232

@@ -42,14 +42,14 @@ pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
4242
let exprs = match get_exprs_from_tts(cx, sp, tts) {
4343
Some([]) => {
4444
cx.span_err(sp, "env! takes 1 or 2 arguments");
45-
return MacResult::dummy_expr();
45+
return MacResult::dummy_expr(sp);
4646
}
47-
None => return MacResult::dummy_expr(),
47+
None => return MacResult::dummy_expr(sp),
4848
Some(exprs) => exprs
4949
};
5050

5151
let var = match expr_to_str(cx, exprs[0], "expected string literal") {
52-
None => return MacResult::dummy_expr(),
52+
None => return MacResult::dummy_expr(sp),
5353
Some((v, _style)) => v
5454
};
5555
let msg = match exprs.len() {
@@ -60,13 +60,13 @@ pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
6060
}
6161
2 => {
6262
match expr_to_str(cx, exprs[1], "expected string literal") {
63-
None => return MacResult::dummy_expr(),
63+
None => return MacResult::dummy_expr(sp),
6464
Some((s, _style)) => s
6565
}
6666
}
6767
_ => {
6868
cx.span_err(sp, "env! takes 1 or 2 arguments");
69-
return MacResult::dummy_expr();
69+
return MacResult::dummy_expr(sp);
7070
}
7171
};
7272

src/libsyntax/ext/expand.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
5151
format!("expected macro name without module \
5252
separators"));
5353
// let compilation continue
54-
return e;
54+
return MacResult::raw_dummy_expr(e.span);
5555
}
5656
let extname = pth.segments[0].identifier;
5757
let extnamestr = token::get_ident(extname);
@@ -64,7 +64,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
6464
extnamestr.get()));
6565

6666
// let compilation continue
67-
return e;
67+
return MacResult::raw_dummy_expr(e.span);
6868
}
6969
Some(&NormalTT(ref expandfun, exp_span)) => {
7070
fld.cx.bt_push(ExpnInfo {
@@ -98,7 +98,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
9898
extnamestr.get()
9999
)
100100
);
101-
return e;
101+
return MacResult::raw_dummy_expr(e.span);
102102
}
103103
};
104104

@@ -111,7 +111,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
111111
format!("'{}' is not a tt-style macro",
112112
extnamestr.get())
113113
);
114-
return e;
114+
return MacResult::raw_dummy_expr(e.span);
115115
}
116116
};
117117

src/libsyntax/ext/format.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
811811
expr,
812812
"format argument must be a string literal.") {
813813
Some((fmt, _)) => fmt,
814-
None => return efmt
814+
None => return MacResult::raw_dummy_expr(sp)
815815
};
816816

817817
let mut parser = parse::Parser::new(fmt.get());
@@ -829,7 +829,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
829829
match parser.errors.shift() {
830830
Some(error) => {
831831
cx.ecx.span_err(efmt.span, "invalid format string: " + error);
832-
return efmt;
832+
return MacResult::raw_dummy_expr(sp);
833833
}
834834
None => {}
835835
}

src/libsyntax/ext/source_util.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
8383
-> base::MacResult {
8484
let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
8585
Some(f) => f,
86-
None => return MacResult::dummy_expr(),
86+
None => return MacResult::dummy_expr(sp),
8787
};
8888
// The file will be added to the code map by the parser
8989
let mut p =
@@ -101,13 +101,13 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
101101
-> base::MacResult {
102102
let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
103103
Some(f) => f,
104-
None => return MacResult::dummy_expr()
104+
None => return MacResult::dummy_expr(sp)
105105
};
106106
let file = res_rel_file(cx, sp, &Path::new(file));
107107
let bytes = match File::open(&file).read_to_end() {
108108
Err(e) => {
109109
cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
110-
return MacResult::dummy_expr();
110+
return MacResult::dummy_expr(sp);
111111
}
112112
Ok(bytes) => bytes,
113113
};
@@ -123,7 +123,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
123123
}
124124
None => {
125125
cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
126-
return MacResult::dummy_expr();
126+
return MacResult::dummy_expr(sp);
127127
}
128128
}
129129
}
@@ -133,13 +133,13 @@ pub fn expand_include_bin(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
133133
{
134134
let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") {
135135
Some(f) => f,
136-
None => return MacResult::dummy_expr()
136+
None => return MacResult::dummy_expr(sp)
137137
};
138138
let file = res_rel_file(cx, sp, &Path::new(file));
139139
match File::open(&file).read_to_end() {
140140
Err(e) => {
141141
cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
142-
return MacResult::dummy_expr();
142+
return MacResult::dummy_expr(sp);
143143
}
144144
Ok(bytes) => {
145145
base::MRExpr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes))))

src/libsyntax/ext/trace_macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt,
3333
cx.set_trace_macros(false);
3434
} else {
3535
cx.span_err(sp, "trace_macros! only accepts `true` or `false`");
36-
return base::MacResult::dummy_expr();
36+
return base::MacResult::dummy_expr(sp);
3737
}
3838

3939
rust_parser.bump();

src/test/compile-fail/issue-11692.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
print!(test!());
13+
//~^ ERROR: macro undefined: 'test'
14+
//~^^ ERROR: format argument must be a string literal
15+
16+
concat!(test!());
17+
//~^ ERROR: macro undefined: 'test'
18+
//~^^ ERROR: expected a literal
19+
}

0 commit comments

Comments
 (0)