Skip to content

Commit b49a5ef

Browse files
committed
Auto merge of #23857 - phildawes:libsyntax_nopanic, r=nikomatsakis
Hello! I've been working towards a libsyntax without panics. See: http://internals.rust-lang.org/t/changing-libsyntax-to-use-result-instead-of-panic/1670 This patch changes the internals of parser.rs to use Result<> rather than panicing. It keeps the following old-style panicing functions as a facade: parse_expr, parse_item, parse_pat, parse_arm, parse_ty, parse_stmt I left these functions because I wasn't sure what to do about the quote_* macros or how many syntax-extensions would break if these and quoting macros returned Result. The gyst of the rest of the patch is: - Functions in parse/parser.rs return PResult<> rather than panicing - Other functions in libsyntax call panic! explicitly if they rely on panicing behaviour. - I added a macro 'panictry!()' to act as scaffolding for callers while converting panicing functions. (This does the same as 'unwrap()' but is easier to grep for and turn into try!()). Am I on the right track? I'd quite like to get something merged soon as keeping this rebased in the face of libsyntax changes is a lot of work. Please let me know what changes you'd like to see to make this happen. Thanks!, Phil
2 parents aab8669 + e3427c3 commit b49a5ef

23 files changed

+1397
-1318
lines changed

src/librustc/metadata/creader.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,10 @@ impl<'a> CrateReader<'a> {
528528
source_name.clone(),
529529
body);
530530
let lo = p.span.lo;
531-
let body = p.parse_all_token_trees();
531+
let body = match p.parse_all_token_trees() {
532+
Ok(body) => body,
533+
Err(err) => panic!(err),
534+
};
532535
let span = mk_sp(lo, p.last_span.hi);
533536
p.abort_if_errors();
534537
macros.push(ast::MacroDef {

src/librustc/session/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ impl Session {
6868
if self.opts.treat_err_as_bug {
6969
self.span_bug(sp, msg);
7070
}
71-
self.diagnostic().span_fatal(sp, msg)
71+
panic!(self.diagnostic().span_fatal(sp, msg))
7272
}
7373
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
7474
if self.opts.treat_err_as_bug {
7575
self.span_bug(sp, msg);
7676
}
77-
self.diagnostic().span_fatal_with_code(sp, msg, code)
77+
panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
7878
}
7979
pub fn fatal(&self, msg: &str) -> ! {
8080
if self.opts.treat_err_as_bug {

src/libsyntax/attr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -503,8 +503,8 @@ pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
503503
let name = meta.name();
504504

505505
if !set.insert(name.clone()) {
506-
diagnostic.span_fatal(meta.span,
507-
&format!("duplicate meta item `{}`", name));
506+
panic!(diagnostic.span_fatal(meta.span,
507+
&format!("duplicate meta item `{}`", name)));
508508
}
509509
}
510510
}

src/libsyntax/diagnostic.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ pub trait Emitter {
6868
sp: RenderSpan, msg: &str, lvl: Level);
6969
}
7070

71-
/// This structure is used to signify that a task has panicked with a fatal error
72-
/// from the diagnostics. You can use this with the `Any` trait to figure out
73-
/// how a rustc task died (if so desired).
71+
/// Used as a return value to signify a fatal error occurred. (It is also
72+
/// used as the argument to panic at the moment, but that will eventually
73+
/// not be true.)
7474
#[derive(Copy, Clone)]
75+
#[must_use]
7576
pub struct FatalError;
7677

7778
/// Signifies that the compiler died with an explicit call to `.bug`
@@ -88,13 +89,13 @@ pub struct SpanHandler {
8889
}
8990

