about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonas Schievink <jonas@schievink.net>2015-11-25 20:58:57 +0100
committerJonas Schievink <jonas@schievink.net>2015-11-25 20:58:57 +0100
commitfc9f9882f351b0823b2e3f140cf28c76bc8787b7 (patch)
treee5cc1d9145532debe19fc6b34bae1dc96529047e
parent1b9a13e6ba83a5619b628c1534b1c6d566157f62 (diff)
downloadrust-fc9f9882f351b0823b2e3f140cf28c76bc8787b7.tar.gz
rust-fc9f9882f351b0823b2e3f140cf28c76bc8787b7.zip
Fix "Cannot fill in a NT" ICE
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs35
1 files changed, 23 insertions, 12 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 675482fd644..5b8307eb6c6 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -200,18 +200,19 @@ pub enum NamedMatch {
 }
 
 pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
-            -> HashMap<Name, Rc<NamedMatch>> {
+            -> ParseResult<HashMap<Name, Rc<NamedMatch>>> {
     fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc<NamedMatch>],
-             ret_val: &mut HashMap<Name, Rc<NamedMatch>>, idx: &mut usize) {
+             ret_val: &mut HashMap<Name, Rc<NamedMatch>>, idx: &mut usize)
+             -> Result<(), (codemap::Span, String)> {
         match *m {
             TokenTree::Sequence(_, ref seq) => {
                 for next_m in &seq.tts {
-                    n_rec(p_s, next_m, res, ret_val, idx)
+                    try!(n_rec(p_s, next_m, res, ret_val, idx))
                 }
             }
             TokenTree::Delimited(_, ref delim) => {
                 for next_m in &delim.tts {
-                    n_rec(p_s, next_m, res, ret_val, idx)
+                    try!(n_rec(p_s, next_m, res, ret_val, idx));
                 }
             }
             TokenTree::Token(sp, MatchNt(bind_name, _, _, _)) => {
@@ -221,26 +222,36 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
                         *idx += 1;
                     }
                     Occupied(..) => {
-                        panic!(p_s.span_diagnostic
-                           .span_fatal(sp,
-                                       &format!("duplicated bind name: {}",
-                                               bind_name)))
+                        return Err((sp, format!("duplicated bind name: {}", bind_name)))
                     }
                 }
             }
-            TokenTree::Token(_, SubstNt(..)) => panic!("Cannot fill in a NT"),
+            TokenTree::Token(sp, SubstNt(..)) => {
+                return Err((sp, "missing fragment specifier".to_string()))
+            }
             TokenTree::Token(_, _) => (),
         }
+
+        Ok(())
     }
+
     let mut ret_val = HashMap::new();
     let mut idx = 0;
-    for m in ms { n_rec(p_s, m, res, &mut ret_val, &mut idx) }
-    ret_val
+    for m in ms {
+        match n_rec(p_s, m, res, &mut ret_val, &mut idx) {
+            Ok(_) => {},
+            Err((sp, msg)) => return Error(sp, msg),
+        }
+    }
+
+    Success(ret_val)
 }
 
 pub enum ParseResult<T> {
     Success(T),
+    /// Arm failed to match
     Failure(codemap::Span, String),
+    /// Fatal error (malformed macro?). Abort compilation.
     Error(codemap::Span, String)
 }
 
@@ -429,7 +440,7 @@ pub fn parse(sess: &ParseSess,
                 for dv in &mut (&mut eof_eis[0]).matches {
                     v.push(dv.pop().unwrap());
                 }
-                return Success(nameize(sess, ms, &v[..]));
+                return nameize(sess, ms, &v[..]);
             } else if eof_eis.len() > 1 {
                 return Error(sp, "ambiguity: multiple successful parses".to_string());
             } else {