]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #34853 - frewsxcv:vec-truncate, r=GuillaumeGomez
authorSeo Sanghyeon <sanxiyn@gmail.com>
Mon, 18 Jul 2016 13:44:56 +0000 (22:44 +0900)
committerGitHub <noreply@github.com>
Mon, 18 Jul 2016 13:44:56 +0000 (22:44 +0900)
Partial rewrite/expansion of `Vec::truncate` documentation.

None

66 files changed:
configure
mk/llvm.mk
mk/rt.mk
src/bootstrap/config.rs
src/doc/book/no-stdlib.md
src/doc/nomicon/phantom-data.md
src/doc/reference.md
src/libcollections/vec.rs
src/libcore/hash/sip.rs
src/libcore/lib.rs
src/libcore/num/mod.rs
src/librustc/infer/error_reporting.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_errors/snippet.rs
src/librustc_errors/styled_buffer.rs [new file with mode: 0644]
src/librustc_lint/types.rs
src/librustc_metadata/decoder.rs
src/librustc_mir/pretty.rs
src/librustc_resolve/assign_ids.rs
src/librustc_resolve/lib.rs
src/librustc_trans/back/write.rs
src/librustdoc/core.rs
src/librustdoc/test.rs
src/libsyntax/ast.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/hygiene.rs [new file with mode: 0644]
src/libsyntax/ext/mtwt.rs [deleted file]
src/libsyntax/json.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/token.rs
src/libsyntax/test.rs
src/libsyntax_pos/lib.rs
src/test/compile-fail/issue-34839.rs [new file with mode: 0644]
src/test/compile-fail/macro-expanded-include/foo/mod.rs
src/test/compile-fail/macro-expanded-include/test.rs
src/test/compile-fail/use-from-trait-xc.rs
src/test/ui/codemap_tests/empty_span.rs [new file with mode: 0644]
src/test/ui/codemap_tests/empty_span.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/huge_multispan_highlight.rs [new file with mode: 0644]
src/test/ui/codemap_tests/huge_multispan_highlight.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/issue-11715.rs [new file with mode: 0644]
src/test/ui/codemap_tests/issue-11715.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/one_line.rs [new file with mode: 0644]
src/test/ui/codemap_tests/one_line.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/overlapping_spans.rs [new file with mode: 0644]
src/test/ui/codemap_tests/overlapping_spans.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/tab.rs [new file with mode: 0644]
src/test/ui/codemap_tests/tab.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/two_files.rs [new file with mode: 0644]
src/test/ui/codemap_tests/two_files.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/two_files_data.rs [new file with mode: 0644]
src/test/ui/codemap_tests/unicode.rs [new file with mode: 0644]
src/test/ui/codemap_tests/unicode.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-26480.stderr
src/test/ui/mismatched_types/main.stderr

index fd009a757a4b70dee62e84b4d8d391ec503d6344..d2ec457a1c8bccd43e60fe13f0f0b3ae9236ff71 100755 (executable)
--- a/configure
+++ b/configure
@@ -612,6 +612,7 @@ opt rustbuild 0 "use the rust and cargo based build system"
 opt orbit 0 "get MIR where it belongs - everywhere; most importantly, in orbit"
 opt codegen-tests 1 "run the src/test/codegen tests"
 opt option-checking 1 "complain about unrecognized options in this configure script"
+opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)"
 
 # Optimization and debugging options. These may be overridden by the release channel, etc.
 opt_nosave optimize 1 "build optimized rust code"
@@ -785,6 +786,17 @@ probe CFG_BISON            bison
 probe CFG_GDB              gdb
 probe CFG_LLDB             lldb
 
+if [ -n "$CFG_ENABLE_NINJA" ]
+then
+  probe CFG_NINJA            ninja
+  if [ -z "$CFG_NINJA" ]
+  then
+    # On Debian and Fedora, the `ninja` binary is an IRC bot, so the build tool was
+    # renamed. Handle this case.
+    probe CFG_NINJA            ninja-build
+  fi
+fi
+
 # For building LLVM
 probe_need CFG_CMAKE cmake
 
@@ -1534,7 +1546,10 @@ do
     fi
 
     # We need the generator later on for compiler-rt even if LLVM's not built
-    if [ ${is_msvc} -ne 0 ]
+    if [ -n "$CFG_NINJA" ]
+    then
+        generator="Ninja"
+    elif [ ${is_msvc} -ne 0 ]
     then
         case "$CFG_MSVC_ROOT" in
             *14.0*)
index 2298565221072acf3e36dc9a4ff148dc16a40379..d6f812049e03cad1b0892f5f44153e28685a457e 100644 (file)
@@ -43,7 +43,9 @@ $$(LLVM_CONFIG_$(1)): $$(LLVM_DONE_$(1))
 
 $$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1))
        @$$(call E, cmake: llvm)
-ifeq ($$(findstring msvc,$(1)),msvc)
+ifneq ($$(CFG_NINJA),)
+       $$(Q)$$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1))
+else ifeq ($$(findstring msvc,$(1)),msvc)
        $$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
                --config $$(LLVM_BUILD_CONFIG_MODE)
 else
@@ -51,8 +53,16 @@ else
 endif
        $$(Q)touch $$@
 
-ifeq ($$(findstring msvc,$(1)),msvc)
+ifneq ($$(CFG_NINJA),)
 clean-llvm$(1):
+       @$$(call E, clean: llvm)
+       $$(Q)$$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1)) -t clean
+else ifeq ($$(findstring msvc,$(1)),msvc)
+clean-llvm$(1):
+       @$$(call E, clean: llvm)
+       $$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
+               --config $$(LLVM_BUILD_CONFIG_MODE) \
+               --target clean
 else
 clean-llvm$(1):
        @$$(call E, clean: llvm)
index d0ab3102d7d70d82e4979463d20664fb46d3731b..8113b68380744dcc837ad9ae920c434840a98c1c 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -350,10 +350,17 @@ $$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD
                $$(COMPRT_DEFINES_$(1)) \
                $$(COMPRT_BUILD_CC_$(1)) \
                -G"$$(CFG_CMAKE_GENERATOR)"
+ifneq ($$(CFG_NINJA),)
+       $$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \
+               --target $$(COMPRT_BUILD_TARGET_$(1)) \
+               --config $$(LLVM_BUILD_CONFIG_MODE) \
+               -- $$(COMPRT_BUILD_ARGS_$(1))
+else
        $$(Q)$$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \
                --target $$(COMPRT_BUILD_TARGET_$(1)) \
                --config $$(LLVM_BUILD_CONFIG_MODE) \
                -- $$(COMPRT_BUILD_ARGS_$(1)) $$(MFLAGS)
+endif
        $$(Q)cp "$$(COMPRT_OUTPUT_$(1))" $$@
 
 endif
index 498196e9b6dfc12454274e75cd695c2ad2a04b65..e64d7e5a437e6103b13f7b5a471c90fa1f9b7c5b 100644 (file)
@@ -317,6 +317,7 @@ macro_rules! check {
                 ("OPTIMIZE_TESTS", self.rust_optimize_tests),
                 ("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
                 ("LOCAL_REBUILD", self.local_rebuild),
+                ("NINJA", self.ninja),
             }
 
             match key {
index c5c139e6580b015b91d49bd6d90a66d037b04f41..6fd7cf66920d48875e03c0a6581e08b7de72101b 100644 (file)
@@ -21,7 +21,7 @@ this using our `Cargo.toml` file:
 
 ```toml
 [dependencies]
-libc = { version = "0.2.11", default-features = false }
+libc = { version = "0.2.14", default-features = false }
 ```
 
 Note that the default features have been disabled. This is a critical step -
@@ -36,8 +36,7 @@ or overriding the default shim for the C `main` function with your own.
 The function marked `#[start]` is passed the command line parameters
 in the same format as C:
 
-```rust
-# #![feature(libc)]
+```rust,ignore
 #![feature(lang_items)]
 #![feature(start)]
 #![no_std]
@@ -51,15 +50,21 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
     0
 }
 
-// These functions and traits are used by the compiler, but not
+// These functions are used by the compiler, but not
 // for a bare-bones hello world. These are normally
 // provided by libstd.
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
-# // fn main() {} tricked you, rustdoc!
+#[lang = "eh_personality"]
+#[no_mangle]
+pub extern fn eh_personality() {
+}
+
+#[lang = "panic_fmt"]
+#[no_mangle]
+pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
+                               _file: &'static str,
+                               _line: u32) -> ! {
+    loop {}
+}
 ```
 
 To override the compiler-inserted `main` shim, one has to disable it
@@ -67,37 +72,55 @@ with `#![no_main]` and then create the appropriate symbol with the
 correct ABI and the correct name, which requires overriding the
 compiler's name mangling too:
 
-```rust
-# #![feature(libc)]
+```rust,ignore
 #![feature(lang_items)]
 #![feature(start)]
 #![no_std]
 #![no_main]
 
+// Pull in the system libc library for what crt0.o likely requires
 extern crate libc;
 
+// Entry point for this program
 #[no_mangle] // ensure that this symbol is called `main` in the output
-pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
+pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
     0
 }
 
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
-# // fn main() {} tricked you, rustdoc!
+// These functions and traits are used by the compiler, but not
+// for a bare-bones hello world. These are normally
+// provided by libstd.
+#[lang = "eh_personality"]
+#[no_mangle]
+pub extern fn eh_personality() {
+}
+
+#[lang = "panic_fmt"]
+#[no_mangle]
+pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
+                               _file: &'static str,
+                               _line: u32) -> ! {
+    loop {}
+}
 ```
 
-The compiler currently makes a few assumptions about symbols which are available
-in the executable to call. Normally these functions are provided by the standard
-library, but without it you must define your own.
+## More about the langauge items
+
+The compiler currently makes a few assumptions about symbols which are
+available in the executable to call. Normally these functions are provided by
+the standard library, but without it you must define your own. These symbols
+are called "language items", and they each have an internal name, and then a
+signature that an implementation must conform to.
 
 The first of these two functions, `eh_personality`, is used by the failure
 mechanisms of the compiler. This is often mapped to GCC's personality function
 (see the [libstd implementation][unwind] for more information), but crates
 which do not trigger a panic can be assured that this function is never
-called. The second function, `panic_fmt`, is also used by the failure
-mechanisms of the compiler.
-
+called. Both the language item and the symbol name are `eh_personality`.
 [unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs
+
+The second function, `panic_fmt`, is also used by the failure mechanisms of the
+compiler. When a panic happens, this controls the message that's displayed on
+the screen. While the language item's name is `panic_fmt`, the symbol name is
+`rust_begin_panic`.
index 0d7ec7f161796e3cf8bc26760e173d419b6e02f9..d565532017a65982d518e2453b780743e609a266 100644 (file)
@@ -51,12 +51,12 @@ struct Vec<T> {
 ```
 
 Unlike the previous example it *appears* that everything is exactly as we
-want. Every generic argument to Vec shows up in the at least one field.
+want. Every generic argument to Vec shows up in at least one field.
 Good to go!
 
 Nope.
 
-The drop checker will generously determine that Vec<T> does not own any values
+The drop checker will generously determine that `Vec<T>` does not own any values
 of type T. This will in turn make it conclude that it doesn't need to worry
 about Vec dropping any T's in its destructor for determining drop check
 soundness. This will in turn allow people to create unsoundness using
@@ -81,7 +81,7 @@ Raw pointers that own an allocation is such a pervasive pattern that the
 standard library made a utility for itself called `Unique<T>` which:
 
 * wraps a `*const T` for variance
-* includes a `PhantomData<T>`,
+* includes a `PhantomData<T>`
 * auto-derives Send/Sync as if T was contained
 * marks the pointer as NonZero for the null-pointer optimization
 
index b3073f5e526033271c855588b8fb343d40d63bb5..b8509321e3d19b0679ba7a29aea280336229dab2 100644 (file)
@@ -853,6 +853,20 @@ extern crate std; // equivalent to: extern crate std as std;
 extern crate std as ruststd; // linking to 'std' under another name
 ```
 
+When naming Rust crates, hyphens are disallowed. However, Cargo packages may
+make use of them. In such case, when `Cargo.toml` doesn't specify a crate name,
+Cargo will transparently replace `-` with `_` (Refer to [RFC 940] for more
+details).
+
+Here is an example:
+
+```{.ignore}
+// Importing the Cargo package hello-world
+extern crate hello_world; // hyphen replaced with an underscore
+```
+
+[RFC 940]: https://github.com/rust-lang/rfcs/blob/master/text/0940-hyphens-considered-harmful.md
+
 #### Use declarations
 
 A _use declaration_ creates one or more local name bindings synonymous with
@@ -3744,9 +3758,9 @@ Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of
 
 ## Type coercions
 
-Coercions are defined in [RFC401]. A coercion is implicit and has no syntax.
+Coercions are defined in [RFC 401]. A coercion is implicit and has no syntax.
 
-[RFC401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
 
 ### Coercion sites
 
@@ -3886,7 +3900,7 @@ Coercion is allowed between the following types:
 
     In the future, coerce_inner will be recursively extended to tuples and
     structs. In addition, coercions from sub-traits to super-traits will be
-    added. See [RFC401] for more details.
+    added. See [RFC 401] for more details.
 
 # Special traits
 
index 966144233894c293c65270a1e77761014a16acdf..2372d5dfc450fd84202cfcce6e017c0764f6b3e8 100644 (file)
@@ -547,7 +547,7 @@ pub fn as_slice(&self) -> &[T] {
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     pub fn as_mut_slice(&mut self) -> &mut [T] {
-        &mut self[..]
+        self
     }
 
     /// Sets the length of a vector.
index c52c0b0730be785d8d8aad84bdd68577df4023e3..4a806a3c98602aa224b963e8a862526d3b1b48ef 100644 (file)
@@ -18,7 +18,7 @@
 /// An implementation of SipHash 1-3.
 ///
 /// See: https://131002.net/siphash/
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 #[derive(Debug, Clone, Default)]
 pub struct SipHasher13 {
     hasher: Hasher<Sip13Rounds>,
@@ -27,7 +27,7 @@ pub struct SipHasher13 {
 /// An implementation of SipHash 2-4.
 ///
 /// See: https://131002.net/siphash/
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 #[derive(Debug, Clone, Default)]
 pub struct SipHasher24 {
     hasher: Hasher<Sip24Rounds>,
@@ -154,14 +154,14 @@ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
 impl SipHasher13 {
     /// Creates a new `SipHasher13` with the two initial keys set to 0.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new() -> SipHasher13 {
         SipHasher13::new_with_keys(0, 0)
     }
 
     /// Creates a `SipHasher13` that is keyed off the provided keys.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
         SipHasher13 {
             hasher: Hasher::new_with_keys(key0, key1)
@@ -172,14 +172,14 @@ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
 impl SipHasher24 {
     /// Creates a new `SipHasher24` with the two initial keys set to 0.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new() -> SipHasher24 {
         SipHasher24::new_with_keys(0, 0)
     }
 
     /// Creates a `SipHasher24` that is keyed off the provided keys.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
         SipHasher24 {
             hasher: Hasher::new_with_keys(key0, key1)
@@ -232,7 +232,7 @@ fn finish(&self) -> u64 {
     }
 }
 
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 impl super::Hasher for SipHasher13 {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
@@ -245,7 +245,7 @@ fn finish(&self) -> u64 {
     }
 }
 
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 impl super::Hasher for SipHasher24 {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
index e849369d647c4754967d63f3d7cd627ae0fc8929..0ad1f671f155b8182c038ce0ec8e8ae9483308b7 100644 (file)
@@ -25,6 +25,8 @@
 //!
 //! # How to use the core library
 //!
+//! Please note that all of these details are currently not considered stable.
+//!
 // FIXME: Fill me in with more detail when the interface settles
 //! This library is built on the assumption of a few existing symbols:
 //!
 //!   These functions are often provided by the system libc, but can also be
 //!   provided by the [rlibc crate](https://crates.io/crates/rlibc).
 //!
-//! * `rust_begin_unwind` - This function takes three arguments, a
-//!   `fmt::Arguments`, a `&str`, and a `u32`. These three arguments dictate
-//!   the panic message, the file at which panic was invoked, and the line.
-//!   It is up to consumers of this core library to define this panic
-//!   function; it is only required to never return.
+//! * `rust_begin_panic` - This function takes three arguments, a
+//!   `fmt::Arguments`, a `&'static str`, and a `u32`. These three arguments
+//!   dictate the panic message, the file at which panic was invoked, and the
+//!   line. It is up to consumers of this core library to define this panic
+//!   function; it is only required to never return. This requires a `lang`
+//!   attribute named `panic_fmt`.
 
 // Since libcore defines many fundamental lang items, all tests live in a
 // separate crate, libcoretest, to avoid bizarre issues.
index fcdbde0d19f4f5a1808621423602e199918e1cd0..97648cc34699a9dc6baaf133fa8a28893b2fe74a 100644 (file)
@@ -2318,7 +2318,7 @@ impl usize {
 /// let num = 12.4_f32;
 /// let inf = f32::INFINITY;
 /// let zero = 0f32;
-/// let sub: f32 = 0.000000000000000000000000000000000000011754942;
+/// let sub: f32 = 1.1754942e-38;
 /// let nan = f32::NAN;
 ///
 /// assert_eq!(num.classify(), FpCategory::Normal);
index 894044296cbd6ecaf1816a3585faf7edc7424f5e..96ecad629f543f24d7a7e586a351e7163375b4c1 100644 (file)
@@ -94,7 +94,7 @@
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax_pos::{self, Pos, Span};
-use errors::{DiagnosticBuilder, check_old_skool};
+use errors::{DiagnosticBuilder, check_old_school};
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn note_and_explain_region(self,
@@ -485,7 +485,7 @@ fn report_type_error(&self,
                                        "{}",
                                        trace.origin);
 
-        if !is_simple_error || check_old_skool() {
+        if !is_simple_error || check_old_school() {
             err.note_expected_found(&"type", &expected, &found);
         }
 
index bc271e9ecc8ea46a67bf56410c759153d9eef52d..65b97abfccbd75f5cb456115f24431e70340939a 100644 (file)
@@ -735,8 +735,8 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
           "for every macro invocation, print its name and arguments"),
     enable_nonzeroing_move_hints: bool = (false, parse_bool,
           "force nonzeroing move optimization on"),
-    keep_mtwt_tables: bool = (false, parse_bool,
-          "don't clear the resolution tables after analysis"),
+    keep_hygiene_data: bool = (false, parse_bool,
+          "don't clear the hygiene data after analysis"),
     keep_ast: bool = (false, parse_bool,
           "keep the AST after lowering it to HIR"),
     show_span: Option<String> = (None, parse_opt_string,
index 0e516bdc21194b3c9d5ce473d0e8a9228f871aab..fa9bc7c83680c45009f1bf09f72685b38d7e1f09 100644 (file)
@@ -22,7 +22,8 @@
 
 use syntax::ast::{NodeId, Name};
 use errors::{self, DiagnosticBuilder};
-use errors::emitter::{Emitter, BasicEmitter, EmitterWriter};
+use errors::emitter::{Emitter, EmitterWriter};
+use errors::snippet::FormatMode;
 use syntax::json::JsonEmitter;
 use syntax::feature_gate;
 use syntax::parse;
@@ -439,7 +440,7 @@ pub fn build_session_with_codemap(sopts: config::Options,
         config::ErrorOutputType::HumanReadable(color_config) => {
             Box::new(EmitterWriter::stderr(color_config,
                                            Some(registry),
-                                           codemap.clone(),
+                                           Some(codemap.clone()),
                                            errors::snippet::FormatMode::EnvironmentSelected))
         }
         config::ErrorOutputType::Json => {
@@ -575,24 +576,32 @@ unsafe fn configure_llvm(sess: &Session) {
 }
 
 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
-    let mut emitter: Box<Emitter> = match output {
+    let emitter: Box<Emitter> = match output {
         config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(BasicEmitter::stderr(color_config))
+            Box::new(EmitterWriter::stderr(color_config,
+                                           None,
+                                           None,
+                                           FormatMode::EnvironmentSelected))
         }
         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
     };
-    emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Fatal);
+    let handler = errors::Handler::with_emitter(true, false, emitter);
+    handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
     panic!(errors::FatalError);
 }
 
 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
-    let mut emitter: Box<Emitter> = match output {
+    let emitter: Box<Emitter> = match output {
         config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(BasicEmitter::stderr(color_config))
+            Box::new(EmitterWriter::stderr(color_config,
+                                           None,
+                                           None,
+                                           FormatMode::EnvironmentSelected))
         }
         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
     };
-    emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Warning);
+    let handler = errors::Handler::with_emitter(true, false, emitter);
+    handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
 }
 
 // Err(0) means compilation was stopped, but no errors were found.
index 3b1124a911e5d2ad9bb9b8a3acf91f9d531bc34e..ab3b20e08c8099130c1b5c3a874a519f9b29fddb 100644 (file)
@@ -236,8 +236,8 @@ macro_rules! controller_entry_point {
     Ok(())
 }
 
-fn keep_mtwt_tables(sess: &Session) -> bool {
-    sess.opts.debugging_opts.keep_mtwt_tables
+fn keep_hygiene_data(sess: &Session) -> bool {
+    sess.opts.debugging_opts.keep_hygiene_data
 }
 
 fn keep_ast(sess: &Session) -> bool {
@@ -479,9 +479,8 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session,
                                input: &Input)
                                -> PResult<'a, ast::Crate> {
     // These may be left in an incoherent state after a previous compile.
-    // `clear_tables` and `clear_ident_interner` can be used to free
-    // memory, but they do not restore the initial state.
-    syntax::ext::mtwt::reset_tables();
+    syntax::ext::hygiene::reset_hygiene_data();
+    // `clear_ident_interner` can be used to free memory, but it does not restore the initial state.
     token::reset_ident_interner();
     let continue_after_error = sess.opts.continue_parse_after_error;
     sess.diagnostic().set_continue_after_error(continue_after_error);
@@ -761,9 +760,9 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
         hir_map::Forest::new(lower_crate(sess, &krate, &mut resolver), &sess.dep_graph)
     });
 
