about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2014-08-11 22:01:37 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2014-08-30 16:50:38 +1000
commit32e437161da5e60c660b86da9003b7f73ebb5676 (patch)
tree6de8bed0e2c88adc2f12927bebe94a3d4f395a06
parentddc8cc92c998b7d80c782d00d178c791ab564915 (diff)
rustc: implement a pretty mode to print ident/name's ctxt & gensyms.
`--pretty expanded,hygiene` is helpful with debugging macro issues,
since two identifiers/names can be textually the same, but different
internally (resulting in weird "undefined variable" errors).
-rw-r--r--src/librustc/driver/pretty.rs50
-rw-r--r--src/librustc/middle/dataflow.rs1
-rw-r--r--src/libsyntax/print/pprust.rs10
-rw-r--r--src/test/run-make/pretty-expanded-hygiene/Makefile20
-rwxr-xr-xsrc/test/run-make/pretty-expanded-hygiene/input.pp.rs16
-rwxr-xr-xsrc/test/run-make/pretty-expanded-hygiene/input.rs22
6 files changed, 116 insertions, 3 deletions
diff --git a/src/librustc/driver/pretty.rs b/src/librustc/driver/pretty.rs
index d7118c7e54c..67dbc6f6a30 100644
--- a/src/librustc/driver/pretty.rs
+++ b/src/librustc/driver/pretty.rs
@@ -42,6 +42,7 @@ pub enum PpSourceMode {
     PpmTyped,
     PpmIdentified,
     PpmExpandedIdentified,
+    PpmExpandedHygiene,
 }
 
 #[deriving(PartialEq, Show)]
@@ -59,6 +60,7 @@ pub fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<UserIdentifie
         "expanded"     => PpmSource(PpmExpanded),
         "typed"        => PpmSource(PpmTyped),
         "expanded,identified" => PpmSource(PpmExpandedIdentified),
