diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 582873082a68b..1f79db9e5232b 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -29,7 +29,7 @@ use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef};
 use middle::ty_fold::TypeFoldable;
 use std::collections::HashMap;
 use std::fmt;
-use syntax::codemap::{DUMMY_SP, Span};
+use syntax::codemap::Span;
 use syntax::attr::{AttributeMethods, AttrMetaMethods};
 
 pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
@@ -81,11 +81,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
     let mut report = None;
     for item in infcx.tcx.get_attrs(def_id).iter() {
         if item.check_name("rustc_on_unimplemented") {
-            let err_sp = if item.meta().span == DUMMY_SP {
-                span
-            } else {
-                item.meta().span
-            };
+            let err_sp = item.meta().span.substitute_dummy(span);
             let def = infcx.tcx.lookup_trait_def(def_id);
             let trait_str = def.trait_ref.to_string();
             if let Some(ref istring) = item.value_str() {
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 17e6b2c2e12df..0aeb572b6bcf6 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -135,6 +135,13 @@ pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0),
                                          hi: BytePos(0),
                                          expn_id: COMMAND_LINE_EXPN };
 
+impl Span {
+    /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
+    pub fn substitute_dummy(self, other: Span) -> Span {
+        if self == DUMMY_SP { other } else { self }
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub struct Spanned<T> {
     pub node: T,
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 4556bd5f8e590..26b4181ea8a66 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -249,22 +249,6 @@ pub enum ParseResult<T> {
 pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
 pub type PositionalParseResult = ParseResult<Vec<Rc<NamedMatch>>>;
 
-pub fn parse_or_else(sess: &ParseSess,
-                     cfg: ast::CrateConfig,
-                     rdr: TtReader,
-                     ms: Vec<TokenTree> )
-                     -> HashMap<Ident, Rc<NamedMatch>> {
-    match parse(sess, cfg, rdr, &ms[..]) {
-        Success(m) => m,
-        Failure(sp, str) => {
-            panic!(sess.span_diagnostic.span_fatal(sp, &str[..]))
-        }
-        Error(sp, str) => {
-            panic!(sess.span_diagnostic.span_fatal(sp, &str[..]))
-        }
-    }
-}
-
 /// Perform a token equality check, ignoring syntax context (that is, an
 /// unhygienic comparison)
 pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index d16fde7bc394e..d728fa59bd1df 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -14,7 +14,7 @@ use ext::base::{ExtCtxt, MacResult, SyntaxExtension};
 use ext::base::{NormalTT, TTMacroExpander};
 use ext::tt::macro_parser::{Success, Error, Failure};
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
-use ext::tt::macro_parser::{parse, parse_or_else};
+use ext::tt::macro_parser::parse;
 use parse::lexer::new_tt_reader;
 use parse::parser::Parser;
 use parse::token::{self, special_idents, gensym_ident, NtTT, Token};
@@ -211,13 +211,16 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 best_fail_spot = sp;
                 best_fail_msg = (*msg).clone();
               },
-              Error(sp, ref msg) => panic!(cx.span_fatal(sp, &msg[..]))
+              Error(err_sp, ref msg) => {
+                panic!(cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]))
+              }
             }
           }
           _ => cx.bug("non-matcher found in parsed lhses")
         }
     }
-    panic!(cx.span_fatal(best_fail_spot, &best_fail_msg[..]));
+
+    panic!(cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]));
 }
 
 // Note that macro-by-example's input is also matched against a token tree:
@@ -266,10 +269,17 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
                                    None,
                                    None,
                                    def.body.clone());
-    let argument_map = parse_or_else(cx.parse_sess(),
-                                     cx.cfg(),
-                                     arg_reader,
-                                     argument_gram);
+
+    let argument_map = match parse(cx.parse_sess(),
+                                   cx.cfg(),
+                                   arg_reader,
+                                   &argument_gram) {
+        Success(m) => m,
+        Failure(sp, str) | Error(sp, str) => {
+            panic!(cx.parse_sess().span_diagnostic
+                     .span_fatal(sp.substitute_dummy(def.span), &str[..]));
+        }
+    };
 
     // Extract the arguments:
     let lhses = match **argument_map.get(&lhs_nm).unwrap() {
diff --git a/src/test/compile-fail/issue-7970a.rs b/src/test/compile-fail/issue-7970a.rs
new file mode 100644
index 0000000000000..114db74f42048
--- /dev/null
+++ b/src/test/compile-fail/issue-7970a.rs
@@ -0,0 +1,14 @@
+// Copyright 2015 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.
+
+fn main() {
+    println!();
+    //~^ ERROR unexpected end of macro invocation
+}
diff --git a/src/test/compile-fail/issue-7970b.rs b/src/test/compile-fail/issue-7970b.rs
new file mode 100644
index 0000000000000..0cff90f281b90
--- /dev/null
+++ b/src/test/compile-fail/issue-7970b.rs
@@ -0,0 +1,14 @@
+// Copyright 2015 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.
+
+fn main() {}
+
+macro_rules! test {}
+//~^ ERROR unexpected end of macro invocation