-    // Discard MTWT tables that aren't required past lowering to HIR.
-    if !keep_mtwt_tables(sess) {
-        syntax::ext::mtwt::clear_tables();
+    // Discard hygiene data, which isn't required past lowering to HIR.
+    if !keep_hygiene_data(sess) {
+        syntax::ext::hygiene::reset_hygiene_data();
     }
 
     Ok(ExpansionResult {
index 84e040319231737c085f9e32a05bd53c567d244b..0a8df923b846b90f2b4783a822fa7471f2497ef4 100644 (file)
 use syntax::parse::{self, PResult};
 use syntax_pos::MultiSpan;
 use errors::emitter::Emitter;
+use errors::snippet::FormatMode;
 
 #[cfg(test)]
 pub mod test;
@@ -138,10 +139,15 @@ pub fn run(args: Vec<String>) -> isize {
                 match session {
                     Some(sess) => sess.fatal(&abort_msg(err_count)),
                     None => {
-                        let mut emitter =
-                            errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto);
-                        emitter.emit(&MultiSpan::new(), &abort_msg(err_count), None,
-                            errors::Level::Fatal);
+                        let emitter =
+                            errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
+                                                                   None,
+                                                                   None,
+                                                                   FormatMode::EnvironmentSelected);
+                        let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
+                        handler.emit(&MultiSpan::new(),
+                                     &abort_msg(err_count),
+                                     errors::Level::Fatal);
                         exit_on_err();
                     }
                 }
@@ -373,23 +379,26 @@ fn handle_explain(code: &str,
 
 fn check_cfg(sopts: &config::Options,
              output: ErrorOutputType) {
-    let mut emitter: Box<Emitter> = match output {
+    let emitter: Box<Emitter> = match output {
         config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(errors::emitter::BasicEmitter::stderr(color_config))
+            Box::new(errors::emitter::EmitterWriter::stderr(color_config,
+                                                            None,
+                                                            None,
+                                                            FormatMode::EnvironmentSelected))
         }
         config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()),
     };
+    let handler = errors::Handler::with_emitter(true, false, emitter);
 
     let mut saw_invalid_predicate = false;
     for item in sopts.cfg.iter() {
         match item.node {
             ast::MetaItemKind::List(ref pred, _) => {
                 saw_invalid_predicate = true;
-                emitter.emit(&MultiSpan::new(),
+                handler.emit(&MultiSpan::new(),
                              &format!("invalid predicate in --cfg command line argument: `{}`",
                                       pred),
-                             None,
-                             errors::Level::Fatal);
+                                errors::Level::Fatal);
             }
             _ => {},
         }
@@ -1046,26 +1055,34 @@ fn flush(&mut self) -> io::Result<()> {
      if let Err(value) = thread.unwrap().join() {
         // Thread panicked without emitting a fatal diagnostic
         if !value.is::<errors::FatalError>() {
-            let mut emitter = errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto);
+            let emitter =
+                Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
+                                                       None,
+                                                       None,
+                                                       FormatMode::EnvironmentSelected));
+            let handler = errors::Handler::with_emitter(true, false, emitter);
 
             // a .span_bug or .bug call has already printed what
             // it wants to print.
             if !value.is::<errors::ExplicitBug>() {
-                emitter.emit(&MultiSpan::new(), "unexpected panic", None, errors::Level::Bug);
+                handler.emit(&MultiSpan::new(),
+                             "unexpected panic",
+                             errors::Level::Bug);
             }
 
             let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
                       format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
             for note in &xs {
-                emitter.emit(&MultiSpan::new(), &note[..], None, errors::Level::Note)
+                handler.emit(&MultiSpan::new(),
+                             &note[..],
+                             errors::Level::Note);
             }
             if match env::var_os("RUST_BACKTRACE") {
                 Some(val) => &val != "0",
                 None => false,
             } {
-                emitter.emit(&MultiSpan::new(),
+                handler.emit(&MultiSpan::new(),
                              "run with `RUST_BACKTRACE=1` for a backtrace",
-                             None,
                              errors::Level::Note);
             }
 
index baac455a25f334c7c6c6a3194f0ed6c00f44da56..14476cc997ff3eb35968e2540a7a99902d81205c 100644 (file)
@@ -456,7 +456,7 @@ fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
                 pp::space(&mut s.s)?;
                 // FIXME #16420: this doesn't display the connections
                 // between syntax contexts
-                s.synth_comment(format!("{}#{}", nm, ctxt.0))
+                s.synth_comment(format!("{}{:?}", nm, ctxt))
             }
             pprust::NodeName(&ast::Name(nm)) => {
                 pp::space(&mut s.s)?;
index 911becd3f569b99fadbb0982e5ae155743a67e1f..39763bfa0eb61c6d279054166cf57eaeab03de87 100644 (file)
@@ -33,8 +33,8 @@
 use syntax::abi::Abi;
 use syntax::codemap::CodeMap;
 use errors;
-use errors::emitter::{CoreEmitter, Emitter};
-use errors::{Level, RenderSpan};
+use errors::emitter::Emitter;
+use errors::{Level, DiagnosticBuilder};
 use syntax::parse::token;
 use syntax::feature_gate::UnstableFeatures;
 use syntax_pos::DUMMY_SP;
@@ -76,15 +76,12 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
     }
 }
 
-impl CoreEmitter for ExpectErrorEmitter {
-    fn emit_message(&mut self,
-                    _sp: &RenderSpan,
-                    msg: &str,
-                    _: Option<&str>,
-                    lvl: Level,
-                    _is_header: bool,
-                    _show_snippet: bool) {
-        remove_message(self, msg, lvl);
+impl Emitter for ExpectErrorEmitter {
+    fn emit(&mut self, db: &DiagnosticBuilder) {
+        remove_message(self, &db.message, db.level);
+        for child in &db.children {
+            remove_message(self, &child.message, child.level);
+        }
     }
 }
 
index a7c68e3a87b318f418f41ff688894afb493ea3a9..893f8a6e4ddb01b4a09963ec5afe445964d81cc1 100644 (file)
 
 use self::Destination::*;
 
-use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan, LineInfo};
+use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo, CharPos};
 use registry;
 
-use check_old_skool;
-use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper};
+use check_old_school;
+use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper};
 use RenderSpan::*;
-use Level::*;
-use snippet::{RenderedLineKind, SnippetData, Style, FormatMode};
+use snippet::{StyledString, Style, FormatMode, Annotation, Line};
+use styled_buffer::StyledBuffer;
 
-use std::{cmp, fmt};
+use std::cmp;
 use std::io::prelude::*;
 use std::io;
 use std::rc::Rc;
 use term;
 
-/// Emitter trait for emitting errors. Do not implement this directly:
-/// implement `CoreEmitter` instead.
+/// Emitter trait for emitting errors.
 pub trait Emitter {
-    /// Emit a standalone diagnostic message.
-    fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level);
-
     /// Emit a structured diagnostic.
-    fn emit_struct(&mut self, db: &DiagnosticBuilder);
-}
-
-pub trait CoreEmitter {
-    fn emit_message(&mut self,
-                    rsp: &RenderSpan,
-                    msg: &str,
-                    code: Option<&str>,
-                    lvl: Level,
-                    is_header: bool,
-                    show_snippet: bool);
+    fn emit(&mut self, db: &DiagnosticBuilder);
 }
 