+        "expanded,hygiene" => PpmSource(PpmExpandedHygiene),
         "identified"   => PpmSource(PpmIdentified),
         "flowgraph"    => PpmFlowGraph,
         _ => {
@@ -106,6 +108,10 @@ impl PpSourceMode {
                 let annotation = IdentifiedAnnotation { sess: sess, ast_map: ast_map };
                 f(&annotation, payload)
             }
+            PpmExpandedHygiene => {
+                let annotation = HygieneAnnotation { sess: sess, ast_map: ast_map };
+                f(&annotation, payload)
+            }
             PpmTyped => {
                 let ast_map = ast_map.expect("--pretty=typed missing ast_map");
                 let analysis = driver::phase_3_run_analysis_passes(sess, krate, ast_map, id);
@@ -191,6 +197,8 @@ impl pprust::PpAnn for IdentifiedAnnotation {
             s: &mut pprust::State,
             node: pprust::AnnNode) -> io::IoResult<()> {
         match node {
+            pprust::NodeIdent(_) | pprust::NodeName(_) => Ok(()),
+
             pprust::NodeItem(item) => {
                 try!(pp::space(&mut s.s));
                 s.synth_comment(item.id.to_string())
@@ -212,6 +220,46 @@ impl pprust::PpAnn for IdentifiedAnnotation {
     }
 }
 
+struct HygieneAnnotation {
+    sess: Session,
+    ast_map: Option<ast_map::Map>,
+}
+
+impl PrinterSupport for HygieneAnnotation {
+    fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
+}
+
+impl SessionCarrier for HygieneAnnotation {
+    fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+}
+
+impl AstMapCarrier for HygieneAnnotation {
+    fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
+        self.ast_map.as_ref()
+    }
+}
+
+impl pprust::PpAnn for HygieneAnnotation {
+    fn post(&self,
+            s: &mut pprust::State,
+            node: pprust::AnnNode) -> io::IoResult<()> {
+        match node {
+            pprust::NodeIdent(&ast::Ident { name: ast::Name(nm), ctxt }) => {
+                try!(pp::space(&mut s.s));
+                // FIXME #16420: this doesn't display the connections
+                // between syntax contexts
+                s.synth_comment(format!("{}#{}", nm, ctxt))
+            }
+            pprust::NodeName(&ast::Name(nm)) => {
+                try!(pp::space(&mut s.s));
+                s.synth_comment(nm.to_string())
+            }
+            _ => Ok(())
+        }
+    }
+}
+
+
 struct TypedAnnotation {
     analysis: CrateAnalysis,
 }
@@ -364,6 +412,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
 
         PpmSource(PpmExpanded) |
         PpmSource(PpmExpandedIdentified) |
+        PpmSource(PpmExpandedHygiene) |
         PpmSource(PpmTyped) |
         PpmFlowGraph => true
     }
@@ -376,6 +425,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
 
         PpmSource(PpmExpanded) |
         PpmSource(PpmExpandedIdentified) |
+        PpmSource(PpmExpandedHygiene) |
         PpmSource(PpmTyped) |
         PpmFlowGraph => true
     }
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 91c227cd5bc..876789f99bc 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -111,6 +111,7 @@ impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> {
            ps: &mut pprust::State,
            node: pprust::AnnNode) -> io::IoResult<()> {
         let id = match node {
+            pprust::NodeIdent(_) | pprust::NodeName(_) => 0,
             pprust::NodeExpr(expr) => expr.id,
             pprust::NodeBlock(blk) => blk.id,
             pprust::NodeItem(_) => 0,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index da265d81250..14ba4d73a4e 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -33,6 +33,8 @@ use std::io;
 use std::mem;
 
 pub enum AnnNode<'a> {
+    NodeIdent(&'a ast::Ident),
+    NodeName(&'a ast::Name),
     NodeBlock(&'a ast::Block),
     NodeItem(&'a ast::Item),
     NodeExpr(&'a ast::Expr),
@@ -1725,14 +1727,16 @@ impl<'a> State<'a> {
     pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
         if self.encode_idents_with_hygiene {
             let encoded = ident.encode_with_hygiene();
-            word(&mut self.s, encoded.as_slice())
+            try!(word(&mut self.s, encoded.as_slice()))
         } else {
-            word(&mut self.s, token::get_ident(ident).get())
+            try!(word(&mut self.s, token::get_ident(ident).get()))
         }
+        self.ann.post(self, NodeIdent(&ident))
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
-        word(&mut self.s, token::get_name(name).get())
+        try!(word(&mut self.s, token::get_name(name).get()));
+        self.ann.post(self, NodeName(&name))
     }
 
     pub fn print_for_decl(&mut self, loc: &ast::Local,
diff --git a/src/test/run-make/pretty-expanded-hygiene/Makefile b/src/test/run-make/pretty-expanded-hygiene/Makefile
new file mode 100644
index 00000000000..11763446437
--- /dev/null
+++ b/src/test/run-make/pretty-expanded-hygiene/Makefile
@@ -0,0 +1,20 @@
+-include ../tools.mk
+
+REPLACEMENT := s/[0-9][0-9]*\#[0-9][0-9]*/$(shell date)/g
+
+all:
+	$(RUSTC) -o $(TMPDIR)/input.out --pretty expanded,hygiene input.rs
+
+	# the name/ctxt numbers are very internals-dependent and thus
+	# change relatively frequently, and testing for their exact values
+	# them will fail annoyingly, so we just check their positions
+	# (using a non-constant replacement like this will make it less
+	# likely the compiler matches whatever other dummy value we
+	# choose).
+	#
+	# (These need to be out-of-place because OSX/BSD & GNU sed
+	# differ.)
+	sed "$(REPLACEMENT)" input.pp.rs > $(TMPDIR)/input.pp.rs
+	sed "$(REPLACEMENT)" $(TMPDIR)/input.out > $(TMPDIR)/input.out.replaced
+
+	diff -u $(TMPDIR)/input.out.replaced $(TMPDIR)/input.pp.rs
diff --git a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs
new file mode 100755
index 00000000000..bf60784ab58
--- /dev/null
+++ b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs
@@ -0,0 +1,16 @@
+// Copyright 2014 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.
+
+#![feature(macro_rules)]
+// minimal junk
+#![no_std]
+
+
+fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ }
diff --git a/src/test/run-make/pretty-expanded-hygiene/input.rs b/src/test/run-make/pretty-expanded-hygiene/input.rs
new file mode 100755
index 00000000000..c9d603c2e1c
--- /dev/null
+++ b/src/test/run-make/pretty-expanded-hygiene/input.rs
@@ -0,0 +1,22 @@
+// Copyright 2014 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.
+
+#![feature(macro_rules)]
+// minimal junk
+#![no_std]
+
+macro_rules! foo {
+    ($x: ident) => { y + $x }
+}
+
+fn bar() {
+    let x = 1;
+    foo!(x)
+}