9091
impl SpanHandler {
91-
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
92+
pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError {
9293
self.handler.emit(Some((&self.cm, sp)), msg, Fatal);
93-
panic!(FatalError);
94+
return FatalError;
9495
}
95-
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
96+
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError {
9697
self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Fatal);
97-
panic!(FatalError);
98+
return FatalError;
9899
}
99100
pub fn span_err(&self, sp: Span, msg: &str) {
100101
self.handler.emit(Some((&self.cm, sp)), msg, Error);

src/libsyntax/ext/asm.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,16 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
9191
p.token != token::ModSep {
9292

9393
if outputs.len() != 0 {
94-
p.eat(&token::Comma);
94+
panictry!(p.eat(&token::Comma));
9595
}
9696

97-
let (constraint, _str_style) = p.parse_str();
97+
let (constraint, _str_style) = panictry!(p.parse_str());
9898

9999
let span = p.last_span;
100100

101-
p.expect(&token::OpenDelim(token::Paren));
101+
panictry!(p.expect(&token::OpenDelim(token::Paren)));
102102
let out = p.parse_expr();
103-
p.expect(&token::CloseDelim(token::Paren));
103+
panictry!(p.expect(&token::CloseDelim(token::Paren)));
104104

105105
// Expands a read+write operand into two operands.
106106
//
@@ -131,20 +131,20 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
131131
p.token != token::ModSep {
132132

133133
if inputs.len() != 0 {
134-
p.eat(&token::Comma);
134+
panictry!(p.eat(&token::Comma));
135135
}
136136

137-
let (constraint, _str_style) = p.parse_str();
137+
let (constraint, _str_style) = panictry!(p.parse_str());
138138

139139
if constraint.starts_with("=") {
140140
cx.span_err(p.last_span, "input operand constraint contains '='");
141141
} else if constraint.starts_with("+") {
142142
cx.span_err(p.last_span, "input operand constraint contains '+'");
143143
}
144144

145-
p.expect(&token::OpenDelim(token::Paren));
145+
panictry!(p.expect(&token::OpenDelim(token::Paren)));
146146
let input = p.parse_expr();
147-
p.expect(&token::CloseDelim(token::Paren));
147+
panictry!(p.expect(&token::CloseDelim(token::Paren)));
148148

149149
inputs.push((constraint, input));
150150
}
@@ -155,10 +155,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
155155
p.token != token::ModSep {
156156

157157
if clobs.len() != 0 {
158-
p.eat(&token::Comma);
158+
panictry!(p.eat(&token::Comma));
159159
}
160160

161-
let (s, _str_style) = p.parse_str();
161+
let (s, _str_style) = panictry!(p.parse_str());
162162

163163
if OPTIONS.iter().any(|&opt| s == opt) {
164164
cx.span_warn(p.last_span, "expected a clobber, found an option");
@@ -167,7 +167,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
167167
}
168168
}
169169
Options => {
170-
let (option, _str_style) = p.parse_str();
170+
let (option, _str_style) = panictry!(p.parse_str());
171171

172172
if option == "volatile" {
173173
// Indicates that the inline assembly has side effects
@@ -182,7 +182,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
182182
}
183183

184184
if p.token == token::Comma {
185-
p.eat(&token::Comma);
185+
panictry!(p.eat(&token::Comma));
186186
}
187187
}
188188
StateNone => ()
@@ -194,12 +194,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
194194
match (&p.token, state.next(), state.next().next()) {
195195
(&token::Colon, StateNone, _) |
196196
(&token::ModSep, _, StateNone) => {
197-
p.bump();
197+
panictry!(p.bump());
198198
break 'statement;
199199
}
200200
(&token::Colon, st, _) |
201201
(&token::ModSep, _, st) => {
202-
p.bump();
202+
panictry!(p.bump());
203203
state = st;
204204
}
205205
(&token::Eof, _, _) => break 'statement,

src/libsyntax/ext/base.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -652,9 +652,9 @@ impl<'a> ExtCtxt<'a> {
652652
pub fn bt_push(&mut self, ei: ExpnInfo) {
653653
self.recursion_count += 1;
654654
if self.recursion_count > self.ecfg.recursion_limit {
655-
self.span_fatal(ei.call_site,
655+
panic!(self.span_fatal(ei.call_site,
656656
&format!("recursion limit reached while expanding the macro `{}`",
657-
ei.callee.name));
657+
ei.callee.name)));
658658
}
659659

660660
let mut call_site = ei.call_site;
@@ -699,7 +699,7 @@ impl<'a> ExtCtxt<'a> {
699699
/// value doesn't have to match anything)
700700
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
701701
self.print_backtrace();
702-
self.parse_sess.span_diagnostic.span_fatal(sp, msg);
702+
panic!(self.parse_sess.span_diagnostic.span_fatal(sp, msg));
703703
}
704704

705705
/// Emit `msg` attached to `sp`, without immediately stopping
@@ -817,7 +817,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
817817
let mut es = Vec::new();
818818
while p.token != token::Eof {
819819
es.push(cx.expander().fold_expr(p.parse_expr()));
820-
if p.eat(&token::Comma) {
820+
if panictry!(p.eat(&token::Comma)){
821821
continue;
822822
}
823823
if p.token != token::Eof {

src/libsyntax/ext/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
2929
let mut p = cx.new_parser_from_tts(tts);
3030
let cfg = p.parse_meta_item();
3131

32-
if !p.eat(&token::Eof) {
32+
if !panictry!(p.eat(&token::Eof)){
3333
cx.span_err(sp, "expected 1 cfg-pattern");
3434
return DummyResult::expr(sp);
3535
}

src/libsyntax/ext/expand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1684,7 +1684,7 @@ mod test {
16841684

16851685
fn expand_crate_str(crate_str: String) -> ast::Crate {
16861686
let ps = parse::new_parse_sess();
1687-
let crate_ast = string_to_parser(&ps, crate_str).parse_crate_mod();
1687+
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
16881688
// the cfg argument actually does matter, here...
16891689
expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast)
16901690
}

src/libsyntax/ext/format.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
9292
let fmtstr = p.parse_expr();
9393
let mut named = false;
9494
while p.token != token::Eof {
95-
if !p.eat(&token::Comma) {
95+
if !panictry!(p.eat(&token::Comma)) {
9696
ecx.span_err(sp, "expected token: `,`");
9797
return None;
9898
}
@@ -101,7 +101,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
101101
named = true;
102102
let ident = match p.token {
103103
token::Ident(i, _) => {
104-
p.bump();
104+
panictry!(p.bump());
105105
i
106106
}
107107
_ if named => {
@@ -120,7 +120,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
120120
let interned_name = token::get_ident(ident);
121121
let name = &interned_name[..];
122122

123-
p.expect(&token::Eq);
123+
panictry!(p.expect(&token::Eq));
124124
let e = p.parse_expr();
125125
match names.get(name) {
126126
None => {}

src/libsyntax/ext/quote.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -781,11 +781,11 @@ fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[ast::TokenTree])
781781
p.quote_depth += 1;
782782

783783
let cx_expr = p.parse_expr();
784-
if !p.eat(&token::Comma) {
785-
p.fatal("expected token `,`");
784+
if !panictry!(p.eat(&token::Comma)) {
785+
panic!(p.fatal("expected token `,`"));
786786
}
787787

788-
let tts = p.parse_all_token_trees();
788+
let tts = panictry!(p.parse_all_token_trees());
789789
p.abort_if_errors();
790790

791791
(cx_expr, tts)

src/libsyntax/ext/source_util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree
117117
while self.p.token != token::Eof {
118118
match self.p.parse_item() {
119119
Some(item) => ret.push(item),
120-
None => self.p.span_fatal(
120+
None => panic!(self.p.span_fatal(
121121
self.p.span,
122122
&format!("expected item, found `{}`",
123123
self.p.this_token_to_string())
124-
)
124+
))
125125
}
126126
}
127127
Some(ret)

src/libsyntax/ext/tt/macro_parser.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
226226
}
227227
Occupied(..) => {
228228
let string = token::get_ident(bind_name);
229-
p_s.span_diagnostic
229+
panic!(p_s.span_diagnostic
230230
.span_fatal(sp,
231231
&format!("duplicated bind name: {}",
232-
&string))
232+
&string)))
233233
}
234234
}
235235
}
@@ -260,10 +260,10 @@ pub fn parse_or_else(sess: &ParseSess,
260260
match parse(sess, cfg, rdr, &ms[..]) {
261261
Success(m) => m,
262262
Failure(sp, str) => {
263-
sess.span_diagnostic.span_fatal(sp, &str[..])
263+
panic!(sess.span_diagnostic.span_fatal(sp, &str[..]))
264264
}
265265
Error(sp, str) => {
266-
sess.span_diagnostic.span_fatal(sp, &str[..])
266+
panic!(sess.span_diagnostic.span_fatal(sp, &str[..]))
267267
}
268268
}
269269
}
@@ -512,46 +512,46 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
512512
match name {
513513
"tt" => {
514514
p.quote_depth += 1; //but in theory, non-quoted tts might be useful
515-
let res = token::NtTT(P(p.parse_token_tree()));
515+
let res = token::NtTT(P(panictry!(p.parse_token_tree())));
516516
p.quote_depth -= 1;
517517
return res;
518518
}
519519
_ => {}
520520
}
521521
// check at the beginning and the parser checks after each bump
522-
p.check_unknown_macro_variable();
522+
panictry!(p.check_unknown_macro_variable());
523523
match name {
524524
"item" => match p.parse_item() {
525525
Some(i) => token::NtItem(i),
526-
None => p.fatal("expected an item keyword")
526+
None => panic!(p.fatal("expected an item keyword"))
527527
},
528-
"block" => token::NtBlock(p.parse_block()),
528+
"block" => token::NtBlock(panictry!(p.parse_block())),
529529
"stmt" => match p.parse_stmt() {
530530
Some(s) => token::NtStmt(s),
531-
None => p.fatal("expected a statement")
531+
None => panic!(p.fatal("expected a statement"))
532532
},
533533
"pat" => token::NtPat(p.parse_pat()),
534534
"expr" => token::NtExpr(p.parse_expr()),
535535
"ty" => token::NtTy(p.parse_ty()),
536536
// this could be handled like a token, since it is one
537537
"ident" => match p.token {
538-
token::Ident(sn,b) => { p.bump(); token::NtIdent(box sn,b) }
538+
token::Ident(sn,b) => { panictry!(p.bump()); token::NtIdent(box sn,b) }
539539
_ => {
540540
let token_str = pprust::token_to_string(&p.token);
541-
p.fatal(&format!("expected ident, found {}",
542-
&token_str[..]))
541+
panic!(p.fatal(&format!("expected ident, found {}",
542+
&token_str[..])))
543543
}
544544
},
545545
"path" => {
546-
token::NtPath(box p.parse_path(LifetimeAndTypesWithoutColons))
546+
token::NtPath(box panictry!(p.parse_path(LifetimeAndTypesWithoutColons)))
547547
}
548548
"meta" => token::NtMeta(p.parse_meta_item()),
549549
_ => {
550-
p.span_fatal_help(sp,
550+
panic!(p.span_fatal_help(sp,
551551
&format!("invalid fragment specifier `{}`", name),
552552
"valid fragment specifiers are `ident`, `block`, \
553553
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
554-
and `item`")
554+
and `item`"))
555555
}
556556
}
557557
}

0 commit comments

Comments
 (0)