-impl<T: CoreEmitter> Emitter for T {
-    fn emit(&mut self,
-            msp: &MultiSpan,
-            msg: &str,
-            code: Option<&str>,
-            lvl: Level) {
-        self.emit_message(&FullSpan(msp.clone()),
-                          msg,
-                          code,
-                          lvl,
-                          true,
-                          true);
-    }
+impl Emitter for EmitterWriter {
+    fn emit(&mut self, db: &DiagnosticBuilder) {
+        // Pick old school mode either from env or let the test dictate the format
+        let old_school = match self.format_mode {
+            FormatMode::NewErrorFormat => false,
+            FormatMode::OriginalErrorFormat => true,
+            FormatMode::EnvironmentSelected => check_old_school()
+        };
 
-    fn emit_struct(&mut self, db: &DiagnosticBuilder) {
-        let old_school = check_old_skool();
-        let db_span = FullSpan(db.span.clone());
-        self.emit_message(&FullSpan(db.span.clone()),
-                          &db.message,
-                          db.code.as_ref().map(|s| &**s),
-                          db.level,
-                          true,
-                          true);
-        for child in &db.children {
-            let render_span = child.render_span
-                                   .clone()
-                                   .unwrap_or_else(
-                                       || FullSpan(child.span.clone()));
-
-            if !old_school {
-                self.emit_message(&render_span,
-                                    &child.message,
-                                    None,
-                                    child.level,
-                                    false,
-                                    true);
-            } else {
-                let (render_span, show_snippet) = match render_span.span().primary_span() {
-                    None => (db_span.clone(), false),
-                    _ => (render_span, true)
-                };
-                self.emit_message(&render_span,
-                                    &child.message,
-                                    None,
-                                    child.level,
-                                    false,
-                                    show_snippet);
-            }
+        if old_school {
+            self.emit_messages_old_school(db);
+        } else {
+            self.emit_messages_default(db);
         }
     }
 }
@@ -117,66 +68,21 @@ fn use_color(&self) -> bool {
     }
 }
 
-/// A basic emitter for when we don't have access to a codemap or registry. Used
-/// for reporting very early errors, etc.
-pub struct BasicEmitter {
-    dst: Destination,
-}
-
-impl CoreEmitter for BasicEmitter {
-    fn emit_message(&mut self,
-                    _rsp: &RenderSpan,
-                    msg: &str,
-                    code: Option<&str>,
-                    lvl: Level,
-                    _is_header: bool,
-                    _show_snippet: bool) {
-        // we ignore the span as we have no access to a codemap at this point
-        if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) {
-            panic!("failed to print diagnostics: {:?}", e);
-        }
-    }
-}
-
-impl BasicEmitter {
-    pub fn stderr(color_config: ColorConfig) -> BasicEmitter {
-        if color_config.use_color() {
-            let dst = Destination::from_stderr();
-            BasicEmitter { dst: dst }
-        } else {
-            BasicEmitter { dst: Raw(Box::new(io::stderr())) }
-        }
-    }
-}
-
 pub struct EmitterWriter {
     dst: Destination,
     registry: Option<registry::Registry>,
-    cm: Rc<CodeMapper>,
-
-    /// Is this the first error emitted thus far? If not, we emit a
-    /// `\n` before the top-level errors.
-    first: bool,
+    cm: Option<Rc<CodeMapper>>,
 
     // For now, allow an old-school mode while we transition
     format_mode: FormatMode
 }
 
-impl CoreEmitter for EmitterWriter {
-    fn emit_message(&mut self,
-                    rsp: &RenderSpan,
-                    msg: &str,
-                    code: Option<&str>,
-                    lvl: Level,
-                    is_header: bool,
-                    show_snippet: bool) {
-        match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) {
-            Ok(()) => { }
-            Err(e) => panic!("failed to emit error: {}", e)
-        }
-    }
+struct FileWithAnnotatedLines {
+    file: Rc<FileMap>,
+    lines: Vec<Line>,
 }
 
+
 /// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See
 /// `EmitterWriter::print_maybe_styled` for details.
 macro_rules! print_maybe_styled {
@@ -194,7 +100,7 @@ macro_rules! println_maybe_styled {
 impl EmitterWriter {
     pub fn stderr(color_config: ColorConfig,
                   registry: Option<registry::Registry>,
-                  code_map: Rc<CodeMapper>,
+                  code_map: Option<Rc<CodeMapper>>,
                   format_mode: FormatMode)
                   -> EmitterWriter {
         if color_config.use_color() {
@@ -202,248 +108,854 @@ pub fn stderr(color_config: ColorConfig,
             EmitterWriter { dst: dst,
                             registry: registry,
                             cm: code_map,
-                            first: true,
                             format_mode: format_mode.clone() }
         } else {
             EmitterWriter { dst: Raw(Box::new(io::stderr())),
                             registry: registry,
                             cm: code_map,
-                            first: true,
                             format_mode: format_mode.clone() }
         }
     }
 
     pub fn new(dst: Box<Write + Send>,
                registry: Option<registry::Registry>,
-               code_map: Rc<CodeMapper>,
+               code_map: Option<Rc<CodeMapper>>,
                format_mode: FormatMode)
                -> EmitterWriter {
         EmitterWriter { dst: Raw(dst),
                         registry: registry,
                         cm: code_map,
-                        first: true,
                         format_mode: format_mode.clone() }
     }
 
-    fn emit_message_(&mut self,
-                     rsp: &RenderSpan,
-                     msg: &str,
-                     code: Option<&str>,
-                     lvl: Level,
-                     is_header: bool,
-                     show_snippet: bool)
-                     -> io::Result<()> {
-        let old_school = match self.format_mode {
-            FormatMode::NewErrorFormat => false,
-            FormatMode::OriginalErrorFormat => true,
-            FormatMode::EnvironmentSelected => check_old_skool()
-        };
+    fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
+        fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
+                                    file: Rc<FileMap>,
+                                    line_index: usize,
+                                    ann: Annotation) {
+
+            for slot in file_vec.iter_mut() {
+                // Look through each of our files for the one we're adding to
+                if slot.file.name == file.name {
+                    // See if we already have a line for it
+                    for line_slot in &mut slot.lines {
+                        if line_slot.line_index == line_index {
+                            line_slot.annotations.push(ann);
+                            return;
+                        }
+                    }
+                    // We don't have a line yet, create one
+                    slot.lines.push(Line {
+                        line_index: line_index,
+                        annotations: vec![ann],
+                    });
+                    slot.lines.sort();
+                    return;
+                }
+            }
+            // This is the first time we're seeing the file
+            file_vec.push(FileWithAnnotatedLines {
+                file: file,
+                lines: vec![Line {
+                                line_index: line_index,
+                                annotations: vec![ann],
+                            }],
+            });
+        }
+
+        let mut output = vec![];
+
+        if let Some(ref cm) = self.cm {
+            for span_label in msp.span_labels() {
+                if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP {
+                    continue;
+                }
+                let lo = cm.lookup_char_pos(span_label.span.lo);
+                let mut hi = cm.lookup_char_pos(span_label.span.hi);
+                let mut is_minimized = false;
+
+                // If the span is multi-line, simplify down to the span of one character
+                if lo.line != hi.line {
+                    hi.line = lo.line;
+                    hi.col = CharPos(lo.col.0 + 1);
+                    is_minimized = true;
+                }
 
-        if is_header {
-            if self.first {
-                self.first = false;
+                // Watch out for "empty spans". If we get a span like 6..6, we
+                // want to just display a `^` at 6, so convert that to
+                // 6..7. This is degenerate input, but it's best to degrade
+                // gracefully -- and the parser likes to supply a span like
+                // that for EOF, in particular.
+                if lo.col == hi.col {
+                    hi.col = CharPos(lo.col.0 + 1);
+                }
+
+                add_annotation_to_file(&mut output,
+                                        lo.file,
+                                        lo.line,
+                                        Annotation {
+                                            start_col: lo.col.0,
+                                            end_col: hi.col.0,
+                                            is_primary: span_label.is_primary,
+                                            is_minimized: is_minimized,
+                                            label: span_label.label.clone(),
+                                        });
+            }
+        }
+        output
+    }
+
+    fn render_source_line(&self,
+                          buffer: &mut StyledBuffer,
+                          file: Rc<FileMap>,
+                          line: &Line,
+                          width_offset: usize) {
+        let source_string = file.get_line(line.line_index - 1)
+            .unwrap_or("");
+
+        let line_offset = buffer.num_lines();
+
+        // First create the source line we will highlight.
+        buffer.puts(line_offset, width_offset, &source_string, Style::Quotation);
+        buffer.puts(line_offset,
+                    0,
+                    &(line.line_index.to_string()),
+                    Style::LineNumber);
+
+        draw_col_separator(buffer, line_offset, width_offset - 2);
+
+        if line.annotations.is_empty() {
+            return;
+        }
+
+        // We want to display like this:
+        //
+        //      vec.push(vec.pop().unwrap());
+        //      ---      ^^^               _ previous borrow ends here
+        //      |        |
+        //      |        error occurs here
+        //      previous borrow of `vec` occurs here
+        //
+        // But there are some weird edge cases to be aware of:
+        //
+        //      vec.push(vec.pop().unwrap());
+        //      --------                    - previous borrow ends here
+        //      ||
+        //      |this makes no sense
+        //      previous borrow of `vec` occurs here
+        //
+        // For this reason, we group the lines into "highlight lines"
+        // and "annotations lines", where the highlight lines have the `~`.
+
+        // Sort the annotations by (start, end col)
+        let mut annotations = line.annotations.clone();
+        annotations.sort();
+
+        // Next, create the highlight line.
+        for annotation in &annotations {
+            for p in annotation.start_col..annotation.end_col {
+                if annotation.is_primary {
+                    buffer.putc(line_offset + 1,
+                                width_offset + p,
+                                '^',
+                                Style::UnderlinePrimary);
+                    if !annotation.is_minimized {
+                        buffer.set_style(line_offset,
+                                            width_offset + p,
+                                            Style::UnderlinePrimary);
+                    }
+                } else {
+                    buffer.putc(line_offset + 1,
+                                width_offset + p,
+                                '-',
+                                Style::UnderlineSecondary);
+                    if !annotation.is_minimized {
+                        buffer.set_style(line_offset,
+                                            width_offset + p,
+                                            Style::UnderlineSecondary);
+                    }
+                }
+            }
+        }
+        draw_col_separator(buffer, line_offset + 1, width_offset - 2);
+
+        // Now we are going to write labels in. To start, we'll exclude
+        // the annotations with no labels.
+        let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = annotations.into_iter()
+            .partition(|a| a.label.is_some());
+
+        // If there are no annotations that need text, we're done.
+        if labeled_annotations.is_empty() {
+            return;
+        }
+        // Now add the text labels. We try, when possible, to stick the rightmost
+        // annotation at the end of the highlight line:
+        //
+        //      vec.push(vec.pop().unwrap());
+        //      ---      ---               - previous borrow ends here
+        //
+        // But sometimes that's not possible because one of the other
+        // annotations overlaps it. For example, from the test
+        // `span_overlap_label`, we have the following annotations
+        // (written on distinct lines for clarity):
+        //
+        //      fn foo(x: u32) {
+        //      --------------
+        //             -
+        //
+        // In this case, we can't stick the rightmost-most label on
+        // the highlight line, or we would get:
+        //
+        //      fn foo(x: u32) {
+        //      -------- x_span
+        //      |
+        //      fn_span
+        //
+        // which is totally weird. Instead we want:
+        //
+        //      fn foo(x: u32) {
+        //      --------------
+        //      |      |
+        //      |      x_span
+        //      fn_span
+        //
+        // which is...less weird, at least. In fact, in general, if
+        // the rightmost span overlaps with any other span, we should
+        // use the "hang below" version, so we can at least make it
+        // clear where the span *starts*.
+        let mut labeled_annotations = &labeled_annotations[..];
+        match labeled_annotations.split_last().unwrap() {
+            (last, previous) => {
+                if previous.iter()
+                    .chain(&unlabeled_annotations)
+                    .all(|a| !overlaps(a, last)) {
+                    // append the label afterwards; we keep it in a separate
+                    // string
+                    let highlight_label: String = format!(" {}", last.label.as_ref().unwrap());
+                    if last.is_primary {
+                        buffer.append(line_offset + 1, &highlight_label, Style::LabelPrimary);
+                    } else {
+                        buffer.append(line_offset + 1, &highlight_label, Style::LabelSecondary);
+                    }
+                    labeled_annotations = previous;
+                }
+            }
+        }
+
+        // If that's the last annotation, we're done
+        if labeled_annotations.is_empty() {
+            return;
+        }
+
+        for (index, annotation) in labeled_annotations.iter().enumerate() {
+            // Leave:
+            // - 1 extra line
+            // - One line for each thing that comes after
+            let comes_after = labeled_annotations.len() - index - 1;
+            let blank_lines = 3 + comes_after;
+
+            // For each blank line, draw a `|` at our column. The
+            // text ought to be long enough for this.
+            for index in 2..blank_lines {
+                if annotation.is_primary {
+                    buffer.putc(line_offset + index,
+                                width_offset + annotation.start_col,
+                                '|',
+                                Style::UnderlinePrimary);
+                } else {
+                    buffer.putc(line_offset + index,
+                                width_offset + annotation.start_col,
+                                '|',
+                                Style::UnderlineSecondary);
+                }
+                draw_col_separator(buffer, line_offset + index, width_offset - 2);
+            }
+
+            if annotation.is_primary {
+                buffer.puts(line_offset + blank_lines,
+                            width_offset + annotation.start_col,
+                            annotation.label.as_ref().unwrap(),
+                            Style::LabelPrimary);
             } else {
-                if !old_school {
-                    write!(self.dst, "\n")?;
+                buffer.puts(line_offset + blank_lines,
+                            width_offset + annotation.start_col,
+                            annotation.label.as_ref().unwrap(),
+                            Style::LabelSecondary);
+            }
+            draw_col_separator(buffer, line_offset + blank_lines, width_offset - 2);
+        }
+    }
+
+    fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
+        let mut max = 0;
+        if let Some(ref cm) = self.cm {
+            for primary_span in msp.primary_spans() {
+                if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP {
+                    let hi = cm.lookup_char_pos(primary_span.hi);
+                    if hi.line > max {
+                        max = hi.line;
+                    }
+                }
+            }
+            for span_label in msp.span_labels() {
+                if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP {
+                    let hi = cm.lookup_char_pos(span_label.span.hi);
+                    if hi.line > max {
+                        max = hi.line;
+                    }
+                }
+            }
+        }
+        max
+    }
+
+    fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize {
+        let mut max = 0;
+
+        let primary = self.get_multispan_max_line_num(&db.span);
+        max = if primary > max { primary } else { max };
+
+        for sub in &db.children {
+            let sub_result = self.get_multispan_max_line_num(&sub.span);
+            max = if sub_result > max { primary } else { max };
+        }
+        max
+    }
+
+    fn emit_message_default(&mut self,
+                            msp: &MultiSpan,
+                            msg: &str,
+                            code: &Option<String>,
+                            level: &Level,
+                            max_line_num_len: usize,
+                            is_secondary: bool)
+                            -> io::Result<()> {
+        let mut buffer = StyledBuffer::new();
+
+        if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary {
+            // This is a secondary message with no span info
+            for _ in 0..max_line_num_len {
+                buffer.prepend(0, " ", Style::NoStyle);
+            }
+            draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
+            buffer.append(0, &level.to_string(), Style::HeaderMsg);
+            buffer.append(0, ": ", Style::NoStyle);
+            buffer.append(0, msg, Style::NoStyle);
+        }
+        else {
+            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+            match code {
+                &Some(ref code) => {
+                    buffer.append(0, "[", Style::Level(level.clone()));
+                    buffer.append(0, &code, Style::Level(level.clone()));
+                    buffer.append(0, "]", Style::Level(level.clone()));
                 }
+                _ => {}
             }
+            buffer.append(0, ": ", Style::HeaderMsg);
+            buffer.append(0, msg, Style::HeaderMsg);
         }
 
-        match code {
-            Some(code) if self.registry.as_ref()
-                                       .and_then(|registry| registry.find_description(code))
-                                       .is_some() => {
-                let code_with_explain = String::from("--explain ") + code;
-                if old_school {
-                    let loc = match rsp.span().primary_span() {
-                        Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
-                        Some(ps) => self.cm.span_to_string(ps),
-                        None => "".to_string()
-                    };
-                    print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))?
+        // Preprocess all the annotations so that they are grouped by file and by line number
+        // This helps us quickly iterate over the whole message (including secondary file spans)
+        let mut annotated_files = self.preprocess_annotations(msp);
+
+        // Make sure our primary file comes first
+        let primary_lo =
+            if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(),
+                                                             msp.primary_span().as_ref()) {
+                if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP {
+                    cm.lookup_char_pos(primary_span.lo)
                 }
                 else {
-                    print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))?
+                    emit_to_destination(&buffer.render(), level, &mut self.dst)?;
+                    return Ok(());
+                }
+            } else {
+                // If we don't have span information, emit and exit
+                emit_to_destination(&buffer.render(), level, &mut self.dst)?;
+                return Ok(());
+            };
+        if let Ok(pos) =
+                annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) {
+            annotated_files.swap(0, pos);
+        }
+
+        // Print out the annotate source lines that correspond with the error
+        for annotated_file in annotated_files {
+            // print out the span location and spacer before we print the annotated source
+            // to do this, we need to know if this span will be primary
+            let is_primary = primary_lo.file.name == annotated_file.file.name;
+            if is_primary {
+                // remember where we are in the output buffer for easy reference
+                let buffer_msg_line_offset = buffer.num_lines();
+
+                buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
+                let loc = primary_lo.clone();
+                buffer.append(buffer_msg_line_offset,
+                                &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1),
+                                Style::LineAndColumn);
+                for _ in 0..max_line_num_len {
+                    buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
+                }
+            } else {
+                // remember where we are in the output buffer for easy reference
+                let buffer_msg_line_offset = buffer.num_lines();
+
+                // Add spacing line
+                draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
+
+                // Then, the secondary file indicator
+                buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
+                buffer.append(buffer_msg_line_offset + 1,
+                                &annotated_file.file.name,
+                                Style::LineAndColumn);
+                for _ in 0..max_line_num_len {
+                    buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle);
                 }
             }
-            _ => {
-                if old_school {
-                    let loc = match rsp.span().primary_span() {
-                        Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
-                        Some(ps) => self.cm.span_to_string(ps),
-                        None => "".to_string()
-                    };
-                    print_diagnostic(&mut self.dst, &loc, lvl, msg, code)?
+
+            // Put in the spacer between the location and annotated source
+            let buffer_msg_line_offset = buffer.num_lines();
+            draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
+
+            // Next, output the annotate source for this file
+            for line_idx in 0..annotated_file.lines.len() {
+                self.render_source_line(&mut buffer,
+                                        annotated_file.file.clone(),
+                                        &annotated_file.lines[line_idx],
+                                        3 + max_line_num_len);
+
+                // check to see if we need to print out or elide lines that come between
+                // this annotated line and the next one
+                if line_idx < (annotated_file.lines.len() - 1) {
+                    let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
+                                            annotated_file.lines[line_idx].line_index;
+                    if line_idx_delta > 2 {
+                        let last_buffer_line_num = buffer.num_lines();
+                        buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
+                    } else if line_idx_delta == 2 {
+                        let unannotated_line = annotated_file.file
+                            .get_line(annotated_file.lines[line_idx].line_index)
+                            .unwrap_or("");
+
+                        let last_buffer_line_num = buffer.num_lines();
+
+                        buffer.puts(last_buffer_line_num,
+                                    0,
+                                    &(annotated_file.lines[line_idx + 1].line_index - 1)
+                                        .to_string(),
+                                    Style::LineNumber);
+                        draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len);
+                        buffer.puts(last_buffer_line_num,
+                                    3 + max_line_num_len,
+                                    &unannotated_line,
+                                    Style::Quotation);
+                    }
                 }
-                else {
-                    print_diagnostic(&mut self.dst, "", lvl, msg, code)?
+            }
+        }
+
+        if let Some(ref primary_span) = msp.primary_span().as_ref() {
+            self.render_macro_backtrace_old_school(primary_span, &mut buffer)?;
+        }
+
+        // final step: take our styled buffer, render it, then output it
+        emit_to_destination(&buffer.render(), level, &mut self.dst)?;
+
+        Ok(())
+    }
+    fn emit_suggestion_default(&mut self,
+                               suggestion: &CodeSuggestion,
+                               level: &Level,
+                               msg: &str,
+                               max_line_num_len: usize)
+                               -> io::Result<()> {
+        use std::borrow::Borrow;
+
+        let primary_span = suggestion.msp.primary_span().unwrap();
+        if let Some(ref cm) = self.cm {
+            let mut buffer = StyledBuffer::new();
+
+            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+            buffer.append(0, ": ", Style::HeaderMsg);
+            buffer.append(0, msg, Style::HeaderMsg);
+
+            let lines = cm.span_to_lines(primary_span).unwrap();
+
+            assert!(!lines.lines.is_empty());
+
+            let complete = suggestion.splice_lines(cm.borrow());
+
+            // print the suggestion without any line numbers, but leave
+            // space for them. This helps with lining up with previous
+            // snippets from the actual error being reported.
+            let mut lines = complete.lines();
+            let mut row_num = 1;
+            for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
+                draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                buffer.append(row_num, line, Style::NoStyle);
+                row_num += 1;
+            }
+
+            // if we elided some lines, add an ellipsis
+            if let Some(_) = lines.next() {
+                buffer.append(row_num, "...", Style::NoStyle);
+            }
+            emit_to_destination(&buffer.render(), level, &mut self.dst)?;
+        }
+        Ok(())
+    }
+    fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
+        let max_line_num = self.get_max_line_num(db);
+        let max_line_num_len = max_line_num.to_string().len();
+
+        match self.emit_message_default(&db.span,
+                                        &db.message,
+                                        &db.code,
+                                        &db.level,
+                                        max_line_num_len,
+                                        false) {
+            Ok(()) => {
+                if !db.children.is_empty() {
+                    let mut buffer = StyledBuffer::new();
+                    draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
+                    match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) {
+                        Ok(()) => (),
+                        Err(e) => panic!("failed to emit error: {}", e)
+                    }
+                }
+                for child in &db.children {
+                    match child.render_span {
+                        Some(FullSpan(ref msp)) => {
+                            match self.emit_message_default(msp,
+                                                            &child.message,
+                                                            &None,
+                                                            &child.level,
+                                                            max_line_num_len,
+                                                            true) {
+                                Err(e) => panic!("failed to emit error: {}", e),
+                                _ => ()
+                            }
+                        },
+                        Some(Suggestion(ref cs)) => {
+                            match self.emit_suggestion_default(cs,
+                                                               &child.level,
+                                                               &child.message,
+                                                               max_line_num_len) {
+                                Err(e) => panic!("failed to emit error: {}", e),
+                                _ => ()
+                            }
+                        },
+                        None => {
+                            match self.emit_message_default(&child.span,
+                                                            &child.message,
+                                                            &None,
+                                                            &child.level,
+                                                            max_line_num_len,
+                                                            true) {
+                                Err(e) => panic!("failed to emit error: {}", e),
+                                _ => ()
+                            }
+                        }
+                    }
                 }
             }
+            Err(e) => panic!("failed to emit error: {}", e)
+        }
+        match write!(&mut self.dst, "\n") {
+            Err(e) => panic!("failed to emit error: {}", e),
+            _ => ()
+        }
+    }
+    fn emit_message_old_school(&mut self,
+                               msp: &MultiSpan,
+                               msg: &str,
+                               code: &Option<String>,
+                               level: &Level,
+                               show_snippet: bool)
+                               -> io::Result<()> {
+        let mut buffer = StyledBuffer::new();
+
+        let loc = match msp.primary_span() {
+            Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
+            Some(ps) => if let Some(ref cm) = self.cm {
+                cm.span_to_string(ps)
+            } else {
+                "".to_string()
+            },
+            None => {
+                "".to_string()
+            }
+        };
+        if loc != "" {
+            buffer.append(0, &loc, Style::NoStyle);
+            buffer.append(0, " ", Style::NoStyle);
+        }
+        buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+        buffer.append(0, ": ", Style::HeaderMsg);
+        buffer.append(0, msg, Style::HeaderMsg);
+        buffer.append(0, " ", Style::NoStyle);
+        match code {
+            &Some(ref code) => {
+                buffer.append(0, "[", Style::ErrorCode);
+                buffer.append(0, &code, Style::ErrorCode);
+                buffer.append(0, "]", Style::ErrorCode);
+            }
+            _ => {}
         }
 
         if !show_snippet {
+            emit_to_destination(&buffer.render(), level, &mut self.dst)?;
             return Ok(());
         }
 
         // Watch out for various nasty special spans; don't try to
         // print any filename or anything for those.
-        match rsp.span().primary_span() {
+        match msp.primary_span() {
             Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
+                emit_to_destination(&buffer.render(), level, &mut self.dst)?;
                 return Ok(());
             }
             _ => { }
         }
 
-        // Otherwise, print out the snippet etc as needed.
-        match *rsp {
-            FullSpan(ref msp) => {
-                self.highlight_lines(msp, lvl)?;
-                if let Some(primary_span) = msp.primary_span() {
-                    self.print_macro_backtrace(primary_span)?;
-                }
-            }
-            Suggestion(ref suggestion) => {
-                self.highlight_suggestion(suggestion)?;
-                if let Some(primary_span) = rsp.span().primary_span() {
-                    self.print_macro_backtrace(primary_span)?;
+        let annotated_files = self.preprocess_annotations(msp);
+
+        if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) =
+            (self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) {
+
+            // Next, print the source line and its squiggle
+            // for old school mode, we will render them to the buffer, then insert the file loc
+            // (or space the same amount) in front of the line and the squiggle
+            let source_string = ann_file.file.get_line(ann_file.lines[0].line_index - 1)
+                .unwrap_or("");
+
+            let line_offset = buffer.num_lines();
+
+            let lo = cm.lookup_char_pos(primary_span.lo);
+            //Before each secondary line in old skool-mode, print the label
+            //as an old-style note
+            let file_pos = format!("{}:{} ", lo.file.name.clone(), lo.line);
+            let file_pos_len = file_pos.len();
+
+            // First create the source line we will highlight.
+            buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle);
+            buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation);
+            // Sort the annotations by (start, end col)
+            let annotations = ann_file.lines[0].annotations.clone();
+
+            // Next, create the highlight line.
+            for annotation in &annotations {
+                for p in annotation.start_col..annotation.end_col {
+                    if p == annotation.start_col {
+                        buffer.putc(line_offset + 1,
+                                    file_pos_len + p,
+                                    '^',
+                                    if annotation.is_primary {
+                                        Style::UnderlinePrimary
+                                    } else {
+                                        Style::OldSchoolNote
+                                    });
+                    } else {
+                        buffer.putc(line_offset + 1,
+                                    file_pos_len + p,
+                                    '~',
+                                    if annotation.is_primary {
+                                        Style::UnderlinePrimary
+                                    } else {
+                                        Style::OldSchoolNote
+                                    });
+                    }
                 }
             }
         }
-        if old_school {
-            match code {
-                Some(code) if self.registry.as_ref()
-                                        .and_then(|registry| registry.find_description(code))
-                                        .is_some() => {
-                    let loc = match rsp.span().primary_span() {
-                        Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
-                        Some(ps) => self.cm.span_to_string(ps),
-                        None => "".to_string()
-                    };
-                    let msg = "run `rustc --explain ".to_string() + &code.to_string() +
-                        "` to see a detailed explanation";
-                    print_diagnostic(&mut self.dst, &loc, Level::Help, &msg,
-                        None)?
-                }
-                _ => ()
+        if let Some(ref primary_span) = msp.primary_span().as_ref() {
+            self.render_macro_backtrace_old_school(primary_span, &mut buffer)?;
+        }
+
+        match code {
+            &Some(ref code) if self.registry.as_ref()
+                                           .and_then(|registry| registry.find_description(code))
+                                           .is_some() => {
+                let msg = "run `rustc --explain ".to_string() + &code.to_string() +
+                    "` to see a detailed explanation";
+
+                let line_offset = buffer.num_lines();
+                buffer.append(line_offset, &loc, Style::NoStyle);
+                buffer.append(line_offset, " ", Style::NoStyle);
+                buffer.append(line_offset, &Level::Help.to_string(), Style::Level(Level::Help));
+                buffer.append(line_offset, ": ", Style::HeaderMsg);
+                buffer.append(line_offset, &msg, Style::HeaderMsg);
             }
+            _ => ()
         }
+
+        // final step: take our styled buffer, render it, then output it
+        emit_to_destination(&buffer.render(), level, &mut self.dst)?;
         Ok(())
     }
-
-    fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()>
-    {
+    fn emit_suggestion_old_school(&mut self,
+                                  suggestion: &CodeSuggestion,
+                                  level: &Level,
+                                  msg: &str)
+                                  -> io::Result<()> {
         use std::borrow::Borrow;
 
         let primary_span = suggestion.msp.primary_span().unwrap();
-        let lines = self.cm.span_to_lines(primary_span).unwrap();
-        assert!(!lines.lines.is_empty());
+        if let Some(ref cm) = self.cm {
+            let mut buffer = StyledBuffer::new();
 
-        let complete = suggestion.splice_lines(self.cm.borrow());
-        let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
-        let display_lines = &lines.lines[..line_count];
+            let loc = cm.span_to_string(primary_span);
 
-        let fm = &*lines.file;
-        // Calculate the widest number to format evenly
-        let max_digits = line_num_max_digits(display_lines.last().unwrap());
+            if loc != "" {
+                buffer.append(0, &loc, Style::NoStyle);
+                buffer.append(0, " ", Style::NoStyle);
+            }
 
-        // print the suggestion without any line numbers, but leave
-        // space for them. This helps with lining up with previous
-        // snippets from the actual error being reported.
-        let mut lines = complete.lines();
-        for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
-            write!(&mut self.dst, "{0}:{1:2$} {3}\n",
-                   fm.name, "", max_digits, line)?;
-        }
+            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+            buffer.append(0, ": ", Style::HeaderMsg);
+            buffer.append(0, msg, Style::HeaderMsg);
 
-        // if we elided some lines, add an ellipsis
-        if let Some(_) = lines.next() {
-            write!(&mut self.dst, "{0:1$} {0:2$} ...\n",
-                   "", fm.name.len(), max_digits)?;
-        }
+            let lines = cm.span_to_lines(primary_span).unwrap();
 
-        Ok(())
-    }
+            assert!(!lines.lines.is_empty());
 
-    pub fn highlight_lines(&mut self,
-                       msp: &MultiSpan,
-                       lvl: Level)
-                       -> io::Result<()>
-    {
-        let old_school = match self.format_mode {
-            FormatMode::NewErrorFormat => false,
-            FormatMode::OriginalErrorFormat => true,
-            FormatMode::EnvironmentSelected => check_old_skool()
-        };
+            let complete = suggestion.splice_lines(cm.borrow());
+            let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
+            let display_lines = &lines.lines[..line_count];
 
-        let mut snippet_data = SnippetData::new(self.cm.clone(),
-                                                msp.primary_span(),
-                                                self.format_mode.clone());
-        if old_school {
-            let mut output_vec = vec![];
+            let fm = &*lines.file;
+            // Calculate the widest number to format evenly
+            let max_digits = line_num_max_digits(display_lines.last().unwrap());
 
-            for span_label in msp.span_labels() {
-                let mut snippet_data = SnippetData::new(self.cm.clone(),
-                                                        Some(span_label.span),
-                                                        self.format_mode.clone());
-
-                snippet_data.push(span_label.span,
-                                  span_label.is_primary,
-                                  span_label.label);
-                if span_label.is_primary {
-                    output_vec.insert(0, snippet_data);
-                }
-                else {
-                    output_vec.push(snippet_data);
+            // print the suggestion without any line numbers, but leave
+            // space for them. This helps with lining up with previous
+            // snippets from the actual error being reported.
+            let mut lines = complete.lines();
+            let mut row_num = 1;
+            for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
+                buffer.append(row_num, &fm.name, Style::FileNameStyle);
+                for _ in 0..max_digits+2 {
+                    buffer.append(row_num, &" ", Style::NoStyle);
                 }
+                buffer.append(row_num, line, Style::NoStyle);
+                row_num += 1;
+            }
+
+            // if we elided some lines, add an ellipsis
+            if let Some(_) = lines.next() {
+                buffer.append(row_num, "...", Style::NoStyle);
             }
+            emit_to_destination(&buffer.render(), level, &mut self.dst)?;
+        }
+        Ok(())
+    }
 
-            for snippet_data in output_vec.iter() {
-                let rendered_lines = snippet_data.render_lines();
-                for rendered_line in &rendered_lines {
-                    for styled_string in &rendered_line.text {
-                        self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
-                        write!(&mut self.dst, "{}", styled_string.text)?;
-                        self.dst.reset_attrs()?;
+    fn emit_messages_old_school(&mut self, db: &DiagnosticBuilder) {
+        match self.emit_message_old_school(&db.span,
+                                           &db.message,
+                                           &db.code,
+                                           &db.level,
+                                           true) {
+            Ok(()) => {
+                for child in &db.children {
+                    let (span, show_snippet) = if child.span.primary_spans().is_empty() {
+                        (db.span.clone(), false)
+                    } else {
+                        (child.span.clone(), true)
+                    };
+
+                    match child.render_span {
+                        Some(FullSpan(_)) => {
+                            match self.emit_message_old_school(&span,
+                                                               &child.message,
+                                                               &None,
+                                                               &child.level,
+                                                               show_snippet) {
+                                Err(e) => panic!("failed to emit error: {}", e),
+                                _ => ()
+                            }
+                        },
+                        Some(Suggestion(ref cs)) => {
+                            match self.emit_suggestion_old_school(cs,
+                                                                  &child.level,
+                                                                  &child.message) {
+                                Err(e) => panic!("failed to emit error: {}", e),
+                                _ => ()
+                            }
+                        },
+                        None => {
+                            match self.emit_message_old_school(&span,
+                                                               &child.message,
+                                                               &None,
+                                                               &child.level,
+                                                               show_snippet) {
+                                Err(e) => panic!("failed to emit error: {}", e),
+                                _ => ()
+                            }
+                        }
                     }
-                    write!(&mut self.dst, "\n")?;
                 }
             }
+            Err(e) => panic!("failed to emit error: {}", e)
         }
-        else {
-            for span_label in msp.span_labels() {
-                snippet_data.push(span_label.span,
-                                  span_label.is_primary,
-                                  span_label.label);
-            }
-            let rendered_lines = snippet_data.render_lines();
-            for rendered_line in &rendered_lines {
-                for styled_string in &rendered_line.text {
-                    self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
-                    write!(&mut self.dst, "{}", styled_string.text)?;
-                    self.dst.reset_attrs()?;
+    }
+
+    fn render_macro_backtrace_old_school(&mut self,
+                                         sp: &Span,
+                                         buffer: &mut StyledBuffer) -> io::Result<()> {
+        if let Some(ref cm) = self.cm {
+            for trace in cm.macro_backtrace(sp.clone()) {
+                let line_offset = buffer.num_lines();
+
+                let mut diag_string =
+                    format!("in this expansion of {}", trace.macro_decl_name);
+                if let Some(def_site_span) = trace.def_site_span {
+                    diag_string.push_str(
+                        &format!(" (defined in {})",
+                            cm.span_to_filename(def_site_span)));
                 }
-                write!(&mut self.dst, "\n")?;
+                let snippet = cm.span_to_string(trace.call_site);
+                buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle);
+                buffer.append(line_offset, "note", Style::Level(Level::Note));
+                buffer.append(line_offset, ": ", Style::NoStyle);
+                buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText);
             }
         }
         Ok(())
     }
+}
 
-    fn print_macro_backtrace(&mut self,
-                             sp: Span)
-                             -> io::Result<()> {
-        for trace in self.cm.macro_backtrace(sp) {
-            let mut diag_string =
-                format!("in this expansion of {}", trace.macro_decl_name);
-            if let Some(def_site_span) = trace.def_site_span {
-                diag_string.push_str(
-                    &format!(" (defined in {})",
-                        self.cm.span_to_filename(def_site_span)));
-            }
-            let snippet = self.cm.span_to_string(trace.call_site);
-            print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
+fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
+    buffer.puts(line, col, "| ", Style::LineNumber);
+}
+
+fn draw_col_separator_no_space(buffer: &mut StyledBuffer, line: usize, col: usize) {
+    buffer.puts(line, col, "|", Style::LineNumber);
+}
+
+fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
+    buffer.puts(line, col, "= ", Style::LineNumber);
+}
+
+fn overlaps(a1: &Annotation, a2: &Annotation) -> bool {
+    (a2.start_col..a2.end_col).contains(a1.start_col) ||
+    (a1.start_col..a1.end_col).contains(a2.start_col)
+}
+
+fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
+        lvl: &Level,
+        dst: &mut Destination) -> io::Result<()> {
+    for line in rendered_buffer {
+        for part in line {
+            dst.apply_style(lvl.clone(), part.style)?;
+            write!(dst, "{}", part.text)?;
+            dst.reset_attrs()?;
         }
-        Ok(())
+        write!(dst, "\n")?;
     }
+    Ok(())
 }
 
 fn line_num_max_digits(line: &LineInfo) -> usize {
@@ -456,40 +968,6 @@ fn line_num_max_digits(line: &LineInfo) -> usize {
     digits
 }
 
-fn print_diagnostic(dst: &mut Destination,
-                    topic: &str,
-                    lvl: Level,
-                    msg: &str,
-                    code: Option<&str>)
-                    -> io::Result<()> {
-    if !topic.is_empty() {
-        let old_school = check_old_skool();
-        if !old_school {
-            write!(dst, "{}: ", topic)?;
-        }
-        else {
-            write!(dst, "{} ", topic)?;
-        }
-        dst.reset_attrs()?;
-    }
-    dst.start_attr(term::Attr::Bold)?;
-    dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
-    write!(dst, "{}", lvl.to_string())?;
-    dst.reset_attrs()?;
-    write!(dst, ": ")?;
-    dst.start_attr(term::Attr::Bold)?;
-    write!(dst, "{}", msg)?;
-
-    if let Some(code) = code {
-        let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
-        print_maybe_styled!(dst, style, " [{}]", code.clone())?;
-    }
-
-    dst.reset_attrs()?;
-    write!(dst, "\n")?;
-    Ok(())
-}
-
 #[cfg(unix)]
 fn stderr_isatty() -> bool {
     use libc;
@@ -513,7 +991,7 @@ fn GetConsoleMode(hConsoleHandle: HANDLE,
     }
 }
 
-enum Destination {
+pub enum Destination {
     Terminal(Box<term::StderrTerminal>),
     Raw(Box<Write + Send>),
 }
@@ -528,35 +1006,39 @@ fn from_stderr() -> Destination {
 
     fn apply_style(&mut self,
                    lvl: Level,
-                   _kind: &RenderedLineKind,
                    style: Style)
                    -> io::Result<()> {
         match style {
-            Style::FileNameStyle |
-            Style::LineAndColumn => {
-            }
+            Style::FileNameStyle | Style::LineAndColumn => {}
             Style::LineNumber => {
-                self.start_attr(term::Attr::Bold)?;
-                self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
+                try!(self.start_attr(term::Attr::Bold));
+                try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
             }
-            Style::Quotation => {
+            Style::ErrorCode => {
+                try!(self.start_attr(term::Attr::Bold));
+                try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA)));
             }
-            Style::OldSkoolNote => {
-                self.start_attr(term::Attr::Bold)?;
-                self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?;
+            Style::Quotation => {}
+            Style::OldSchoolNote => {
+                try!(self.start_attr(term::Attr::Bold));
+                try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN)));
             }
-            Style::OldSkoolNoteText => {
-                self.start_attr(term::Attr::Bold)?;
+            Style::OldSchoolNoteText | Style::HeaderMsg => {
+                try!(self.start_attr(term::Attr::Bold));
             }
             Style::UnderlinePrimary | Style::LabelPrimary => {
-                self.start_attr(term::Attr::Bold)?;
-                self.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
+                try!(self.start_attr(term::Attr::Bold));
+                try!(self.start_attr(term::Attr::ForegroundColor(lvl.color())));
             }
-            Style::UnderlineSecondary | Style::LabelSecondary => {
-                self.start_attr(term::Attr::Bold)?;
-                self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
+            Style::UnderlineSecondary |
+            Style::LabelSecondary => {
+                try!(self.start_attr(term::Attr::Bold));
+                try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
             }
-            Style::NoStyle => {
+            Style::NoStyle => {}
+            Style::Level(l) => {
+                try!(self.start_attr(term::Attr::Bold));
+                try!(self.start_attr(term::Attr::ForegroundColor(l.color())));
             }
         }
         Ok(())
@@ -577,46 +1059,6 @@ fn reset_attrs(&mut self) -> io::Result<()> {
         }
         Ok(())
     }
-
-    fn print_maybe_styled(&mut self,
-                          args: fmt::Arguments,
-                          color: term::Attr,
-                          print_newline_at_end: bool)
-                          -> io::Result<()> {
-        match *self {
-            Terminal(ref mut t) => {
-                t.attr(color)?;
-                // If `msg` ends in a newline, we need to reset the color before
-                // the newline. We're making the assumption that we end up writing
-                // to a `LineBufferedWriter`, which means that emitting the reset
-                // after the newline ends up buffering the reset until we print
-                // another line or exit. Buffering the reset is a problem if we're
-                // sharing the terminal with any other programs (e.g. other rustc
-                // instances via `make -jN`).
-                //
-                // Note that if `msg` contains any internal newlines, this will
-                // result in the `LineBufferedWriter` flushing twice instead of
-                // once, which still leaves the opportunity for interleaved output
-                // to be miscolored. We assume this is rare enough that we don't
-                // have to worry about it.
-                t.write_fmt(args)?;
-                t.reset()?;
-                if print_newline_at_end {
-                    t.write_all(b"\n")
-                } else {
-                    Ok(())
-                }
-            }
-            Raw(ref mut w) => {
-                w.write_fmt(args)?;
-                if print_newline_at_end {
-                    w.write_all(b"\n")
-                } else {
-                    Ok(())
-                }
-            }
-        }
-    }
 }
 
 impl Write for Destination {
@@ -632,4 +1074,4 @@ fn flush(&mut self) -> io::Result<()> {
             Raw(ref mut w) => w.flush(),
         }
     }
-}
+}
\ No newline at end of file
index 18fc826f9aa4bc5840fb8e7b05c10732c07ab33b..6a48f65714cc50d95e6463d337ec64af32233dd1 100644 (file)
@@ -49,6 +49,7 @@
 pub mod emitter;
 pub mod snippet;
 pub mod registry;
+pub mod styled_buffer;
 
 use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
 use syntax_pos::{MacroBacktrace};
@@ -81,16 +82,6 @@ pub trait CodeMapper {
     fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
 }
 
-impl RenderSpan {
-    fn span(&self) -> &MultiSpan {
-        match *self {
-            FullSpan(ref msp) |
-            Suggestion(CodeSuggestion { ref msp, .. }) =>
-                msp
-        }
-    }
-}
-
 impl CodeSuggestion {
     /// Returns the assembled code suggestion.
     pub fn splice_lines(&self, cm: &CodeMapper) -> String {
@@ -238,7 +229,7 @@ pub fn emit(&mut self) {
             return;
         }
 
-        self.handler.emit.borrow_mut().emit_struct(&self);
+        self.handler.emitter.borrow_mut().emit(&self);
         self.cancel();
         self.handler.panic_if_treat_err_as_bug();
 
@@ -359,11 +350,20 @@ pub fn level(&self) -> Level {
     fn new(handler: &'a Handler,
            level: Level,
            message: &str) -> DiagnosticBuilder<'a> {
+        DiagnosticBuilder::new_with_code(handler, level, None, message)
+    }
+
+    /// Convenience function for internal use, clients should use one of the
+    /// struct_* methods on Handler.
+    fn new_with_code(handler: &'a Handler,
+           level: Level,
+           code: Option<String>,
+           message: &str) -> DiagnosticBuilder<'a> {
         DiagnosticBuilder {
             handler: handler,
             level: level,
             message: message.to_owned(),
-            code: None,
+            code: code,
             span: MultiSpan::new(),
             children: vec![],
         }
@@ -397,10 +397,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl<'a> Drop for DiagnosticBuilder<'a> {
     fn drop(&mut self) {
         if !panicking() && !self.cancelled() {
-            self.handler.emit.borrow_mut().emit(&MultiSpan::new(),
-                                                "Error constructed but not emitted",
-                                                None,
-                                                Bug);
+            let mut db = DiagnosticBuilder::new(self.handler,
+                                                Bug,
+                                                "Error constructed but not emitted");
+            db.emit();
             panic!();
         }
     }
@@ -411,7 +411,7 @@ fn drop(&mut self) {
 /// others log errors for later reporting.
 pub struct Handler {
     err_count: Cell<usize>,
-    emit: RefCell<Box<Emitter>>,
+    emitter: RefCell<Box<Emitter>>,
     pub can_emit_warnings: bool,
     treat_err_as_bug: bool,
     continue_after_error: Cell<bool>,
@@ -423,7 +423,7 @@ pub fn with_tty_emitter(color_config: ColorConfig,
                             registry: Option<registry::Registry>,
                             can_emit_warnings: bool,
                             treat_err_as_bug: bool,
-                            cm: Rc<CodeMapper>)
+                            cm: Option<Rc<CodeMapper>>)
                             -> Handler {
         let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm,
                                snippet::FormatMode::EnvironmentSelected));
@@ -435,7 +435,7 @@ pub fn with_emitter(can_emit_warnings: bool,
                         e: Box<Emitter>) -> Handler {
         Handler {
             err_count: Cell::new(0),
-            emit: RefCell::new(e),
+            emitter: RefCell::new(e),
             can_emit_warnings: can_emit_warnings,
             treat_err_as_bug: treat_err_as_bug,
             continue_after_error: Cell::new(true),
@@ -588,7 +588,7 @@ pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.bump_err_count();
     }
     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.emit.borrow_mut().emit(&sp.into(), msg, None, Note);
+        self.emit(&sp.into(), msg, Note);
     }
     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
         self.span_bug(sp, &format!("unimplemented {}", msg));
@@ -597,7 +597,10 @@ pub fn fatal(&self, msg: &str) -> FatalError {
         if self.treat_err_as_bug {
             self.bug(msg);
         }
-        self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal);
+        let mut db = DiagnosticBuilder::new(self,
+                                            Fatal,
+                                            msg);
+        db.emit();
         self.bump_err_count();
         FatalError
     }
@@ -605,17 +608,29 @@ pub fn err(&self, msg: &str) {
         if self.treat_err_as_bug {
             self.bug(msg);
         }
-        self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error);
+        let mut db = DiagnosticBuilder::new(self,
+                                            Error,
+                                            msg);
+        db.emit();
         self.bump_err_count();
     }
     pub fn warn(&self, msg: &str) {
-        self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning);
+        let mut db = DiagnosticBuilder::new(self,
+                                            Warning,
+                                            msg);
+        db.emit();
     }
     pub fn note_without_error(&self, msg: &str) {
-        self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note);
+        let mut db = DiagnosticBuilder::new(self,
+                                            Note,
+                                            msg);
+        db.emit();
     }
     pub fn bug(&self, msg: &str) -> ! {
-        self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug);
+        let mut db = DiagnosticBuilder::new(self,
+                                            Bug,
+                                            msg);
+        db.emit();
         panic!(ExplicitBug);
     }
     pub fn unimpl(&self, msg: &str) -> ! {
@@ -661,7 +676,9 @@ pub fn emit(&self,
                 msg: &str,
                 lvl: Level) {
         if lvl == Warning && !self.can_emit_warnings { return }
-        self.emit.borrow_mut().emit(&msp, msg, None, lvl);
+        let mut db = DiagnosticBuilder::new(self, lvl, msg);
+        db.set_span(msp.clone());
+        db.emit();
         if !self.continue_after_error.get() { self.abort_if_errors(); }
     }
     pub fn emit_with_code(&self,
@@ -670,7 +687,12 @@ pub fn emit_with_code(&self,
                           code: &str,
                           lvl: Level) {
         if lvl == Warning && !self.can_emit_warnings { return }
-        self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl);
+        let mut db = DiagnosticBuilder::new_with_code(self,
+                                                      lvl,
+                                                      Some(code.to_owned()),
+                                                      msg);
+        db.set_span(msp.clone());
+        db.emit();
         if !self.continue_after_error.get() { self.abort_if_errors(); }
     }
 }
@@ -734,13 +756,13 @@ pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
 ///
 /// FIXME(#33240)
 #[cfg(not(test))]
-pub fn check_old_skool() -> bool {
+pub fn check_old_school() -> bool {
     use std::env;
     env::var("RUST_NEW_ERROR_FORMAT").is_err()
 }
 
 /// For unit tests, use the new format.
 #[cfg(test)]
-pub fn check_old_skool() -> bool {
+pub fn check_old_school() -> bool {
     false
 }
index 33f40ffc71a9f69b78b965db5c2f7cb066503e4c..2f94a7f6832fe34401b3a52b6d54cb7d610023ef 100644 (file)
 
 // Code for annotating snippets.
 
-use syntax_pos::{Span, FileMap, CharPos, LineInfo};
-use check_old_skool;
+use syntax_pos::{Span, FileMap};
 use CodeMapper;
-use std::cmp;
 use std::rc::Rc;
-use std::mem;
+use {Level};
 
 #[derive(Clone)]
 pub enum FormatMode {
@@ -49,37 +47,31 @@ pub struct FileInfo {
     format_mode: FormatMode,
 }
 
-#[derive(Clone, Debug)]
-struct Line {
-    line_index: usize,
-    annotations: Vec<Annotation>,
+#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Line {
+    pub line_index: usize,
+    pub annotations: Vec<Annotation>,
 }
 
 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
-struct Annotation {
+pub struct Annotation {
     /// Start column, 0-based indexing -- counting *characters*, not
     /// utf-8 bytes. Note that it is important that this field goes
     /// first, so that when we sort, we sort orderings by start
     /// column.
-    start_col: usize,
+    pub start_col: usize,
 
     /// End column within the line (exclusive)
-    end_col: usize,
+    pub end_col: usize,
 
     /// Is this annotation derived from primary span
-    is_primary: bool,
+    pub is_primary: bool,
 
     /// Is this a large span minimized down to a smaller span
-    is_minimized: bool,
+    pub is_minimized: bool,
 
     /// Optional label to display adjacent to the annotation.
-    label: Option<String>,
-}
-
-#[derive(Debug)]
-pub struct RenderedLine {
-    pub text: Vec<StyledString>,
-    pub kind: RenderedLineKind,
+    pub label: Option<String>,
 }
 
 #[derive(Debug)]
@@ -88,14 +80,9 @@ pub struct StyledString {
     pub style: Style,
 }
 
-#[derive(Debug)]
-pub struct StyledBuffer {
-    text: Vec<Vec<char>>,
-    styles: Vec<Vec<Style>>
-}
-
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum Style {
+    HeaderMsg,
     FileNameStyle,
     LineAndColumn,
     LineNumber,
@@ -104,813 +91,9 @@ pub enum Style {
     UnderlineSecondary,
     LabelPrimary,
     LabelSecondary,
-    OldSkoolNoteText,
-    OldSkoolNote,
+    OldSchoolNoteText,
+    OldSchoolNote,
     NoStyle,
-}
-
-#[derive(Debug, Clone)]
-pub enum RenderedLineKind {
-    PrimaryFileName,
-    OtherFileName,
-    SourceText {
-        file: Rc<FileMap>,
-        line_index: usize,
-    },
-    Annotations,
-    Elision,
-}
-
-impl SnippetData {
-    pub fn new(codemap: Rc<CodeMapper>,
-               primary_span: Option<Span>,
-               format_mode: FormatMode) // (*)
-               -> Self {
-        // (*) The primary span indicates the file that must appear
-        // first, and which will have a line number etc in its
-        // name. Outside of tests, this is always `Some`, but for many
-        // tests it's not relevant to test this portion of the logic,
-        // and it's tedious to pick a primary span (read: tedious to
-        // port older tests that predate the existence of a primary
-        // span).
-
-        debug!("SnippetData::new(primary_span={:?})", primary_span);
-
-        let mut data = SnippetData {
-            codemap: codemap.clone(),
-            files: vec![],
-            format_mode: format_mode.clone()
-        };
-        if let Some(primary_span) = primary_span {
-            let lo = codemap.lookup_char_pos(primary_span.lo);
-            data.files.push(
-                FileInfo {
-                    file: lo.file,
-                    primary_span: Some(primary_span),
-                    lines: vec![],
-                    format_mode: format_mode.clone(),
-                });
-        }
-        data
-    }
-
-    pub fn push(&mut self, span: Span, is_primary: bool, label: Option<String>) {
-        debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})",
-               span, is_primary, label);
-
-        let file_lines = match self.codemap.span_to_lines(span) {
-            Ok(file_lines) => file_lines,
-            Err(_) => {
-                // ignore unprintable spans completely.
-                return;
-            }
-        };
-
-        self.file(&file_lines.file)
-            .push_lines(&file_lines.lines, is_primary, label);
-    }
-
-    fn file(&mut self, file_map: &Rc<FileMap>) -> &mut FileInfo {
-        let index = self.files.iter().position(|f| f.file.name == file_map.name);
-        if let Some(index) = index {
-            return &mut self.files[index];
-        }
-
-        self.files.push(
-            FileInfo {
-                file: file_map.clone(),
-                lines: vec![],
-                primary_span: None,
-                format_mode: self.format_mode.clone()
-            });
-        self.files.last_mut().unwrap()
-    }
-
-    pub fn render_lines(&self) -> Vec<RenderedLine> {
-        debug!("SnippetData::render_lines()");
-
-        let mut rendered_lines: Vec<_> =
-            self.files.iter()
-                      .flat_map(|f| f.render_file_lines(&self.codemap))
-                      .collect();
-        prepend_prefixes(&mut rendered_lines, &self.format_mode);
-        trim_lines(&mut rendered_lines);
-        rendered_lines
-    }
-}
-
-pub trait StringSource {
-    fn make_string(self) -> String;
-}
-
-impl StringSource for String {
-    fn make_string(self) -> String {
-        self
-    }
-}
-
-impl StringSource for Vec<char> {
-    fn make_string(self) -> String {
-        self.into_iter().collect()
-    }
-}
-
-impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine
-    where S: StringSource
-{
-    fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self {
-        RenderedLine {
-            text: vec![StyledString {
-                text: text.make_string(),
-                style: style,
-            }],
-            kind: kind,
-        }
-    }
-}
-
-impl<S1,S2> From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine
-    where S1: StringSource, S2: StringSource
-{
-    fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self {
-        let (text1, style1, text2, style2, kind) = tuple;
-        RenderedLine {
-            text: vec![
-                StyledString {
-                    text: text1.make_string(),
-                    style: style1,
-                },
-                StyledString {
-                    text: text2.make_string(),
-                    style: style2,
-                }
-            ],
-            kind: kind,
-        }
-    }
-}
-
-impl RenderedLine {
-    fn trim_last(&mut self) {
-        if let Some(last_text) = self.text.last_mut() {
-            let len = last_text.text.trim_right().len();
-            last_text.text.truncate(len);
-        }
-    }
-}
-
-impl RenderedLineKind {
-    fn prefix(&self) -> StyledString {
-        match *self {
-            RenderedLineKind::SourceText { file: _, line_index } =>
-                StyledString {
-                    text: format!("{}", line_index + 1),
-                    style: Style::LineNumber,
-                },
-            RenderedLineKind::Elision =>
-                StyledString {
-                    text: String::from("..."),
-                    style: Style::LineNumber,
-                },
-            RenderedLineKind::PrimaryFileName |
-            RenderedLineKind::OtherFileName |
-            RenderedLineKind::Annotations =>
-                StyledString {
-                    text: String::from(""),
-                    style: Style::LineNumber,
-                },
-        }
-    }
-}
-
-impl StyledBuffer {
-    fn new() -> StyledBuffer {
-        StyledBuffer { text: vec![], styles: vec![] }
-    }
-
-    fn render(&self, source_kind: RenderedLineKind) -> Vec<RenderedLine> {
-        let mut output: Vec<RenderedLine> = vec![];
-        let mut styled_vec: Vec<StyledString> = vec![];
-
-        for (row, row_style) in self.text.iter().zip(&self.styles) {
-            let mut current_style = Style::NoStyle;
-            let mut current_text = String::new();
-
-            for (&c, &s) in row.iter().zip(row_style) {
-                if s != current_style {
-                    if !current_text.is_empty() {
-                        styled_vec.push(StyledString { text: current_text, style: current_style });
-                    }
-                    current_style = s;
-                    current_text = String::new();
-                }
-                current_text.push(c);
-            }
-            if !current_text.is_empty() {
-                styled_vec.push(StyledString { text: current_text, style: current_style });
-            }
-
-            if output.is_empty() {
-                //We know our first output line is source and the rest are highlights and labels
-                output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() });
-            } else {
-                output.push(RenderedLine { text: styled_vec, kind: RenderedLineKind::Annotations });
-            }
-            styled_vec = vec![];
-        }
-
-        output
-    }
-
-    fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
-        while line >= self.text.len() {
-            self.text.push(vec![]);
-            self.styles.push(vec![]);
-        }
-
-        if col < self.text[line].len() {
-            self.text[line][col] = chr;
-            self.styles[line][col] = style;
-        } else {
-            let mut i = self.text[line].len();
-            while i < col {
-                let s = match self.text[0].get(i) {
-                    Some(&'\t') => '\t',
-                    _ => ' '
-                };
-                self.text[line].push(s);
-                self.styles[line].push(Style::NoStyle);
-                i += 1;
-            }
-            self.text[line].push(chr);
-            self.styles[line].push(style);
-        }
-    }
-
-    fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
-        let mut n = col;
-        for c in string.chars() {
-            self.putc(line, n, c, style);
-            n += 1;
-        }
-    }
-
-    fn set_style(&mut self, line: usize, col: usize, style: Style) {
-        if self.styles.len() > line && self.styles[line].len() > col {
-            self.styles[line][col] = style;
-        }
-    }
-
-    fn append(&mut self, line: usize, string: &str, style: Style) {
-        if line >= self.text.len() {
-            self.puts(line, 0, string, style);
-        } else {
-            let col = self.text[line].len();
-            self.puts(line, col, string, style);
-        }
-    }
-}
-
-impl FileInfo {
-    fn push_lines(&mut self,
-                  lines: &[LineInfo],
-                  is_primary: bool,
-                  label: Option<String>) {
-        assert!(lines.len() > 0);
-
-        // If a span covers multiple lines, we reduce it to a single
-        // point at the start of the span. This means that instead
-        // of producing output like this:
-        //
-        // ```
-        // --> foo.rs:2:1
-        // 2   |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
-        //     |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        // 3   |>                               -> Set<LR0Item<'grammar>>
-        //     |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        // (and so on)
-        // ```
-        //
-        // we produce:
-        //
-        // ```
-        // --> foo.rs:2:1
-        // 2   |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
-        //        ^
-        // ```
-        //
-        // Basically, although this loses information, multi-line spans just
-        // never look good.
-
-        let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 {
-            (lines[0].line_index, lines[0].start_col, lines[0].end_col, false)
-        } else {
-            (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true)
-        };
-
-        // Watch out for "empty spans". If we get a span like 6..6, we
-        // want to just display a `^` at 6, so convert that to
-        // 6..7. This is degenerate input, but it's best to degrade
-        // gracefully -- and the parser likes to suply a span like
-        // that for EOF, in particular.
-        if start_col == end_col {
-            end_col.0 += 1;
-        }
-
-        let index = self.ensure_source_line(line);
-        self.lines[index].push_annotation(start_col,
-                                          end_col,
-                                          is_primary,
-                                          is_minimized,
-                                          label);
-    }
-
-    /// Ensure that we have a `Line` struct corresponding to
-    /// `line_index` in the file. If we already have some other lines,
-    /// then this will add the intervening lines to ensure that we
-    /// have a complete snippet. (Note that when we finally display,
-    /// some of those lines may be elided.)
-    fn ensure_source_line(&mut self, line_index: usize) -> usize {
-        if self.lines.is_empty() {
-            self.lines.push(Line::new(line_index));
-            return 0;
-        }
-
-        // Find the range of lines we have thus far.
-        let first_line_index = self.lines.first().unwrap().line_index;
-        let last_line_index = self.lines.last().unwrap().line_index;
-        assert!(first_line_index <= last_line_index);
-
-        // If the new line is lower than all the lines we have thus
-        // far, then insert the new line and any intervening lines at
-        // the front. In a silly attempt at micro-optimization, we
-        // don't just call `insert` repeatedly, but instead make a new
-        // (empty) vector, pushing the new lines onto it, and then
-        // appending the old vector.
-        if line_index < first_line_index {
-            let lines = mem::replace(&mut self.lines, vec![]);
-            self.lines.extend(
-                (line_index .. first_line_index)
-                    .map(|line| Line::new(line))
-                    .chain(lines));
-            return 0;
-        }
-
-        // If the new line comes after the ones we have so far, insert
-        // lines for it.
-        if line_index > last_line_index {
-            self.lines.extend(
-                (last_line_index+1 .. line_index+1)
-                    .map(|line| Line::new(line)));
-            return self.lines.len() - 1;
-        }
-
-        // Otherwise it should already exist.
-        return line_index - first_line_index;
-    }
-
-    fn render_file_lines(&self, codemap: &Rc<CodeMapper>) -> Vec<RenderedLine> {
-        let old_school = match self.format_mode {
-            FormatMode::OriginalErrorFormat => true,
-            FormatMode::NewErrorFormat => false,
-            FormatMode::EnvironmentSelected => check_old_skool()
-        };
-
-        // As a first step, we elide any instance of more than one
-        // continuous unannotated line.
-
-        let mut lines_iter = self.lines.iter();
-        let mut output = vec![];
-
-        // First insert the name of the file.
-        if !old_school {
-            match self.primary_span {
-                Some(span) => {
-                    let lo = codemap.lookup_char_pos(span.lo);
-                    output.push(RenderedLine {
-                        text: vec![StyledString {
-                            text: lo.file.name.clone(),
-                            style: Style::FileNameStyle,
-                        }, StyledString {
-                            text: format!(":{}:{}", lo.line, lo.col.0 + 1),
-                            style: Style::LineAndColumn,
-                        }],
-                        kind: RenderedLineKind::PrimaryFileName,
-                    });
-                    output.push(RenderedLine {
-                        text: vec![StyledString {
-                            text: "".to_string(),
-                            style: Style::FileNameStyle,
-                        }],
-                        kind: RenderedLineKind::Annotations,
-                    });
-                }
-                None => {
-                    output.push(RenderedLine {
-                        text: vec![StyledString {
-                            text: self.file.name.clone(),
-                            style: Style::FileNameStyle,
-                        }],
-                        kind: RenderedLineKind::OtherFileName,
-                    });
-                    output.push(RenderedLine {
-                        text: vec![StyledString {
-                            text: "".to_string(),
-                            style: Style::FileNameStyle,
-                        }],
-                        kind: RenderedLineKind::Annotations,
-                    });
-                }
-            }
-        }
-
-        let mut next_line = lines_iter.next();
-        while next_line.is_some() {
-            // Consume lines with annotations.
-            while let Some(line) = next_line {
-                if line.annotations.is_empty() { break; }
-
-                let mut rendered_lines = self.render_line(line);
-                assert!(!rendered_lines.is_empty());
-                if old_school {
-                    match self.primary_span {
-                        Some(span) => {
-                            let lo = codemap.lookup_char_pos(span.lo);
-                            let hi = codemap.lookup_char_pos(span.hi);
-                            //Before each secondary line in old skool-mode, print the label
-                            //as an old-style note
-                            if !line.annotations[0].is_primary {
-                                if let Some(ann) = line.annotations[0].label.clone() {
-                                    output.push(RenderedLine {
-                                        text: vec![StyledString {
-                                            text: lo.file.name.clone(),
-                                            style: Style::FileNameStyle,
-                                        }, StyledString {
-                                            text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1,
-                                                hi.line, hi.col.0+1),
-                                            style: Style::LineAndColumn,
-                                        }, StyledString {
-                                            text: format!("note: "),
-                                            style: Style::OldSkoolNote,
-                                        }, StyledString {
-                                            text: format!("{}", ann),
-                                            style: Style::OldSkoolNoteText,
-                                        }],
-                                        kind: RenderedLineKind::Annotations,
-                                    });
-                                }
-                            }
-                            rendered_lines[0].text.insert(0, StyledString {
-                                text: format!(":{} ", lo.line),
-                                style: Style::LineAndColumn,
-                            });
-                            rendered_lines[0].text.insert(0, StyledString {
-                                text: lo.file.name.clone(),
-                                style: Style::FileNameStyle,
-                            });
-                            let gap_amount =
-                                rendered_lines[0].text[0].text.len() +
-                                rendered_lines[0].text[1].text.len();
-                            assert!(rendered_lines.len() >= 2,
-                                    "no annotations resulted from: {:?}",
-                                    line);
-                            for i in 1..rendered_lines.len() {
-                                rendered_lines[i].text.insert(0, StyledString {
-                                    text: vec![" "; gap_amount].join(""),
-                                    style: Style::NoStyle
-                                });
-                            }
-                        }
-                        _ =>()
-                    }
-                }
-                output.append(&mut rendered_lines);
-                next_line = lines_iter.next();
-            }
-
-            // Emit lines without annotations, but only if they are
-            // followed by a line with an annotation.
-            let unannotated_line = next_line;
-            let mut unannotated_lines = 0;
-            while let Some(line) = next_line {
-                if !line.annotations.is_empty() { break; }
-                unannotated_lines += 1;
-                next_line = lines_iter.next();
-            }
-            if unannotated_lines > 1 {
-                output.push(RenderedLine::from((String::new(),
-                                                Style::NoStyle,
-                                                RenderedLineKind::Elision)));
-            } else if let Some(line) = unannotated_line {
-                output.append(&mut self.render_line(line));
-            }
-        }
-
-        output
-    }
-
-    fn render_line(&self, line: &Line) -> Vec<RenderedLine> {
-        let old_school = match self.format_mode {
-            FormatMode::OriginalErrorFormat => true,
-            FormatMode::NewErrorFormat => false,
-            FormatMode::EnvironmentSelected => check_old_skool()
-        };
-
-        let source_string = self.file.get_line(line.line_index)
-                                     .unwrap_or("");
-        let source_kind = RenderedLineKind::SourceText {
-            file: self.file.clone(),
-            line_index: line.line_index,
-        };
-
-        let mut styled_buffer = StyledBuffer::new();
-
-        // First create the source line we will highlight.
-        styled_buffer.append(0, &source_string, Style::Quotation);
-
-        if line.annotations.is_empty() {
-            return styled_buffer.render(source_kind);
-        }
-
-        // We want to display like this:
-        //
-        //      vec.push(vec.pop().unwrap());
-        //      ---      ^^^               _ previous borrow ends here
-        //      |        |
-        //      |        error occurs here
-        //      previous borrow of `vec` occurs here
-        //
-        // But there are some weird edge cases to be aware of:
-        //
-        //      vec.push(vec.pop().unwrap());
-        //      --------                    - previous borrow ends here
-        //      ||
-        //      |this makes no sense
-        //      previous borrow of `vec` occurs here
-        //
-        // For this reason, we group the lines into "highlight lines"
-        // and "annotations lines", where the highlight lines have the `~`.
-
-        //let mut highlight_line = Self::whitespace(&source_string);
-
-        // Sort the annotations by (start, end col)
-        let mut annotations = line.annotations.clone();
-        annotations.sort();
-
-        // Next, create the highlight line.
-        for annotation in &annotations {
-            if old_school {
-                for p in annotation.start_col .. annotation.end_col {
-                    if p == annotation.start_col {
-                        styled_buffer.putc(1, p, '^',
-                            if annotation.is_primary {
-                                Style::UnderlinePrimary
-                            } else {
-                                Style::OldSkoolNote
-                            });
-                    }
-                    else {
-                        styled_buffer.putc(1, p, '~',
-                            if annotation.is_primary {
-                                Style::UnderlinePrimary
-                            } else {
-                                Style::OldSkoolNote
-                            });
-                    }
-                }
-            }
-            else {
-                for p in annotation.start_col .. annotation.end_col {
-                    if annotation.is_primary {
-                        styled_buffer.putc(1, p, '^', Style::UnderlinePrimary);
-                        if !annotation.is_minimized {
-                            styled_buffer.set_style(0, p, Style::UnderlinePrimary);
-                        }
-                    } else {
-                        styled_buffer.putc(1, p, '-', Style::UnderlineSecondary);
-                        if !annotation.is_minimized {
-                            styled_buffer.set_style(0, p, Style::UnderlineSecondary);
-                        }
-                    }
-                }
-            }
-        }
-
-        // Now we are going to write labels in. To start, we'll exclude
-        // the annotations with no labels.
-        let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) =
-            annotations.into_iter()
-                       .partition(|a| a.label.is_some());
-
-        // If there are no annotations that need text, we're done.
-        if labeled_annotations.is_empty() {
-            return styled_buffer.render(source_kind);
-        }
-        if old_school {
-            return styled_buffer.render(source_kind);
-        }
-
-        // Now add the text labels. We try, when possible, to stick the rightmost
-        // annotation at the end of the highlight line:
-        //
-        //      vec.push(vec.pop().unwrap());
-        //      ---      ---               - previous borrow ends here
-        //
-        // But sometimes that's not possible because one of the other
-        // annotations overlaps it. For example, from the test
-        // `span_overlap_label`, we have the following annotations
-        // (written on distinct lines for clarity):
-        //
-        //      fn foo(x: u32) {
-        //      --------------
-        //             -
-        //
-        // In this case, we can't stick the rightmost-most label on
-        // the highlight line, or we would get:
-        //
-        //      fn foo(x: u32) {
-        //      -------- x_span
-        //      |
-        //      fn_span
-        //
-        // which is totally weird. Instead we want:
-        //
-        //      fn foo(x: u32) {
-        //      --------------
-        //      |      |
-        //      |      x_span
-        //      fn_span
-        //
-        // which is...less weird, at least. In fact, in general, if
-        // the rightmost span overlaps with any other span, we should
-        // use the "hang below" version, so we can at least make it
-        // clear where the span *starts*.
-        let mut labeled_annotations = &labeled_annotations[..];
-        match labeled_annotations.split_last().unwrap() {
-            (last, previous) => {
-                if previous.iter()
-                           .chain(&unlabeled_annotations)
-                           .all(|a| !overlaps(a, last))
-                {
-                    // append the label afterwards; we keep it in a separate
-                    // string
-                    let highlight_label: String = format!(" {}", last.label.as_ref().unwrap());
-                    if last.is_primary {
-                        styled_buffer.append(1, &highlight_label, Style::LabelPrimary);
-                    } else {
-                        styled_buffer.append(1, &highlight_label, Style::LabelSecondary);
-                    }
-                    labeled_annotations = previous;
-                }
-            }
-        }
-
-        // If that's the last annotation, we're done
-        if labeled_annotations.is_empty() {
-            return styled_buffer.render(source_kind);
-        }
-
-        for (index, annotation) in labeled_annotations.iter().enumerate() {
-            // Leave:
-            // - 1 extra line
-            // - One line for each thing that comes after
-            let comes_after = labeled_annotations.len() - index - 1;
-            let blank_lines = 3 + comes_after;
-
-            // For each blank line, draw a `|` at our column. The
-            // text ought to be long enough for this.
-            for index in 2..blank_lines {
-                if annotation.is_primary {
-                    styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary);
-                } else {
-                    styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary);
-                }
-            }
-
-            if annotation.is_primary {
-                styled_buffer.puts(blank_lines, annotation.start_col,
-                    annotation.label.as_ref().unwrap(), Style::LabelPrimary);
-            } else {
-                styled_buffer.puts(blank_lines, annotation.start_col,
-                    annotation.label.as_ref().unwrap(), Style::LabelSecondary);
-            }
-        }
-
-        styled_buffer.render(source_kind)
-    }
-}
-
-fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) {
-    let old_school = match *format_mode {
-        FormatMode::OriginalErrorFormat => true,
-        FormatMode::NewErrorFormat => false,
-        FormatMode::EnvironmentSelected => check_old_skool()
-    };
-    if old_school {
-        return;
-    }
-
-    let prefixes: Vec<_> =
-        rendered_lines.iter()
-                      .map(|rl| rl.kind.prefix())
-                      .collect();
-
-    // find the max amount of spacing we need; add 1 to
-    // p.text.len() to leave space between the prefix and the
-    // source text
-    let padding_len =
-        prefixes.iter()
-                .map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 })
-                .max()
-                .unwrap_or(0);
-
-    // Ensure we insert at least one character of padding, so that the
-    // `-->` arrows can fit etc.
-    let padding_len = cmp::max(padding_len, 1);
-
-    for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) {
-        let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' ');
-        prefix.text.extend(extra_spaces);
-        match line.kind {
-            RenderedLineKind::Elision => {
-                line.text.insert(0, prefix);
-            }
-            RenderedLineKind::PrimaryFileName => {
-                //   --> filename
-                // 22 |>
-                //   ^
-                //   padding_len
-                let dashes = (0..padding_len - 1).map(|_| ' ')
-                                                 .chain(Some('-'))
-                                                 .chain(Some('-'))
-                                                 .chain(Some('>'))
-                                                 .chain(Some(' '));
-                line.text.insert(0, StyledString {text: dashes.collect(),
-                                                  style: Style::LineNumber})
-            }
-            RenderedLineKind::OtherFileName => {
-                //   ::: filename
-                // 22 |>
-                //   ^
-                //   padding_len
-                let dashes = (0..padding_len - 1).map(|_| ' ')
-                                                 .chain(Some(':'))
-                                                 .chain(Some(':'))
-                                                 .chain(Some(':'))
-                                                 .chain(Some(' '));
-                line.text.insert(0, StyledString {text: dashes.collect(),
-                                                  style: Style::LineNumber})
-            }
-            _ => {
-                line.text.insert(0, prefix);
-                line.text.insert(1, StyledString {text: String::from("|> "),
-                                                  style: Style::LineNumber})
-            }
-        }
-    }
-}
-
-fn trim_lines(rendered_lines: &mut [RenderedLine]) {
-    for line in rendered_lines {
-        while !line.text.is_empty() {
-            line.trim_last();
-            if line.text.last().unwrap().text.is_empty() {
-                line.text.pop();
-            } else {
-                break;
-            }
-        }
-    }
-}
-
-impl Line {
-    fn new(line_index: usize) -> Line {
-        Line {
-            line_index: line_index,
-            annotations: vec![]
-        }
-    }
-
-    fn push_annotation(&mut self,
-                       start: CharPos,
-                       end: CharPos,
-                       is_primary: bool,
-                       is_minimized: bool,
-                       label: Option<String>) {
-        self.annotations.push(Annotation {
-            start_col: start.0,
-            end_col: end.0,
-            is_primary: is_primary,
-            is_minimized: is_minimized,
-            label: label,
-        });
-    }
-}
-
-fn overlaps(a1: &Annotation,
-            a2: &Annotation)
-            -> bool
-{
-    (a2.start_col .. a2.end_col).contains(a1.start_col) ||
-        (a1.start_col .. a1.end_col).contains(a2.start_col)
-}
+    ErrorCode,
+    Level(Level),
+}
\ No newline at end of file
diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs
new file mode 100644 (file)
index 0000000..9768b68
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2012-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.
+
+// Code for creating styled buffers
+
+use snippet::{Style, StyledString};
+
+#[derive(Debug)]
+pub struct StyledBuffer {
+    text: Vec<Vec<char>>,
+    styles: Vec<Vec<Style>>,
+}
+
+impl StyledBuffer {
+    pub fn new() -> StyledBuffer {
+        StyledBuffer {
+            text: vec![],
+            styles: vec![],
+        }
+    }
+
+    pub fn copy_tabs(&mut self, row: usize) {
+        if row < self.text.len() {
+            for i in row+1..self.text.len() {
+                for j in 0..self.text[i].len() {
+                    if self.text[row].len() > j &&
+                       self.text[row][j] == '\t' &&
+                       self.text[i][j] == ' ' {
+                        self.text[i][j] = '\t';
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn render(&mut self) -> Vec<Vec<StyledString>> {
+        let mut output: Vec<Vec<StyledString>> = vec![];
+        let mut styled_vec: Vec<StyledString> = vec![];
+
+        //before we render, do a little patch-up work to support tabs
+        self.copy_tabs(3);
+
+        for (row, row_style) in self.text.iter().zip(&self.styles) {
+            let mut current_style = Style::NoStyle;
+            let mut current_text = String::new();
+
+            for (&c, &s) in row.iter().zip(row_style) {
+                if s != current_style {
+                    if !current_text.is_empty() {
+                        styled_vec.push(StyledString {
+                            text: current_text,
+                            style: current_style,
+                        });
+                    }
+                    current_style = s;
+                    current_text = String::new();
+                }
+                current_text.push(c);
+            }
+            if !current_text.is_empty() {
+                styled_vec.push(StyledString {
+                    text: current_text,
+                    style: current_style,
+                });
+            }
+
+            // We're done with the row, push and keep going
+            output.push(styled_vec);
+
+            styled_vec = vec![];
+        }
+
+        output
+    }
+
+    fn ensure_lines(&mut self, line: usize) {
+        while line >= self.text.len() {
+            self.text.push(vec![]);
+            self.styles.push(vec![]);
+        }
+    }
+
+    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
+        self.ensure_lines(line);
+        if col < self.text[line].len() {
+            self.text[line][col] = chr;
+            self.styles[line][col] = style;
+        } else {
+            let mut i = self.text[line].len();
+            while i < col {
+                self.text[line].push(' ');
+                self.styles[line].push(Style::NoStyle);
+                i += 1;
+            }
+            self.text[line].push(chr);
+            self.styles[line].push(style);
+        }
+    }
+
+    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
+        let mut n = col;
+        for c in string.chars() {
+            self.putc(line, n, c, style);
+            n += 1;
+        }
+    }
+
+    pub fn set_style(&mut self, line: usize, col: usize, style: Style) {
+        if self.styles.len() > line && self.styles[line].len() > col {
+            self.styles[line][col] = style;
+        }
+    }
+
+    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
+        self.ensure_lines(line);
+        let string_len = string.len();
+
+        // Push the old content over to make room for new content
+        for _ in 0..string_len {
+            self.styles[line].insert(0, Style::NoStyle);
+            self.text[line].insert(0, ' ');
+        }
+
+        self.puts(line, 0, string, style);
+    }
+
+    pub fn append(&mut self, line: usize, string: &str, style: Style) {
+        if line >= self.text.len() {
+            self.puts(line, 0, string, style);
+        } else {
+            let col = self.text[line].len();
+            self.puts(line, col, string, style);
+        }
+    }
+
+    pub fn num_lines(&self) -> usize {
+        self.text.len()
+    }
+}
index 9b08ddcafab8e7d9e773a2d81e85dd15f2549a21..f688bd80ee9dabe95701d425a5a851f09ad65cb8 100644 (file)
@@ -698,7 +698,8 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
             if gens.ty_params.is_empty() {  // sizes only make sense for non-generic types
                 let t = cx.tcx.node_id_to_type(it.id);
                 let layout = cx.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
-                    t.layout(&infcx).unwrap_or_else(|e| {
+                    let ty = cx.tcx.erase_regions(&t);
+                    ty.layout(&infcx).unwrap_or_else(|e| {
                         bug!("failed to get layout for `{}`: {}", t, e)
                     })
                 });
index 3f5c9a6d3bd83724637bd350a38846d4d60efce5..409cec282bce93de82457834f12ad5e479c33d57 100644 (file)
@@ -687,32 +687,6 @@ fn each_child_of_item_or_crate<F, G>(cdata: Cmd,
         }
     }
 
-    // As a special case, iterate over all static methods of
-    // associated implementations too. This is a bit of a botch.
-    // --pcwalton
-    for inherent_impl_def_id_doc in reader::tagged_docs(item_doc,
-                                                             tag_items_data_item_inherent_impl) {
-        let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata);
-        if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.index) {
-            for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc,
-                                                                 tag_item_impl_item) {
-                let impl_item_def_id = item_def_id(impl_item_def_id_doc,
-                                                   cdata);
-                if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.index) {
-                    if let StaticMethod = item_family(impl_method_doc) {
-                        // Hand off the static method to the callback.
-                        let static_method_name = item_name(impl_method_doc);
-                        let static_method_def_like = item_to_def_like(cdata, impl_method_doc,
-                                                                      impl_item_def_id);
-                        callback(static_method_def_like,
-                                 static_method_name,
-                                 item_visibility(impl_method_doc));
-                    }
-                }
-            }
-        }
-    }
-
     for reexport_doc in reexports(item_doc) {
         let def_id_doc = reader::get_doc(reexport_doc,
                                          tag_items_data_item_reexport_def_id);
index 515620d425389676617e3efa5f9cbba8cf5c96b3..c9ca1a963a42a5a9d38c40ed335c51bf0409e0e0 100644 (file)
@@ -195,7 +195,7 @@ fn write_basic_block(tcx: TyCtxt,
              ALIGN,
              comment(tcx, data.terminator().source_info))?;
 
-    writeln!(w, "{}}}\n", INDENT)
+    writeln!(w, "{}}}", INDENT)
 }
 
 fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
