1
Fork 0

Don't panic for fatal errors in attribute parsing.

This commit is contained in:
Eli Friedman 2015-10-23 19:02:38 -07:00
parent c141f47c24
commit de95857129
5 changed files with 56 additions and 54 deletions

View file

@ -26,7 +26,7 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
tts: &[ast::TokenTree]) tts: &[ast::TokenTree])
-> Box<base::MacResult+'static> { -> Box<base::MacResult+'static> {
let mut p = cx.new_parser_from_tts(tts); let mut p = cx.new_parser_from_tts(tts);
let cfg = p.parse_meta_item(); let cfg = panictry!(p.parse_meta_item());
if !panictry!(p.eat(&token::Eof)){ if !panictry!(p.eat(&token::Eof)){
cx.span_err(sp, "expected 1 cfg-pattern"); cx.span_err(sp, "expected 1 cfg-pattern");

View file

@ -526,7 +526,7 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
"path" => { "path" => {
token::NtPath(Box::new(panictry!(p.parse_path(LifetimeAndTypesWithoutColons)))) token::NtPath(Box::new(panictry!(p.parse_path(LifetimeAndTypesWithoutColons))))
}, },
"meta" => token::NtMeta(p.parse_meta_item()), "meta" => token::NtMeta(panictry!(p.parse_meta_item())),
_ => { _ => {
panic!(p.span_fatal_help(sp, panic!(p.span_fatal_help(sp,
&format!("invalid fragment specifier `{}`", name), &format!("invalid fragment specifier `{}`", name),

View file

@ -12,20 +12,21 @@ use attr;
use ast; use ast;
use codemap::{spanned, Spanned, mk_sp, Span}; use codemap::{spanned, Spanned, mk_sp, Span};
use parse::common::*; //resolve bug? use parse::common::*; //resolve bug?
use parse::PResult;
use parse::token; use parse::token;
use parse::parser::{Parser, TokenType}; use parse::parser::{Parser, TokenType};
use ptr::P; use ptr::P;
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// Parse attributes that appear before an item /// Parse attributes that appear before an item
pub fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> { pub fn parse_outer_attributes(&mut self) -> PResult<Vec<ast::Attribute>> {
let mut attrs: Vec<ast::Attribute> = Vec::new(); let mut attrs: Vec<ast::Attribute> = Vec::new();
loop { loop {
debug!("parse_outer_attributes: self.token={:?}", debug!("parse_outer_attributes: self.token={:?}",
self.token); self.token);
match self.token { match self.token {
token::Pound => { token::Pound => {
attrs.push(self.parse_attribute(false)); attrs.push(try!(self.parse_attribute(false)));
} }
token::DocComment(s) => { token::DocComment(s) => {
let attr = ::attr::mk_sugared_doc_attr( let attr = ::attr::mk_sugared_doc_attr(
@ -35,32 +36,32 @@ impl<'a> Parser<'a> {
self.span.hi self.span.hi
); );
if attr.node.style != ast::AttrStyle::Outer { if attr.node.style != ast::AttrStyle::Outer {
panic!(self.fatal("expected outer comment")); return Err(self.fatal("expected outer comment"));
} }
attrs.push(attr); attrs.push(attr);
panictry!(self.bump()); try!(self.bump());
} }
_ => break _ => break
} }
} }
return attrs; return Ok(attrs);
} }
/// Matches `attribute = # ! [ meta_item ]` /// Matches `attribute = # ! [ meta_item ]`
/// ///
/// If permit_inner is true, then a leading `!` indicates an inner /// If permit_inner is true, then a leading `!` indicates an inner
/// attribute /// attribute
fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute { fn parse_attribute(&mut self, permit_inner: bool) -> PResult<ast::Attribute> {
debug!("parse_attributes: permit_inner={:?} self.token={:?}", debug!("parse_attributes: permit_inner={:?} self.token={:?}",
permit_inner, self.token); permit_inner, self.token);
let (span, value, mut style) = match self.token { let (span, value, mut style) = match self.token {
token::Pound => { token::Pound => {
let lo = self.span.lo; let lo = self.span.lo;
panictry!(self.bump()); try!(self.bump());
if permit_inner { self.expected_tokens.push(TokenType::Token(token::Not)); } if permit_inner { self.expected_tokens.push(TokenType::Token(token::Not)); }
let style = if self.token == token::Not { let style = if self.token == token::Not {
panictry!(self.bump()); try!(self.bump());
if !permit_inner { if !permit_inner {
let span = self.span; let span = self.span;
self.span_err(span, self.span_err(span,
@ -74,27 +75,27 @@ impl<'a> Parser<'a> {
ast::AttrStyle::Outer ast::AttrStyle::Outer
}; };
panictry!(self.expect(&token::OpenDelim(token::Bracket))); try!(self.expect(&token::OpenDelim(token::Bracket)));
let meta_item = self.parse_meta_item(); let meta_item = try!(self.parse_meta_item());
let hi = self.span.hi; let hi = self.span.hi;
panictry!(self.expect(&token::CloseDelim(token::Bracket))); try!(self.expect(&token::CloseDelim(token::Bracket)));
(mk_sp(lo, hi), meta_item, style) (mk_sp(lo, hi), meta_item, style)
} }
_ => { _ => {
let token_str = self.this_token_to_string(); let token_str = self.this_token_to_string();
panic!(self.fatal(&format!("expected `#`, found `{}`", token_str))); return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
} }
}; };
if permit_inner && self.token == token::Semi { if permit_inner && self.token == token::Semi {
panictry!(self.bump()); try!(self.bump());
self.span_warn(span, "this inner attribute syntax is deprecated. \ self.span_warn(span, "this inner attribute syntax is deprecated. \
The new syntax is `#![foo]`, with a bang and no semicolon"); The new syntax is `#![foo]`, with a bang and no semicolon");
style = ast::AttrStyle::Inner; style = ast::AttrStyle::Inner;
} }
return Spanned { Ok(Spanned {
span: span, span: span,
node: ast::Attribute_ { node: ast::Attribute_ {
id: attr::mk_attr_id(), id: attr::mk_attr_id(),
@ -102,7 +103,7 @@ impl<'a> Parser<'a> {
value: value, value: value,
is_sugared_doc: false is_sugared_doc: false
} }
}; })
} }
/// Parse attributes that appear after the opening of an item. These should /// Parse attributes that appear after the opening of an item. These should
@ -110,7 +111,7 @@ impl<'a> Parser<'a> {
/// terminated by a semicolon. /// terminated by a semicolon.
/// matches inner_attrs* /// matches inner_attrs*
pub fn parse_inner_attributes(&mut self) -> Vec<ast::Attribute> { pub fn parse_inner_attributes(&mut self) -> PResult<Vec<ast::Attribute>> {
let mut attrs: Vec<ast::Attribute> = vec![]; let mut attrs: Vec<ast::Attribute> = vec![];
loop { loop {
match self.token { match self.token {
@ -120,7 +121,7 @@ impl<'a> Parser<'a> {
break; break;
} }
let attr = self.parse_attribute(true); let attr = try!(self.parse_attribute(true));
assert!(attr.node.style == ast::AttrStyle::Inner); assert!(attr.node.style == ast::AttrStyle::Inner);
attrs.push(attr); attrs.push(attr);
} }
@ -131,7 +132,7 @@ impl<'a> Parser<'a> {
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), str, lo, hi); let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), str, lo, hi);
if attr.node.style == ast::AttrStyle::Inner { if attr.node.style == ast::AttrStyle::Inner {
attrs.push(attr); attrs.push(attr);
panictry!(self.bump()); try!(self.bump());
} else { } else {
break; break;
} }
@ -139,13 +140,13 @@ impl<'a> Parser<'a> {
_ => break _ => break
} }
} }
attrs Ok(attrs)
} }
/// matches meta_item = IDENT /// matches meta_item = IDENT
/// | IDENT = lit /// | IDENT = lit
/// | IDENT meta_seq /// | IDENT meta_seq
pub fn parse_meta_item(&mut self) -> P<ast::MetaItem> { pub fn parse_meta_item(&mut self) -> PResult<P<ast::MetaItem>> {
let nt_meta = match self.token { let nt_meta = match self.token {
token::Interpolated(token::NtMeta(ref e)) => { token::Interpolated(token::NtMeta(ref e)) => {
Some(e.clone()) Some(e.clone())
@ -155,19 +156,19 @@ impl<'a> Parser<'a> {
match nt_meta { match nt_meta {
Some(meta) => { Some(meta) => {
panictry!(self.bump()); try!(self.bump());
return meta; return Ok(meta);
} }
None => {} None => {}
} }
let lo = self.span.lo; let lo = self.span.lo;
let ident = panictry!(self.parse_ident()); let ident = try!(self.parse_ident());
let name = self.id_to_interned_str(ident); let name = self.id_to_interned_str(ident);
match self.token { match self.token {
token::Eq => { token::Eq => {
panictry!(self.bump()); try!(self.bump());
let lit = panictry!(self.parse_lit()); let lit = try!(self.parse_lit());
// FIXME #623 Non-string meta items are not serialized correctly; // FIXME #623 Non-string meta items are not serialized correctly;
// just forbid them for now // just forbid them for now
match lit.node { match lit.node {
@ -179,25 +180,25 @@ impl<'a> Parser<'a> {
} }
} }
let hi = self.span.hi; let hi = self.span.hi;
P(spanned(lo, hi, ast::MetaNameValue(name, lit))) Ok(P(spanned(lo, hi, ast::MetaNameValue(name, lit))))
} }
token::OpenDelim(token::Paren) => { token::OpenDelim(token::Paren) => {
let inner_items = self.parse_meta_seq(); let inner_items = try!(self.parse_meta_seq());
let hi = self.span.hi; let hi = self.span.hi;
P(spanned(lo, hi, ast::MetaList(name, inner_items))) Ok(P(spanned(lo, hi, ast::MetaList(name, inner_items))))
} }
_ => { _ => {
let hi = self.last_span.hi; let hi = self.last_span.hi;
P(spanned(lo, hi, ast::MetaWord(name))) Ok(P(spanned(lo, hi, ast::MetaWord(name))))
} }
} }
} }
/// matches meta_seq = ( COMMASEP(meta_item) ) /// matches meta_seq = ( COMMASEP(meta_item) )
fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>> { fn parse_meta_seq(&mut self) -> PResult<Vec<P<ast::MetaItem>>> {
panictry!(self.parse_seq(&token::OpenDelim(token::Paren), self.parse_unspanned_seq(&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren), &token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma), seq_sep_trailing_allowed(token::Comma),
|p| Ok(p.parse_meta_item()))).node |p| p.parse_meta_item())
} }
} }

View file

@ -82,7 +82,8 @@ pub fn parse_crate_attrs_from_file(
cfg: ast::CrateConfig, cfg: ast::CrateConfig,
sess: &ParseSess sess: &ParseSess
) -> Vec<ast::Attribute> { ) -> Vec<ast::Attribute> {
new_parser_from_file(sess, cfg, input).parse_inner_attributes() // FIXME: maybe_aborted?
panictry!(new_parser_from_file(sess, cfg, input).parse_inner_attributes())
} }
pub fn parse_crate_from_source_str(name: String, pub fn parse_crate_from_source_str(name: String,
@ -106,7 +107,7 @@ pub fn parse_crate_attrs_from_source_str(name: String,
cfg, cfg,
name, name,
source); source);
maybe_aborted(p.parse_inner_attributes(), p) maybe_aborted(panictry!(p.parse_inner_attributes()), p)
} }
pub fn parse_expr_from_source_str(name: String, pub fn parse_expr_from_source_str(name: String,
@ -133,7 +134,7 @@ pub fn parse_meta_from_source_str(name: String,
sess: &ParseSess) sess: &ParseSess)
-> P<ast::MetaItem> { -> P<ast::MetaItem> {
let mut p = new_parser_from_source_str(sess, cfg, name, source); let mut p = new_parser_from_source_str(sess, cfg, name, source);
maybe_aborted(p.parse_meta_item(), p) maybe_aborted(panictry!(p.parse_meta_item()), p)
} }
pub fn parse_stmt_from_source_str(name: String, pub fn parse_stmt_from_source_str(name: String,

View file

@ -1174,7 +1174,7 @@ impl<'a> Parser<'a> {
seq_sep_none(), seq_sep_none(),
|p| -> PResult<P<TraitItem>> { |p| -> PResult<P<TraitItem>> {
maybe_whole!(no_clone p, NtTraitItem); maybe_whole!(no_clone p, NtTraitItem);
let mut attrs = p.parse_outer_attributes(); let mut attrs = try!(p.parse_outer_attributes());
let lo = p.span.lo; let lo = p.span.lo;
let (name, node) = if try!(p.eat_keyword(keywords::Type)) { let (name, node) = if try!(p.eat_keyword(keywords::Type)) {
@ -2956,7 +2956,7 @@ impl<'a> Parser<'a> {
pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> { pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
maybe_whole!(no_clone self, NtArm); maybe_whole!(no_clone self, NtArm);
let attrs = self.parse_outer_attributes(); let attrs = try!(self.parse_outer_attributes());
let pats = try!(self.parse_pats()); let pats = try!(self.parse_pats());
let mut guard = None; let mut guard = None;
if try!(self.eat_keyword(keywords::If) ){ if try!(self.eat_keyword(keywords::If) ){
@ -3465,7 +3465,7 @@ impl<'a> Parser<'a> {
} }
} }
let attrs = self.parse_outer_attributes(); let attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo; let lo = self.span.lo;
Ok(Some(if self.check_keyword(keywords::Let) { Ok(Some(if self.check_keyword(keywords::Let) {
@ -3607,7 +3607,7 @@ impl<'a> Parser<'a> {
let lo = self.span.lo; let lo = self.span.lo;
try!(self.expect(&token::OpenDelim(token::Brace))); try!(self.expect(&token::OpenDelim(token::Brace)));
Ok((self.parse_inner_attributes(), Ok((try!(self.parse_inner_attributes()),
try!(self.parse_block_tail(lo, DefaultBlock)))) try!(self.parse_block_tail(lo, DefaultBlock))))
} }
@ -4431,7 +4431,7 @@ impl<'a> Parser<'a> {
pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> { pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
maybe_whole!(no_clone self, NtImplItem); maybe_whole!(no_clone self, NtImplItem);
let mut attrs = self.parse_outer_attributes(); let mut attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo; let lo = self.span.lo;
let vis = try!(self.parse_visibility()); let vis = try!(self.parse_visibility());
let (name, node) = if try!(self.eat_keyword(keywords::Type)) { let (name, node) = if try!(self.eat_keyword(keywords::Type)) {
@ -4608,7 +4608,7 @@ impl<'a> Parser<'a> {
generics.where_clause = try!(self.parse_where_clause()); generics.where_clause = try!(self.parse_where_clause());
try!(self.expect(&token::OpenDelim(token::Brace))); try!(self.expect(&token::OpenDelim(token::Brace)));
let attrs = self.parse_inner_attributes(); let attrs = try!(self.parse_inner_attributes());
let mut impl_items = vec![]; let mut impl_items = vec![];
while !try!(self.eat(&token::CloseDelim(token::Brace))) { while !try!(self.eat(&token::CloseDelim(token::Brace))) {
@ -4727,7 +4727,7 @@ impl<'a> Parser<'a> {
&token::CloseDelim(token::Paren), &token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma), seq_sep_trailing_allowed(token::Comma),
|p| { |p| {
let attrs = p.parse_outer_attributes(); let attrs = try!(p.parse_outer_attributes());
let lo = p.span.lo; let lo = p.span.lo;
let struct_field_ = ast::StructField_ { let struct_field_ = ast::StructField_ {
kind: UnnamedField(try!(p.parse_visibility())), kind: UnnamedField(try!(p.parse_visibility())),
@ -4769,7 +4769,7 @@ impl<'a> Parser<'a> {
/// Parse an element of a struct definition /// Parse an element of a struct definition
fn parse_struct_decl_field(&mut self, allow_pub: bool) -> PResult<StructField> { fn parse_struct_decl_field(&mut self, allow_pub: bool) -> PResult<StructField> {
let attrs = self.parse_outer_attributes(); let attrs = try!(self.parse_outer_attributes());
if try!(self.eat_keyword(keywords::Pub) ){ if try!(self.eat_keyword(keywords::Pub) ){
if !allow_pub { if !allow_pub {
@ -4841,7 +4841,7 @@ impl<'a> Parser<'a> {
let mod_inner_lo = self.span.lo; let mod_inner_lo = self.span.lo;
let old_owns_directory = self.owns_directory; let old_owns_directory = self.owns_directory;
self.owns_directory = true; self.owns_directory = true;
let attrs = self.parse_inner_attributes(); let attrs = try!(self.parse_inner_attributes());
let m = try!(self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)); let m = try!(self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo));
self.owns_directory = old_owns_directory; self.owns_directory = old_owns_directory;
self.pop_mod_path(); self.pop_mod_path();
@ -4990,7 +4990,7 @@ impl<'a> Parser<'a> {
Some(name), Some(name),
id_sp); id_sp);
let mod_inner_lo = p0.span.lo; let mod_inner_lo = p0.span.lo;
let mod_attrs = p0.parse_inner_attributes(); let mod_attrs = try!(p0.parse_inner_attributes());
let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo)); let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo));
self.sess.included_mod_stack.borrow_mut().pop(); self.sess.included_mod_stack.borrow_mut().pop();
Ok((ast::ItemMod(m0), mod_attrs)) Ok((ast::ItemMod(m0), mod_attrs))
@ -5093,7 +5093,7 @@ impl<'a> Parser<'a> {
let abi = opt_abi.unwrap_or(abi::C); let abi = opt_abi.unwrap_or(abi::C);
attrs.extend(self.parse_inner_attributes()); attrs.extend(try!(self.parse_inner_attributes()));
let mut foreign_items = vec![]; let mut foreign_items = vec![];
while let Some(item) = try!(self.parse_foreign_item()) { while let Some(item) = try!(self.parse_foreign_item()) {
@ -5143,7 +5143,7 @@ impl<'a> Parser<'a> {
let mut all_nullary = true; let mut all_nullary = true;
let mut any_disr = None; let mut any_disr = None;
while self.token != token::CloseDelim(token::Brace) { while self.token != token::CloseDelim(token::Brace) {
let variant_attrs = self.parse_outer_attributes(); let variant_attrs = try!(self.parse_outer_attributes());
let vlo = self.span.lo; let vlo = self.span.lo;
let struct_def; let struct_def;
@ -5505,7 +5505,7 @@ impl<'a> Parser<'a> {
/// Parse a foreign item. /// Parse a foreign item.
fn parse_foreign_item(&mut self) -> PResult<Option<P<ForeignItem>>> { fn parse_foreign_item(&mut self) -> PResult<Option<P<ForeignItem>>> {
let attrs = self.parse_outer_attributes(); let attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo; let lo = self.span.lo;
let visibility = try!(self.parse_visibility()); let visibility = try!(self.parse_visibility());
@ -5605,7 +5605,7 @@ impl<'a> Parser<'a> {
} }
pub fn parse_item_nopanic(&mut self) -> PResult<Option<P<Item>>> { pub fn parse_item_nopanic(&mut self) -> PResult<Option<P<Item>>> {
let attrs = self.parse_outer_attributes(); let attrs = try!(self.parse_outer_attributes());
self.parse_item_(attrs, true) self.parse_item_(attrs, true)
} }
@ -5724,7 +5724,7 @@ impl<'a> Parser<'a> {
pub fn parse_crate_mod(&mut self) -> PResult<Crate> { pub fn parse_crate_mod(&mut self) -> PResult<Crate> {
let lo = self.span.lo; let lo = self.span.lo;
Ok(ast::Crate { Ok(ast::Crate {
attrs: self.parse_inner_attributes(), attrs: try!(self.parse_inner_attributes()),
module: try!(self.parse_mod_items(&token::Eof, lo)), module: try!(self.parse_mod_items(&token::Eof, lo)),
config: self.cfg.clone(), config: self.cfg.clone(),
span: mk_sp(lo, self.span.lo), span: mk_sp(lo, self.span.lo),