index d4465822229e953baf1e4d8e38a76138d85cbbd7..70e566de8a7be5ab9a53900cd82678e7268329fe 100644 (file)
@@ -11,7 +11,7 @@
 use Resolver;
 use rustc::session::Session;
 use syntax::ast;
-use syntax::ext::mtwt;
+use syntax::ext::hygiene::Mark;
 use syntax::fold::{self, Folder};
 use syntax::ptr::P;
 use syntax::util::move_map::MoveMap;
@@ -31,7 +31,7 @@ pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate {
 
 struct NodeIdAssigner<'a> {
     sess: &'a Session,
-    macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<ast::Mrk>>,
+    macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<Mark>>,
 }
 
 impl<'a> Folder for NodeIdAssigner<'a> {
@@ -49,7 +49,7 @@ fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
             block.stmts = block.stmts.move_flat_map(|stmt| {
                 if let ast::StmtKind::Item(ref item) = stmt.node {
                     if let ast::ItemKind::Mac(..) = item.node {
-                        macros.push(mtwt::outer_mark(item.ident.ctxt));
+                        macros.push(item.ident.ctxt.data().outer_mark);
                         return None;
                     }
                 }
index 2535c264ef8f647fc516231ae8a55a2ed93375f5..aa8c706ea1e27b9cb73978f7248864c3627ee7e8 100644 (file)
@@ -53,7 +53,7 @@
 use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
 use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
 
-use syntax::ext::mtwt;
+use syntax::ext::hygiene::Mark;
 use syntax::ast::{self, FloatTy};
 use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
 use syntax::parse::token::{self, keywords};
@@ -654,7 +654,7 @@ enum RibKind<'a> {
     ModuleRibKind(Module<'a>),
 
     // We passed through a `macro_rules!` statement with the given expansion
-    MacroDefinition(ast::Mrk),
+    MacroDefinition(Mark),
 }
 
 #[derive(Copy, Clone)]
@@ -933,7 +933,7 @@ pub struct Resolver<'a> {
 
     // Maps the node id of a statement to the expansions of the `macro_rules!`s
     // immediately above the statement (if appropriate).
-    macros_at_scope: HashMap<NodeId, Vec<ast::Mrk>>,
+    macros_at_scope: HashMap<NodeId, Vec<Mark>>,
 
     graph_root: Module<'a>,
 
@@ -1434,10 +1434,9 @@ fn resolve_ident_in_lexical_scope(&mut self,
             if let MacroDefinition(mac) = self.get_ribs(ns)[i].kind {
                 // If an invocation of this macro created `ident`, give up on `ident`
                 // and switch to `ident`'s source from the macro definition.
-                if let Some((source_ident, source_macro)) = mtwt::source(ident) {
-                    if mac == source_macro {
-                        ident = source_ident;
-                    }
+                let (source_ctxt, source_macro) = ident.ctxt.source();
+                if source_macro == mac {
+                    ident.ctxt = source_ctxt;
                 }
             }
         }
@@ -1585,10 +1584,9 @@ fn search_label(&self, mut ident: ast::Ident) -> Option<Def> {
                 MacroDefinition(mac) => {
                     // If an invocation of this macro created `ident`, give up on `ident`
                     // and switch to `ident`'s source from the macro definition.
-                    if let Some((source_ident, source_macro)) = mtwt::source(ident) {
-                        if mac == source_macro {
-                            ident = source_ident;
-                        }
+                    let (source_ctxt, source_macro) = ident.ctxt.source();
+                    if source_macro == mac {
+                        ident.ctxt = source_ctxt;
                     }
                 }
                 _ => {
index 071960f1944cfe941a62467a88f9872b7354e2f0..33cffa8a480137a17a36dffef93a12422ae64065 100644 (file)
@@ -19,8 +19,8 @@
 use {CrateTranslation, ModuleTranslation};
 use util::common::time;
 use util::common::path2cstr;
-use errors::{self, Handler, Level, RenderSpan};
-use errors::emitter::CoreEmitter;
+use errors::{self, Handler, Level, DiagnosticBuilder};
+use errors::emitter::Emitter;
 use syntax_pos::MultiSpan;
 
 use std::collections::HashMap;
@@ -100,23 +100,23 @@ fn dump(&mut self, handler: &Handler) {
     }
 }
 
-impl CoreEmitter for SharedEmitter {
-    fn emit_message(&mut self,
-                    _rsp: &RenderSpan,
-                    msg: &str,
-                    code: Option<&str>,
-                    lvl: Level,
-                    _is_header: bool,
-                    _show_snippet: bool) {
+impl Emitter for SharedEmitter {
+    fn emit(&mut self, db: &DiagnosticBuilder) {
         self.buffer.lock().unwrap().push(Diagnostic {
-            msg: msg.to_string(),
-            code: code.map(|s| s.to_string()),
-            lvl: lvl,
+            msg: db.message.to_string(),
+            code: db.code.clone(),
+            lvl: db.level,
         });
+        for child in &db.children {
+            self.buffer.lock().unwrap().push(Diagnostic {
+                msg: child.message.to_string(),
+                code: None,
+                lvl: child.level,
+            });
+        }
     }
 }
 
-
 // On android, we by default compile for armv7 processors. This enables
 // things like double word CAS instructions (rather than emulating them)
 // which are *far* more efficient. This is obviously undesirable in some
index 49a3991ecbe0bfb7b1a51d74bb11c1fd2b6d65e7..fc9ae73f5ce7e2ec96a4c584c4e8f652c9b38746 100644 (file)
@@ -131,7 +131,7 @@ pub fn run_core(search_paths: SearchPaths,
                                                                None,
                                                                true,
                                                                false,
-                                                               codemap.clone());
+                                                               Some(codemap.clone()));
 
     let dep_graph = DepGraph::new(false);
     let _ignore = dep_graph.in_ignore();
index bb69ba6e568d573d7618602ad2f7d29ee5c52733..f9d0df9981a1d73bc9e796746aaca850cda0736d 100644 (file)
@@ -77,7 +77,7 @@ pub fn run(input: &str,
                                                                None,
                                                                true,
                                                                false,
-                                                               codemap.clone());
+                                                               Some(codemap.clone()));
 
     let dep_graph = DepGraph::new(false);
     let _ignore = dep_graph.in_ignore();
@@ -229,7 +229,7 @@ fn drop(&mut self) {
     let codemap = Rc::new(CodeMap::new());
     let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
                                                 None,
-                                                codemap.clone(),
+                                                Some(codemap.clone()),
                                                 errors::snippet::FormatMode::EnvironmentSelected);
     let old = io::set_panic(box Sink(data.clone()));
     let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
index 6b662c6779a4bd118e2dcffbe9c81b47a91c92b6..a8bb255fba4a4d4b099c936239dee1abdc7fee7c 100644 (file)
@@ -19,6 +19,7 @@
 use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId};
 use codemap::{respan, Spanned};
 use abi::Abi;
+use ext::hygiene::SyntaxContext;
 use parse::token::{self, keywords, InternedString};
 use print::pprust;
 use ptr::P;
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Name(pub u32);
 
-/// A SyntaxContext represents a chain of macro-expandings
-/// and renamings. Each macro expansion corresponds to
-/// a fresh u32. This u32 is a reference to a table stored
-/// in thread-local storage.
-/// The special value EMPTY_CTXT is used to indicate an empty
-/// syntax context.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct SyntaxContext(pub u32);
-
 /// An identifier contains a Name (index into the interner
 /// table) and a SyntaxContext to track renaming and
 /// macro expansion per Flatt et al., "Macros That Work Together"
@@ -81,20 +73,15 @@ fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
     }
 }
 
-pub const EMPTY_CTXT : SyntaxContext = SyntaxContext(0);
-
 impl Ident {
-    pub fn new(name: Name, ctxt: SyntaxContext) -> Ident {
-        Ident {name: name, ctxt: ctxt}
-    }
     pub const fn with_empty_ctxt(name: Name) -> Ident {
-        Ident {name: name, ctxt: EMPTY_CTXT}
+        Ident { name: name, ctxt: SyntaxContext::empty() }
     }
 }
 
 impl fmt::Debug for Ident {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}#{}", self.name, self.ctxt.0)
+        write!(f, "{}{:?}", self.name, self.ctxt)
     }
 }
 
@@ -116,9 +103,6 @@ fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
     }
 }
 
-/// A mark represents a unique id associated with a macro expansion
-pub type Mrk = u32;
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
index 743f96d737e2da8fe3a179befb42eacb40d3c0ae..a8aca90e6238daf18f6503aa6f7b7664dd35366e 100644 (file)
@@ -827,12 +827,6 @@ fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use errors::{Level, CodeSuggestion};
-    use errors::emitter::EmitterWriter;
-    use errors::snippet::{SnippetData, RenderedLine, FormatMode};
-    use std::sync::{Arc, Mutex};
-    use std::io::{self, Write};
-    use std::str::from_utf8;
     use std::rc::Rc;
 
     #[test]
@@ -1122,24 +1116,6 @@ fn span_substr(&self,
         }
     }
 
-    fn splice(start: Span, end: Span) -> Span {
-        Span {
-            lo: start.lo,
-            hi: end.hi,
-            expn_id: NO_EXPANSION,
-        }
-    }
-
-    fn make_string(lines: &[RenderedLine]) -> String {
-        lines.iter()
-            .flat_map(|rl| {
-                rl.text.iter()
-                        .map(|s| &s.text[..])
-                        .chain(Some("\n"))
-            })
-            .collect()
-    }
-
     fn init_expansion_chain(cm: &CodeMap) -> Span {
         // Creates an expansion chain containing two recursive calls
         // root -> expA -> expA -> expB -> expB -> end
@@ -1219,761 +1195,4 @@ fn t12() {
 ";
         assert_eq!(sstr, res_str);
     }
-
-    struct Sink(Arc<Mutex<Vec<u8>>>);
-    impl Write for Sink {
-        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-            Write::write(&mut *self.0.lock().unwrap(), data)
-        }
-        fn flush(&mut self) -> io::Result<()> { Ok(()) }
-    }
-
-    // Diagnostic doesn't align properly in span where line number increases by one digit
-    #[test]
-    fn test_hilight_suggestion_issue_11715() {
-        let data = Arc::new(Mutex::new(Vec::new()));
-        let cm = Rc::new(CodeMap::new());
-        let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())),
-                                        None,
-                                        cm.clone(),
-                                        FormatMode::NewErrorFormat);
-        let content = "abcdefg
-        koksi
-        line3
-        line4
-        cinq
-        line6
-        line7
-        line8
-        line9
-        line10
-        e-lä-vän
-        tolv
-        dreizehn
-        ";
-        let file = cm.new_filemap_and_lines("dummy.txt", None, content);
-        let start = file.lines.borrow()[10];
-        let end = file.lines.borrow()[11];
-        let sp = mk_sp(start, end);
-        let lvl = Level::Error;
-        println!("highlight_lines");
-        ew.highlight_lines(&sp.into(), lvl).unwrap();
-        println!("done");
-        let vec = data.lock().unwrap().clone();
-        let vec: &[u8] = &vec;
-        let str = from_utf8(vec).unwrap();
-        println!("r#\"\n{}\"#", str);
-        assert_eq!(str, &r#"
-  --> dummy.txt:11:1
-   |>
-11 |>         e-lä-vän
-   |> ^
-"#[1..]);
-    }
-
-    #[test]
-    fn test_single_span_splice() {
-        // Test that a `MultiSpan` containing a single span splices a substition correctly
-        let cm = CodeMap::new();
-        let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
-        let selection = "     \n    ~~\n~~~\n~~~~~     \n   \n";
-        cm.new_filemap_and_lines("blork.rs", None, inputtext);
-        let sp = span_from_selection(inputtext, selection);
-        let msp: MultiSpan = sp.into();
-
-        // check that we are extracting the text we thought we were extracting
-        assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD");
-
-        let substitute = "ZZZZZZ".to_owned();
-        let expected = "bbbbZZZZZZddddd";
-        let suggest = CodeSuggestion {
-            msp: msp,
-            substitutes: vec![substitute],
-        };
-        assert_eq!(suggest.splice_lines(&cm), expected);
-    }
-
-    #[test]
-    fn test_multi_span_splice() {
-        // Test that a `MultiSpan` containing multiple spans splices a substition correctly
-        let cm = CodeMap::new();
-        let inputtext  = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
-        let selection1 = "     \n      \n   \n          \n ~ \n"; // intentionally out of order
-        let selection2 = "     \n    ~~\n~~~\n~~~~~     \n   \n";
-        cm.new_filemap_and_lines("blork.rs", None, inputtext);
-        let sp1 = span_from_selection(inputtext, selection1);
-        let sp2 = span_from_selection(inputtext, selection2);
-        let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
-
-        let expected = "bbbbZZZZZZddddd\neXYZe";
-        let suggest = CodeSuggestion {
-            msp: msp,
-            substitutes: vec!["ZZZZZZ".to_owned(),
-                              "XYZ".to_owned()]
-        };
-
-        assert_eq!(suggest.splice_lines(&cm), expected);
-    }
-
-    #[test]
-    fn test_multispan_highlight() {
-        let data = Arc::new(Mutex::new(Vec::new()));
-        let cm = Rc::new(CodeMap::new());
-        let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())),
-                                          None,
-                                          cm.clone(),
-                                          FormatMode::NewErrorFormat);
-
-        let inp =       "_____aaaaaa____bbbbbb__cccccdd_";
-        let sp1 =       "     ~~~~~~                    ";
-        let sp2 =       "               ~~~~~~          ";
-        let sp3 =       "                       ~~~~~   ";
-        let sp4 =       "                          ~~~~ ";
-        let sp34 =      "                       ~~~~~~~ ";
-
-        let expect_start = &r#"
- --> dummy.txt:1:6
-  |>
-1 |> _____aaaaaa____bbbbbb__cccccdd_
-  |>      ^^^^^^    ^^^^^^  ^^^^^^^
-"#[1..];
-
-        let span = |sp, expected| {
-            let sp = span_from_selection(inp, sp);
-            assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
-            sp
-        };
-        cm.new_filemap_and_lines("dummy.txt", None, inp);
-        let sp1 = span(sp1, "aaaaaa");
-        let sp2 = span(sp2, "bbbbbb");
-        let sp3 = span(sp3, "ccccc");
-        let sp4 = span(sp4, "ccdd");
-        let sp34 = span(sp34, "cccccdd");
-
-        let spans = vec![sp1, sp2, sp3, sp4];
-
-        let test = |expected, highlight: &mut FnMut()| {
-            data.lock().unwrap().clear();
-            highlight();
-            let vec = data.lock().unwrap().clone();
-            let actual = from_utf8(&vec[..]).unwrap();
-            println!("actual=\n{}", actual);
-            assert_eq!(actual, expected);
-        };
-
-        let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]);
-        test(expect_start, &mut || {
-            diag.highlight_lines(&msp, Level::Error).unwrap();
-        });
-        test(expect_start, &mut || {
-            let msp = MultiSpan::from_spans(spans.clone());
-            diag.highlight_lines(&msp, Level::Error).unwrap();
-        });
-    }
-
-    #[test]
-    fn test_huge_multispan_highlight() {
-        let data = Arc::new(Mutex::new(Vec::new()));
-        let cm = Rc::new(CodeMap::new());
-        let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())),
-                                          None,
-                                          cm.clone(),
-                                          FormatMode::NewErrorFormat);
-
-        let inp = "aaaaa\n\
-                   aaaaa\n\
-                   aaaaa\n\
-                   bbbbb\n\
-                   ccccc\n\
-                   xxxxx\n\
-                   yyyyy\n\
-                   _____\n\
-                   ddd__eee_\n\
-                   elided\n\
-                   __f_gg";
-        let file = cm.new_filemap_and_lines("dummy.txt", None, inp);
-
-        let span = |lo, hi, (off_lo, off_hi)| {
-            let lines = file.lines.borrow();
-            let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]);
-            lo.0 += off_lo;
-            hi.0 += off_hi;
-            mk_sp(lo, hi)
-        };
-        let sp0 = span(4, 6, (0, 5));
-        let sp1 = span(0, 6, (0, 5));
-        let sp2 = span(8, 8, (0, 3));
-        let sp3 = span(8, 8, (5, 8));
-        let sp4 = span(10, 10, (2, 3));
-        let sp5 = span(10, 10, (4, 6));
-
-        let expect0 = &r#"
-   --> dummy.txt:5:1
-    |>
-5   |> ccccc
-    |> ^
-...
-9   |> ddd__eee_
-    |> ^^^  ^^^
-10  |> elided
-11  |> __f_gg
-    |>   ^ ^^
-"#[1..];
-
-        let expect = &r#"
-   --> dummy.txt:1:1
-    |>
-1   |> aaaaa
-    |> ^
-...
-9   |> ddd__eee_
-    |> ^^^  ^^^
-10  |> elided
-11  |> __f_gg
-    |>   ^ ^^
-"#[1..];
-
-        macro_rules! test {
-            ($expected: expr, $highlight: expr) => ({
-                data.lock().unwrap().clear();
-                $highlight();
-                let vec = data.lock().unwrap().clone();
-                let actual = from_utf8(&vec[..]).unwrap();
-                println!("actual:");
-                println!("{}", actual);
-                println!("expected:");
-                println!("{}", $expected);
-                assert_eq!(&actual[..], &$expected[..]);
-            });
-        }
-
-        let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]);
-        let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]);
-
-        test!(expect0, || {
-            diag.highlight_lines(&msp0, Level::Error).unwrap();
-        });
-        test!(expect, || {
-            diag.highlight_lines(&msp, Level::Error).unwrap();
-        });
-    }
-
-    #[test]
-    fn tab() {
-        let file_text = "
-fn foo() {
-\tbar;
-}
-";
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-        let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
-
-        let mut snippet = SnippetData::new(cm, Some(span_bar), FormatMode::NewErrorFormat);
-        snippet.push(span_bar, true, None);
-
-        let lines = snippet.render_lines();
-        let text = make_string(&lines);
-        assert_eq!(&text[..], &"
- --> foo.rs:3:2
-  |>
-3 |> \tbar;
-  |> \t^^^
-"[1..]);
-    }
-
-    #[test]
-    fn one_line() {
-        let file_text = r#"
-fn foo() {
-    vec.push(vec.pop().unwrap());
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-        let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
-        let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
-        let span_semi = cm.span_substr(&foo, file_text, ";", 0);
-
-        let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
-        snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
-        snippet.push(span_vec1, false, Some(format!("error occurs here")));
-        snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
-
-        let lines = snippet.render_lines();
-        println!("{:#?}", lines);
-
-        let text: String = make_string(&lines);
-
-        println!("text=\n{}", text);
-        assert_eq!(&text[..], &r#"
- ::: foo.rs
-  |>
-3 |>     vec.push(vec.pop().unwrap());
-  |>     ---      ---                - previous borrow ends here
-  |>     |        |
-  |>     |        error occurs here
-  |>     previous borrow of `vec` occurs here
-"#[1..]);
-    }
-
-    #[test]
-    fn two_files() {
-        let file_text_foo = r#"
-fn foo() {
-    vec.push(vec.pop().unwrap());
-}
-"#;
-
-        let file_text_bar = r#"
-fn bar() {
-    // these blank links here
-    // serve to ensure that the line numbers
-    // from bar.rs
-    // require more digits
-
-
-
-
-
-
-
-
-
-
-    vec.push();
-
-    // this line will get elided
-
-    vec.pop().unwrap());
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo);
-        let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
-        let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
-        let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
-
-        let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar);
-        let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
-        let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
-        let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
-
-        let mut snippet = SnippetData::new(cm, Some(span_foo_vec1), FormatMode::NewErrorFormat);
-        snippet.push(span_foo_vec0, false, Some(format!("a")));
-        snippet.push(span_foo_vec1, true, Some(format!("b")));
-        snippet.push(span_foo_semi, false, Some(format!("c")));
-        snippet.push(span_bar_vec0, false, Some(format!("d")));
-        snippet.push(span_bar_vec1, false, Some(format!("e")));
-        snippet.push(span_bar_semi, false, Some(format!("f")));
-
-        let lines = snippet.render_lines();
-        println!("{:#?}", lines);
-
-        let text: String = make_string(&lines);
-
-        println!("text=\n{}", text);
-
-        // Note that the `|>` remain aligned across both files:
-        assert_eq!(&text[..], &r#"
-   --> foo.rs:3:14
-    |>
-3   |>     vec.push(vec.pop().unwrap());
-    |>     ---      ^^^                - c
-    |>     |        |
-    |>     |        b
-    |>     a
-   ::: bar.rs
-    |>
-17  |>     vec.push();
-    |>     ---       - f
-    |>     |
-    |>     d
-...
-21  |>     vec.pop().unwrap());
-    |>     --- e
-"#[1..]);
-    }
-
-    #[test]
-    fn multi_line() {
-        let file_text = r#"
-fn foo() {
-    let name = find_id(&data, 22).unwrap();
-
-    // Add one more item we forgot to the vector. Silly us.
-    data.push(Data { name: format!("Hera"), id: 66 });
-
-    // Print everything out.
-    println!("Name: {:?}", name);
-    println!("Data: {:?}", data);
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-        let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
-        let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
-        let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
-
-        let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
-        snippet.push(span_data0, false, Some(format!("immutable borrow begins here")));
-        snippet.push(span_data1, false, Some(format!("mutable borrow occurs here")));
-        snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here")));
-
-        let lines = snippet.render_lines();
-        println!("{:#?}", lines);
-
-        let text: String = make_string(&lines);
-
-        println!("text=\n{}", text);
-        assert_eq!(&text[..], &r#"
-   ::: foo.rs
-    |>
-3   |>     let name = find_id(&data, 22).unwrap();
-    |>                         ---- immutable borrow begins here
-...
-6   |>     data.push(Data { name: format!("Hera"), id: 66 });
-    |>     ---- mutable borrow occurs here
-...
-11  |> }
-    |> - immutable borrow ends here
-"#[1..]);
-    }
-
-    #[test]
-    fn overlapping() {
-        let file_text = r#"
-fn foo() {
-    vec.push(vec.pop().unwrap());
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-        let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
-        let span1 = cm.span_substr(&foo, file_text, "vec", 0);
-        let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
-        let span3 = cm.span_substr(&foo, file_text, "unwrap", 0);
-
-        let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
-        snippet.push(span0, false, Some(format!("A")));
-        snippet.push(span1, false, Some(format!("B")));
-        snippet.push(span2, false, Some(format!("C")));
-        snippet.push(span3, false, Some(format!("D")));
-
-        let lines = snippet.render_lines();
-        println!("{:#?}", lines);
-        let text: String = make_string(&lines);
-
-        println!("text=r#\"\n{}\".trim_left()", text);
-        assert_eq!(&text[..], &r#"
- ::: foo.rs
-  |>
-3 |>     vec.push(vec.pop().unwrap());
-  |>     --------           ------ D
-  |>     ||
-  |>     |C
-  |>     A
-  |>     B
-"#[1..]);
-    }
-
-    #[test]
-    fn one_line_out_of_order() {
-        let file_text = r#"
-fn foo() {
-    vec.push(vec.pop().unwrap());
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-        let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
-        let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
-        let span_semi = cm.span_substr(&foo, file_text, ";", 0);
-
-        // intentionally don't push the snippets left to right
-        let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
-        snippet.push(span_vec1, false, Some(format!("error occurs here")));
-        snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
-        snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
-
-        let lines = snippet.render_lines();
-        println!("{:#?}", lines);
-        let text: String = make_string(&lines);
-
-        println!("text=r#\"\n{}\".trim_left()", text);
-        assert_eq!(&text[..], &r#"
- ::: foo.rs
-  |>
-3 |>     vec.push(vec.pop().unwrap());
-  |>     ---      ---                - previous borrow ends here
-  |>     |        |
-  |>     |        error occurs here
-  |>     previous borrow of `vec` occurs here
-"#[1..]);
-    }
-
-    #[test]
-    fn elide_unnecessary_lines() {
-        let file_text = r#"
-fn foo() {
-    let mut vec = vec![0, 1, 2];
-    let mut vec2 = vec;
-    vec2.push(3);
-    vec2.push(4);
-    vec2.push(5);
-    vec2.push(6);
-    vec.push(7);
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-        let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
-        let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
-
-        let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
-        snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \
-            has type `collections::vec::Vec<i32>`")));
-        snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`")));
-
-        let lines = snippet.render_lines();
-        println!("{:#?}", lines);
-        let text: String = make_string(&lines);
-        println!("text=r#\"\n{}\".trim_left()", text);
-        assert_eq!(&text[..], &r#"
-   ::: foo.rs
-    |>
-4   |>     let mut vec2 = vec;
-    |>                    --- `vec` moved here because it has type `collections::vec::Vec<i32>`
-...
-9   |>     vec.push(7);
-    |>     --- use of moved value: `vec`
-"#[1..]);
-    }
-
-    #[test]
-    fn spans_without_labels() {
-        let file_text = r#"
-fn foo() {
-    let mut vec = vec![0, 1, 2];
-    let mut vec2 = vec;
-    vec2.push(3);
-    vec2.push(4);
-    vec2.push(5);
-    vec2.push(6);
-    vec.push(7);
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
-        let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
-        for i in 0..4 {
-            let span_veci = cm.span_substr(&foo, file_text, "vec", i);
-            snippet.push(span_veci, false, None);
-        }
-
-        let lines = snippet.render_lines();
-        let text: String = make_string(&lines);
-        println!("text=&r#\"\n{}\n\"#[1..]", text);
-        assert_eq!(text, &r#"
- ::: foo.rs
-  |>
-3 |>     let mut vec = vec![0, 1, 2];
-  |>             ---   ---
-4 |>     let mut vec2 = vec;
-  |>             ---    ---
-"#[1..]);
-    }
-
-    #[test]
-    fn span_long_selection() {
-        let file_text = r#"
-impl SomeTrait for () {
-    fn foo(x: u32) {
-        // impl 1
-        // impl 2
-        // impl 3
-    }
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
-        let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
-        let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
-        let rbrace_span = cm.span_substr(&foo, file_text, "}", 0);
-        snippet.push(splice(fn_span, rbrace_span), false, None);
-        let lines = snippet.render_lines();
-        let text: String = make_string(&lines);
-        println!("r#\"\n{}\"", text);
-        assert_eq!(text, &r#"
- ::: foo.rs
-  |>
-3 |>     fn foo(x: u32) {
-  |>     -
-"#[1..]);
-    }
-
-    #[test]
-    fn span_overlap_label() {
-        // Test that we don't put `x_span` to the right of its highlight,
-        // since there is another highlight that overlaps it.
-
-        let file_text = r#"
-    fn foo(x: u32) {
-    }
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
-        let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
-        let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
-        let x_span = cm.span_substr(&foo, file_text, "x", 0);
-        snippet.push(fn_span, false, Some(format!("fn_span")));
-        snippet.push(x_span, false, Some(format!("x_span")));
-        let lines = snippet.render_lines();
-        let text: String = make_string(&lines);
-        println!("r#\"\n{}\"", text);
-        assert_eq!(text, &r#"
- ::: foo.rs
-  |>
-2 |>     fn foo(x: u32) {
-  |>     --------------
-  |>     |      |
-  |>     |      x_span
-  |>     fn_span
-"#[1..]);
-    }
-
-    #[test]
-    fn span_overlap_label2() {
-        // Test that we don't put `x_span` to the right of its highlight,
-        // since there is another highlight that overlaps it. In this
-        // case, the overlap is only at the beginning, but it's still
-        // better to show the beginning more clearly.
-
-        let file_text = r#"
-    fn foo(x: u32) {
-    }
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
-        let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
-        let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
-        let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0);
-        snippet.push(fn_span, false, Some(format!("fn_span")));
-        snippet.push(x_span, false, Some(format!("x_span")));
-        let lines = snippet.render_lines();
-        let text: String = make_string(&lines);
-        println!("r#\"\n{}\"", text);
-        assert_eq!(text, &r#"
- ::: foo.rs
-  |>
-2 |>     fn foo(x: u32) {
-  |>     --------------
-  |>     |      |
-  |>     |      x_span
-  |>     fn_span
-"#[1..]);
-    }
-
-    #[test]
-    fn span_overlap_label3() {
-        // Test that we don't put `x_span` to the right of its highlight,
-        // since there is another highlight that overlaps it. In this
-        // case, the overlap is only at the beginning, but it's still
-        // better to show the beginning more clearly.
-
-        let file_text = r#"
-    fn foo() {
-       let closure = || {
-           inner
-       };
-    }
-}
-"#;
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
-        let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
-
-        let closure_span = {
-            let closure_start_span = cm.span_substr(&foo, file_text, "||", 0);
-            let closure_end_span = cm.span_substr(&foo, file_text, "}", 0);
-            splice(closure_start_span, closure_end_span)
-        };
-
-        let inner_span = cm.span_substr(&foo, file_text, "inner", 0);
-
-        snippet.push(closure_span, false, Some(format!("foo")));
-        snippet.push(inner_span, false, Some(format!("bar")));
-
-        let lines = snippet.render_lines();
-        let text: String = make_string(&lines);
-        println!("r#\"\n{}\"", text);
-        assert_eq!(text, &r#"
- ::: foo.rs
-  |>
-3 |>        let closure = || {
-  |>                      - foo
-4 |>            inner
-  |>            ----- bar
-"#[1..]);
-    }
-
-    #[test]
-    fn span_empty() {
-        // In one of the unit tests, we found that the parser sometimes
-        // gives empty spans, and in particular it supplied an EOF span
-        // like this one, which points at the very end. We want to
-        // fallback gracefully in this case.
-
-        let file_text = r#"
-fn main() {
-    struct Foo;
-
-    impl !Sync for Foo {}
-
-    unsafe impl Send for &'static Foo {
-    // error: cross-crate traits with a default impl, like `core::marker::Send`,
-    //        can only be implemented for a struct/enum type, not
-    //        `&'static Foo`
-}"#;
-
-
-        let cm = Rc::new(CodeMap::new());
-        let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
-        let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1);
-        rbrace_span.lo = rbrace_span.hi;
-
-        let mut snippet = SnippetData::new(cm.clone(),
-                                           Some(rbrace_span),
-                                           FormatMode::NewErrorFormat);
-        snippet.push(rbrace_span, false, None);
-        let lines = snippet.render_lines();
-        let text: String = make_string(&lines);
-        println!("r#\"\n{}\"", text);
-        assert_eq!(text, &r#"
-  --> foo.rs:11:2
-   |>
-11 |> }
-   |>  -
-"#[1..]);
-    }
 }
index 7ebcd12cdb9512853b9122c49079f8690a381e65..ca2be89def0f17c4176967c0d728de5556ee7e9d 100644 (file)
@@ -816,6 +816,12 @@ pub fn suggest_macro_name(&mut self,
 /// compilation on error, merely emits a non-fatal error and returns None.
 pub fn expr_to_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str)
                       -> Option<(InternedString, ast::StrStyle)> {
+    // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
+    let expr = expr.map(|mut expr| {
+        expr.span.expn_id = cx.backtrace;
+        expr
+    });
+
     // we want to be able to handle e.g. concat("foo", "bar")
     let expr = cx.expander().fold_expr(expr);
     match expr.node {
index 3e9837a6995c3f06ba9791404a010603a49ec61d..18342f2e38c1be8c51be9d662fed96c24ef83e7a 100644 (file)
@@ -9,20 +9,19 @@
 // except according to those terms.
 
 use ast::{Block, Crate, Ident, Mac_, Name, PatKind};
-use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind};
+use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
 use ast;
-use attr::HasAttrs;
-use ext::mtwt;
-use attr;
+use ext::hygiene::Mark;
+use attr::{self, HasAttrs};
 use attr::AttrMetaMethods;
-use codemap::{dummy_spanned, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
+use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
 use ext::base::*;
 use feature_gate::{self, Features};
 use fold;
 use fold::*;
-use parse::token::{fresh_mark, intern, keywords};
+use parse::token::{intern, keywords};
 use ptr::P;
 use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
@@ -130,9 +129,9 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
     // It would almost certainly be cleaner to pass the whole macro invocation in,
     // rather than pulling it apart and marking the tts and the ctxt separately.
     let Mac_ { path, tts, .. } = mac.node;
-    let mark = fresh_mark();
+    let mark = Mark::fresh();
 
-    fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, mark: Mrk,
+    fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, mark: Mark,
                       attrs: Vec<ast::Attribute>, call_site: Span, fld: &'a mut MacroExpander)
                       -> Option<Box<MacResult + 'a>> {
         // Detect use of feature-gated or invalid attributes on macro invoations
@@ -708,30 +707,17 @@ pub fn expand_crate(mut cx: ExtCtxt,
     return (ret, cx.syntax_env.names);
 }
 
-// HYGIENIC CONTEXT EXTENSION:
-// all of these functions are for walking over
-// ASTs and making some change to the context of every
-// element that has one. a CtxtFn is a trait-ified
-// version of a closure in (SyntaxContext -> SyntaxContext).
-// the ones defined here include:
-// Marker - add a mark to a context
-
 // A Marker adds the given mark to the syntax context and
 // sets spans' `expn_id` to the given expn_id (unless it is `None`).
-struct Marker { mark: Mrk, expn_id: Option<ExpnId> }
+struct Marker { mark: Mark, expn_id: Option<ExpnId> }
 
 impl Folder for Marker {
-    fn fold_ident(&mut self, id: Ident) -> Ident {
-        ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt))
-    }
-    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
-        Spanned {
-            node: Mac_ {
-                path: self.fold_path(node.path),
-                tts: self.fold_tts(&node.tts),
-            },
-            span: self.new_span(span),
-        }
+    fn fold_ident(&mut self, mut ident: Ident) -> Ident {
+        ident.ctxt = ident.ctxt.apply_mark(self.mark);
+        ident
+    }
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+        noop_fold_mac(mac, self)
     }
 
     fn new_span(&mut self, mut span: Span) -> Span {
@@ -743,7 +729,7 @@ fn new_span(&mut self, mut span: Span) -> Span {
 }
 
 // apply a given mark to the given token trees. Used prior to expansion of a macro.
-fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
+fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec<TokenTree> {
     noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None})
 }
 
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
new file mode 100644 (file)
index 0000000..ade165e
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2012-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.
+
+//! Machinery for hygienic macros, inspired by the MTWT[1] paper.
+//!
+//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler.
+//! 2012. *Macros that work together: Compile-time bindings, partial expansion,
+//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
+//! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::fmt;
+
+/// A SyntaxContext represents a chain of macro expansions (represented by marks).
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)]
+pub struct SyntaxContext(u32);
+
+#[derive(Copy, Clone)]
+pub struct SyntaxContextData {
+    pub outer_mark: Mark,
+    pub prev_ctxt: SyntaxContext,
+}
+
+/// A mark represents a unique id associated with a macro expansion.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
+pub struct Mark(u32);
+
+impl Mark {
+    pub fn fresh() -> Self {
+        HygieneData::with(|data| {
+            let next_mark = Mark(data.next_mark.0 + 1);
+            ::std::mem::replace(&mut data.next_mark, next_mark)
+        })
+    }
+}
+
+struct HygieneData {
+    syntax_contexts: Vec<SyntaxContextData>,
+    markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
+    next_mark: Mark,
+}
+
+impl HygieneData {
+    fn new() -> Self {
+        HygieneData {
+            syntax_contexts: vec![SyntaxContextData {
+                outer_mark: Mark(0), // the null mark
+                prev_ctxt: SyntaxContext(0), // the empty context
+            }],
+            markings: HashMap::new(),
+            next_mark: Mark(1),
+        }
+    }
+
+    fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
+        thread_local! {
+            static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
+        }
+        HYGIENE_DATA.with(|data| f(&mut *data.borrow_mut()))
+    }
+}
+
+pub fn reset_hygiene_data() {
+    HygieneData::with(|data| *data = HygieneData::new())
+}
+
+impl SyntaxContext {
+    pub const fn empty() -> Self {
+        SyntaxContext(0)
+    }
+
+    pub fn data(self) -> SyntaxContextData {
+        HygieneData::with(|data| data.syntax_contexts[self.0 as usize])
+    }
+
+    /// Extend a syntax context with a given mark
+    pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
+        // Applying the same mark twice is a no-op
+        let ctxt_data = self.data();
+        if mark == ctxt_data.outer_mark {
+            return ctxt_data.prev_ctxt;
+        }
+
+        HygieneData::with(|data| {
+            let syntax_contexts = &mut data.syntax_contexts;
+            *data.markings.entry((self, mark)).or_insert_with(|| {
+                syntax_contexts.push(SyntaxContextData {
+                    outer_mark: mark,
+                    prev_ctxt: self,
+                });
+                SyntaxContext(syntax_contexts.len() as u32 - 1)
+            })
+        })
+    }
+
+   /// If `ident` is macro expanded, return the source ident from the macro definition
+   /// and the mark of the expansion that created the macro definition.
+   pub fn source(self) -> (Self /* source context */, Mark /* source macro */) {
+        let macro_def_ctxt = self.data().prev_ctxt.data();
+        (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark)
+   }
+}
+
+impl fmt::Debug for SyntaxContext {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "#{}", self.0)
+    }
+}
diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs
deleted file mode 100644 (file)
index d2f6df9..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2012-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.
-
-//! Machinery for hygienic macros, as described in the MTWT[1] paper.
-//!
-//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler.
-//! 2012. *Macros that work together: Compile-time bindings, partial expansion,
-//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
-//! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
-
-pub use self::SyntaxContext_::*;
-
-use ast::{Ident, Mrk, SyntaxContext};
-
-use std::cell::RefCell;
-use std::collections::HashMap;
-
-/// The SCTable contains a table of SyntaxContext_'s. It
-/// represents a flattened tree structure, to avoid having
-/// managed pointers everywhere (that caused an ICE).
-/// The `marks` ensures that adding the same mark to the
-/// same context gives you back the same context as before.
-pub struct SCTable {
-    table: RefCell<Vec<SyntaxContext_>>,
-    marks: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
-}
-
-#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)]
-pub enum SyntaxContext_ {
-    EmptyCtxt,
-    Mark (Mrk,SyntaxContext),
-}
-
-/// Extend a syntax context with a given mark
-pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
-    with_sctable(|table| apply_mark_internal(m, ctxt, table))
-}
-
-/// Extend a syntax context with a given mark and sctable (explicit memoization)
-fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext {
-    let ctxts = &mut *table.table.borrow_mut();
-    match ctxts[ctxt.0 as usize] {
-        // Applying the same mark twice is a no-op.
-        Mark(outer_mark, prev_ctxt) if outer_mark == m => return prev_ctxt,
-        _ => *table.marks.borrow_mut().entry((ctxt, m)).or_insert_with(|| {
-            SyntaxContext(idx_push(ctxts, Mark(m, ctxt)))
-        }),
-    }
-}
-
-/// Fetch the SCTable from TLS, create one if it doesn't yet exist.
-pub fn with_sctable<T, F>(op: F) -> T where
-    F: FnOnce(&SCTable) -> T,
-{
-    thread_local!(static SCTABLE_KEY: SCTable = new_sctable_internal());
-    SCTABLE_KEY.with(move |slot| op(slot))
-}
-
-// Make a fresh syntax context table with EmptyCtxt in slot zero.
-fn new_sctable_internal() -> SCTable {
-    SCTable {
-        table: RefCell::new(vec![EmptyCtxt]),
-        marks: RefCell::new(HashMap::new()),
-    }
-}
-
-/// Clear the tables from TLD to reclaim memory.
-pub fn clear_tables() {
-    with_sctable(|table| {
-        *table.table.borrow_mut() = Vec::new();
-        *table.marks.borrow_mut() = HashMap::new();
-    });
-}
-
-/// Reset the tables to their initial state
-pub fn reset_tables() {
-    with_sctable(|table| {
-        *table.table.borrow_mut() = vec![EmptyCtxt];
-        *table.marks.borrow_mut() = HashMap::new();
-    });
-}
-
-/// Add a value to the end of a vec, return its index
-fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
-    vec.push(val);
-    (vec.len() - 1) as u32
-}
-
-/// Return the outer mark for a context with a mark at the outside.
-/// FAILS when outside is not a mark.
-pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
-    with_sctable(|sctable| {
-        match (*sctable.table.borrow())[ctxt.0 as usize] {
-            Mark(mrk, _) => mrk,
-            _ => panic!("can't retrieve outer mark when outside is not a mark")
-        }
-    })
-}
-
-/// If `ident` is macro expanded, return the source ident from the macro definition
-/// and the mark of the expansion that created the macro definition.
-pub fn source(ident: Ident) -> Option<(Ident /* source ident */, Mrk /* source macro */)> {
-    with_sctable(|sctable| {
-        let ctxts = sctable.table.borrow();
-        if let Mark(_expansion_mark, macro_ctxt) = ctxts[ident.ctxt.0 as usize] {
-            if let Mark(definition_mark, orig_ctxt) = ctxts[macro_ctxt.0 as usize] {
-                return Some((Ident::new(ident.name, orig_ctxt), definition_mark));
-            }
-        }
-        None
-    })
-}
-
-#[cfg(test)]
-mod tests {
-    use ast::{EMPTY_CTXT, Mrk, SyntaxContext};
-    use super::{apply_mark_internal, new_sctable_internal, Mark, SCTable};
-
-    // extend a syntax context with a sequence of marks given
-    // in a vector. v[0] will be the outermost mark.
-    fn unfold_marks(mrks: Vec<Mrk> , tail: SyntaxContext, table: &SCTable)
-                    -> SyntaxContext {
-        mrks.iter().rev().fold(tail, |tail:SyntaxContext, mrk:&Mrk|
-                   {apply_mark_internal(*mrk,tail,table)})
-    }
-
-    #[test] fn unfold_marks_test() {
-        let mut t = new_sctable_internal();
-
-        assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),SyntaxContext(2));
-        {
-            let table = t.table.borrow();
-            assert!((*table)[1] == Mark(7,EMPTY_CTXT));
-            assert!((*table)[2] == Mark(3,SyntaxContext(1)));
-        }
-    }
-
-    #[test]
-    fn hashing_tests () {
-        let mut t = new_sctable_internal();
-        assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(1));
-        assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),SyntaxContext(2));
-        // using the same one again should result in the same index:
-        assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(1));
-        // I'm assuming that the rename table will behave the same....
-    }
-}
index dc9a5ee46645fbabb28aa1775d9b8864df6694b0..a40c30b3e3397fe61d6175a21e5ab9f56bd8bbad 100644 (file)
@@ -22,7 +22,7 @@
 use codemap::CodeMap;
 use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
 use errors::registry::Registry;
-use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
+use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
 use errors::emitter::Emitter;
 
 use std::rc::Rc;
@@ -53,14 +53,7 @@ pub fn stderr(registry: Option<Registry>,
 }
 
 impl Emitter for JsonEmitter {
-    fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, level: Level) {
-        let data = Diagnostic::new(span, msg, code, level, self);
-        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
-            panic!("failed to print diagnostics: {:?}", e);
-        }
-    }
-
-    fn emit_struct(&mut self, db: &DiagnosticBuilder) {
+    fn emit(&mut self, db: &DiagnosticBuilder) {
         let data = Diagnostic::from_diagnostic_builder(db, self);
         if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
             panic!("failed to print diagnostics: {:?}", e);
@@ -146,22 +139,6 @@ struct DiagnosticCode {
 }
 
 impl<'a> Diagnostic<'a> {
-    fn new(msp: &MultiSpan,
-           msg: &'a str,
-           code: Option<&str>,
-           level: Level,
-           je: &JsonEmitter)
-           -> Diagnostic<'a> {
-        Diagnostic {
-            message: msg,
-            code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je),
-            level: level.to_str(),
-            spans: DiagnosticSpan::from_multispan(msp, je),
-            children: vec![],
-            rendered: None,
-        }
-    }
-
     fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder,
                                    je: &JsonEmitter)
                                    -> Diagnostic<'c> {
index 8febf1c49ec2badeb618ed632b4c661168da73d4..5ad1744418890b21f46e0b68139f04bf5386ce51 100644 (file)
@@ -127,7 +127,7 @@ pub mod ext {
     pub mod base;
     pub mod build;
     pub mod expand;
-    pub mod mtwt;
+    pub mod hygiene;
     pub mod quote;
     pub mod source_util;
 
index 77b5c10899a3da8cc158c1003161b44a200d78bf..5ea1d6be9fec9903b3155b7faf60cafe2efe240d 100644 (file)
@@ -1686,7 +1686,7 @@ fn mk_sh(cm: Rc<CodeMap>) -> errors::Handler {
         // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
         let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
                                                 None,
-                                                cm,
+                                                Some(cm),
                                                 errors::snippet::FormatMode::EnvironmentSelected);
         errors::Handler::with_emitter(true, false, Box::new(emitter))
     }
index 9502bc48a3e110f84e0ddf107a3a3181ec92c06d..2147e8ec2eb1f4054ecef0715b4f0ab571786e6f 100644 (file)
@@ -50,7 +50,11 @@ pub struct ParseSess {
 impl ParseSess {
     pub fn new() -> ParseSess {
         let cm = Rc::new(CodeMap::new());
-        let handler = Handler::with_tty_emitter(ColorConfig::Auto, None, true, false, cm.clone());
+        let handler = Handler::with_tty_emitter(ColorConfig::Auto,
+                                                None,
+                                                true,
+                                                false,
+                                                Some(cm.clone()));
         ParseSess::with_span_handler(handler, cm)
     }
 
@@ -224,10 +228,18 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
 // compiler expands into it
 pub fn new_parser_from_tts<'a>(sess: &'a ParseSess,
                                cfg: ast::CrateConfig,
-                               tts: Vec<tokenstream::TokenTree>) -> Parser<'a> {
+                               tts: Vec<tokenstream::TokenTree>)
+                               -> Parser<'a> {
     tts_to_parser(sess, tts, cfg)
 }
 
+pub fn new_parser_from_ts<'a>(sess: &'a ParseSess,
+                              cfg: ast::CrateConfig,
+                              ts: tokenstream::TokenStream)
+                              -> Parser<'a> {
+    tts_to_parser(sess, ts.tts, cfg)
+}
+
 
 // base abstractions
 
index fe9d3ef7c234dff8c364e9f4c9bdffb94183c150..f0a6f8edeec73a241622a50a937b604c5896c6bd 100644 (file)
@@ -633,8 +633,3 @@ pub fn fresh_name(src: ast::Ident) -> ast::Name {
     /*let num = rand::thread_rng().gen_uint_range(0,0xffff);
     gensym(format!("{}_{}",ident_to_string(src),num))*/
 }
-
-// create a fresh mark.
-pub fn fresh_mark() -> ast::Mrk {
-    gensym("mark").0
-}
index 327696e87b08e26fc98ddbc9725f42a1c0a45580..faf6a17a150459fb62cd380b952340d5b90b12d5 100644 (file)
@@ -26,7 +26,7 @@
 
 use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute};
 use errors;
-use errors::snippet::{RenderedLine, SnippetData};
+use errors::snippet::{SnippetData};
 use config;
 use entry::{self, EntryPointType};
 use ext::base::{ExtCtxt, DummyMacroLoader};
index 39bb5956312bce7b752388892d7e33c00dea7625..7dfe19452a2a933a64cdd849e2a21ce535880f50 100644 (file)
@@ -568,7 +568,7 @@ fn sub(self, rhs: CharPos) -> CharPos {
 //
 
 /// A source code location used for error reporting
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct Loc {
     /// Information about the original source
     pub file: Rc<FileMap>,
diff --git a/src/test/compile-fail/issue-34839.rs b/src/test/compile-fail/issue-34839.rs
new file mode 100644 (file)
index 0000000..be7e782
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 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(rustc_attrs)]
+#![allow(dead_code)]
+
+trait RegularExpression: Sized {
+    type Text;
+}
+
+struct ExecNoSyncStr<'a>(&'a u8);
+
+impl<'c> RegularExpression for ExecNoSyncStr<'c> {
+    type Text = u8;
+}
+
+struct FindCaptures<'t, R>(&'t R::Text) where R: RegularExpression, R::Text: 't;
+
+enum FindCapturesInner<'r, 't> {
+    Dynamic(FindCaptures<'t, ExecNoSyncStr<'r>>),
+}
+
+#[rustc_error]
+fn main() {}    //~ ERROR compilation successful
index 57b7b72a1d435b6f8ac0572f5434f5d5a87c128b..888bdf5179a23fe26637ba0c4a2c7ecc451b36a8 100644 (file)
@@ -13,3 +13,7 @@
 macro_rules! m {
     () => { include!("file.txt"); }
 }
+
+macro_rules! n {
+    () => { unsafe { asm!(include_str!("file.txt")); } }
+}
index 7ab9dd19b1b70dc9df3c47a01a7b334e28705a40..e1e85ddb2c1b18a145f6852ddd34e6e0b1a0f8f9 100644 (file)
@@ -8,12 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
+#![feature(asm, rustc_attrs)]
+#![allow(unused)]
 
 #[macro_use]
 mod foo;
 
 m!();
+fn f() { n!(); }
 
 #[rustc_error]
 fn main() {} //~ ERROR compilation successful
index e6c9b1b41c0486bebef3aa6c1e04b86309658a8a..687cdba1542bdce4c9be2889ac2bd453bb5f7da9 100644 (file)
@@ -31,6 +31,6 @@
 //~^ ERROR unresolved import `use_from_trait_xc::Bar::new`
 
 use use_from_trait_xc::Baz::new as baznew;
-//~^ ERROR `baznew` is not directly importable
+//~^ ERROR unresolved import `use_from_trait_xc::Baz::new`
 
 fn main() {}
diff --git a/src/test/ui/codemap_tests/empty_span.rs b/src/test/ui/codemap_tests/empty_span.rs
new file mode 100644 (file)
index 0000000..c78a586
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+#![feature(optin_builtin_traits)]
+fn main() {
+    struct Foo;
+
+    impl !Sync for Foo {}
+
+    unsafe impl Send for &'static Foo { }
+}
diff --git a/src/test/ui/codemap_tests/empty_span.stderr b/src/test/ui/codemap_tests/empty_span.stderr
new file mode 100644 (file)
index 0000000..f3e04ef
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static main::Foo`
+  --> $DIR/empty_span.rs:18:5
+   |
+18 |     unsafe impl Send for &'static Foo { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.rs b/src/test/ui/codemap_tests/huge_multispan_highlight.rs
new file mode 100644 (file)
index 0000000..b06832c
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+fn main() {
+    let x = "foo";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    let y = &mut x;
+}
+
+
+
diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
new file mode 100644 (file)
index 0000000..6a898a4
--- /dev/null
@@ -0,0 +1,11 @@
+error: cannot borrow immutable local variable `x` as mutable
+   --> $DIR/huge_multispan_highlight.rs:100:18
+    |
+14  |     let x = "foo";
+    |         - use `mut x` here to make mutable
+...
+100 |     let y = &mut x;
+    |                  ^ cannot borrow mutably
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/issue-11715.rs b/src/test/ui/codemap_tests/issue-11715.rs
new file mode 100644 (file)
index 0000000..7ea497a
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+fn main() {
+    let mut x = "foo";
+    let y = &mut x;
+    let z = &mut x;
+}
+
+
+
diff --git a/src/test/ui/codemap_tests/issue-11715.stderr b/src/test/ui/codemap_tests/issue-11715.stderr
new file mode 100644 (file)
index 0000000..4947cbe
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+   --> $DIR/issue-11715.rs:100:18
+    |
+99  |     let y = &mut x;
+    |                  - first mutable borrow occurs here
+100 |     let z = &mut x;
+    |                  ^ second mutable borrow occurs here
+101 | }
+    | - first borrow ends here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/one_line.rs b/src/test/ui/codemap_tests/one_line.rs
new file mode 100644 (file)
index 0000000..2a5ee6f
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+fn main() {
+    let mut v = vec![Some("foo"), Some("bar")];
+    v.push(v.pop().unwrap());
+}
diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr
new file mode 100644 (file)
index 0000000..8f80489
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/one_line.rs:15:12
+   |
+15 |     v.push(v.pop().unwrap());
+   |     -      ^               - first borrow ends here
+   |     |      |
+   |     |      second mutable borrow occurs here
+   |     first mutable borrow occurs here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/overlapping_spans.rs b/src/test/ui/codemap_tests/overlapping_spans.rs
new file mode 100644 (file)
index 0000000..5a90852
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+#[derive(Debug)]
+struct Foo { }
+
+struct S {f:String}
+impl Drop for S {
+    fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn main() {
+    match (S {f:"foo".to_string()}) {
+        S {f:_s} => {}
+    }
+}
diff --git a/src/test/ui/codemap_tests/overlapping_spans.stderr b/src/test/ui/codemap_tests/overlapping_spans.stderr
new file mode 100644 (file)
index 0000000..cbcf154
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/overlapping_spans.rs:22:9
+   |
+22 |         S {f:_s} => {}
+   |         ^^^^^--^
+   |         |    |
+   |         |    hint: to prevent move, use `ref _s` or `ref mut _s`
+   |         cannot move out of here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/tab.rs b/src/test/ui/codemap_tests/tab.rs
new file mode 100644 (file)
index 0000000..aaaee8c
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+// ignore-tidy-tab
+fn main() {
+       bar;
+}
+
diff --git a/src/test/ui/codemap_tests/tab.stderr b/src/test/ui/codemap_tests/tab.stderr
new file mode 100644 (file)
index 0000000..543c02f
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0425]: unresolved name `bar`
+  --> $DIR/tab.rs:14:2
+   |
+14 | \tbar;
+   | \t^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/two_files.rs b/src/test/ui/codemap_tests/two_files.rs
new file mode 100644 (file)
index 0000000..53e240e
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+include!("two_files_data.rs");
+
+struct Baz { }
+
+impl Bar for Baz { }
+
+fn main() { }
diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr
new file mode 100644 (file)
index 0000000..6c388cd
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0404]: `Bar` is not a trait
+  --> $DIR/two_files.rs:16:6
+   |
+16 | impl Bar for Baz { }
+   |      ^^^ `Bar` is not a trait
+   | 
+  ::: $DIR/two_files_data.rs
+   |
+15 | type Bar = Foo;
+   | --------------- type aliases cannot be used for traits
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/ui/codemap_tests/two_files_data.rs b/src/test/ui/codemap_tests/two_files_data.rs
new file mode 100644 (file)
index 0000000..412c40f
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+// ignore-test
+trait Foo { }
+
+type Bar = Foo;
+
diff --git a/src/test/ui/codemap_tests/unicode.rs b/src/test/ui/codemap_tests/unicode.rs
new file mode 100644 (file)
index 0000000..1966013
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+extern "路濫狼á́́" fn foo() {}
+
+fn main() { }
diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr
new file mode 100644 (file)
index 0000000..178bee7
--- /dev/null
@@ -0,0 +1,8 @@
+error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́`
+  --> $DIR/unicode.rs:12:8
+   |
+12 | extern "路濫狼á́́" fn foo() {}
+   |        ^^^^^^^^
+
+error: aborting due to previous error
+
index c00594a59c1150fc6f8dde664fcf3b440a736c4b..ff6920d28ccf90a3647df517a6d4dae074feecdd 100644 (file)
@@ -1,15 +1,16 @@
-error: mismatched types [--explain E0308]
+error[E0308]: mismatched types
   --> $DIR/issue-26480.rs:27:19
-   |>
-27 |>                   $arr.len() * size_of($arr[0]));
-   |>                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize
-$DIR/issue-26480.rs:38:5: 38:19: note: in this expansion of write! (defined in $DIR/issue-26480.rs)
+   |
+27 |                   $arr.len() * size_of($arr[0]));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize
+$DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs)
 
 error: non-scalar cast: `_` as `()`
   --> $DIR/issue-26480.rs:33:19
-   |>
-33 |>     ($x:expr) => ($x as ())
-   |>                   ^^^^^^^^
-$DIR/issue-26480.rs:39:5: 39:14: note: in this expansion of cast! (defined in $DIR/issue-26480.rs)
+   |
+33 |     ($x:expr) => ($x as ())
+   |                   ^^^^^^^^
+$DIR/issue-26480.rs:39:5: 39:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs)
 
 error: aborting due to 2 previous errors
+
index 1af332ee5bea7036b7f216bb554b6c3420a4f67e..2903aa08c0a91e744d5ff55bb56028104121df10 100644 (file)
@@ -1,9 +1,11 @@
-error: mismatched types [--explain E0308]
+error[E0308]: mismatched types
   --> $DIR/main.rs:14:18
-   |>
-14 |>     let x: u32 = (
-   |>                  ^ expected u32, found ()
-note: expected type `u32`
-note:    found type `()`
+   |
+14 |     let x: u32 = (
+   |                  ^ expected u32, found ()
+   |
+   = note: expected type `u32`
+   = note:    found type `()`
 
 error: aborting due to previous error
+