Merge branch 'master' into issue-30961

This commit is contained in:
Cameron Hart 2016-07-19 20:57:49 +10:00
commit 79358aa523
80 changed files with 2169 additions and 2561 deletions

19
configure vendored
View file

@ -600,7 +600,7 @@ opt debug-assertions 0 "build with debugging assertions"
opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
opt local-rebuild 0 "use an installed rustc matching the current version, for rebuilds"
opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version"
opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
opt rpath 1 "build rpaths into rustc itself"
opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
@ -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*)

View file

@ -7,10 +7,10 @@ CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so
CFG_STATIC_LIB_NAME_mips-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -mabi=32 $(CFLAGS)
CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -mabi=32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -mabi=32
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_mips-unknown-linux-gnu :=
CFG_INSTALL_NAME_mips-unknown-linux-gnu =

View 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)

View file

@ -20,29 +20,6 @@ CFG_RELEASE_NUM=1.12.0
# versions (section 9)
CFG_PRERELEASE_VERSION=.1
# Append a version-dependent hash to each library, so we can install different
# versions in the same place
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
# A magic value that allows the compiler to use unstable features during the
# bootstrap even when doing so would normally be an error because of feature
# staging or because the build turns on warnings-as-errors and unstable features
# default to warnings. The build has to match this key in an env var.
#
# This value is keyed off the release to ensure that all compilers for one
# particular release have the same bootstrap key. Note that this is
# intentionally not "secure" by any definition, this is largely just a deterrent
# from users enabling unstable features on the stable compiler.
CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA)
# The stage0 compiler needs to use the previous key recorded in src/stage0.txt,
# except for local-rebuild when it just uses the same current key.
ifdef CFG_ENABLE_LOCAL_REBUILD
CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY)
else
CFG_BOOTSTRAP_KEY_STAGE0=$(shell grep 'rustc_key' $(S)src/stage0.txt | sed 's/rustc_key: '//)
endif
ifeq ($(CFG_RELEASE_CHANNEL),stable)
# This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
CFG_RELEASE=$(CFG_RELEASE_NUM)
@ -72,6 +49,38 @@ CFG_RELEASE=$(CFG_RELEASE_NUM)-dev
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-dev
endif
# Append a version-dependent hash to each library, so we can install different
# versions in the same place
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
# A magic value that allows the compiler to use unstable features during the
# bootstrap even when doing so would normally be an error because of feature
# staging or because the build turns on warnings-as-errors and unstable features
# default to warnings. The build has to match this key in an env var.
#
# This value is keyed off the release to ensure that all compilers for one
# particular release have the same bootstrap key. Note that this is
# intentionally not "secure" by any definition, this is largely just a deterrent
# from users enabling unstable features on the stable compiler.
CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA)
# If local-rust is the same as the current version, then force a local-rebuild
ifdef CFG_ENABLE_LOCAL_RUST
ifeq ($(CFG_RELEASE),\
$(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT)))
CFG_INFO := $(info cfg: auto-detected local-rebuild $(CFG_RELEASE))
CFG_ENABLE_LOCAL_REBUILD = 1
endif
endif
# The stage0 compiler needs to use the previous key recorded in src/stage0.txt,
# except for local-rebuild when it just uses the same current key.
ifdef CFG_ENABLE_LOCAL_REBUILD
CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY)
else
CFG_BOOTSTRAP_KEY_STAGE0=$(shell sed -ne 's/^rustc_key: //p' $(S)src/stage0.txt)
endif
# The name of the package to use for creating tarballs, installers etc.
CFG_PACKAGE_NAME=rustc-$(CFG_PACKAGE_VERS)

View file

@ -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

View file

@ -11,6 +11,7 @@ endif
$(SNAPSHOT_RUSTC_POST_CLEANUP): \
$(S)src/stage0.txt \
$(S)src/etc/local_stage0.sh \
$(S)src/etc/get-stage0.py $(MKFILE_DEPS) \
| $(HBIN0_H_$(CFG_BUILD))/
@$(call E, fetch: $@)

View file

@ -317,6 +317,7 @@ impl Config {
("OPTIMIZE_TESTS", self.rust_optimize_tests),
("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
("LOCAL_REBUILD", self.local_rebuild),
("NINJA", self.ninja),
}
match key {

View file

@ -118,6 +118,7 @@ pub struct Build {
ver_date: Option<String>,
version: String,
package_vers: String,
local_rebuild: bool,
bootstrap_key: String,
bootstrap_key_stage0: String,
@ -174,6 +175,7 @@ impl Build {
Some(ref s) => PathBuf::from(s),
None => stage0_root.join(exe("cargo", &config.build)),
};
let local_rebuild = config.local_rebuild;
Build {
flags: flags,
@ -189,6 +191,7 @@ impl Build {
short_ver_hash: None,
ver_date: None,
version: String::new(),
local_rebuild: local_rebuild,
bootstrap_key: String::new(),
bootstrap_key_stage0: String::new(),
package_vers: String::new(),
@ -219,6 +222,16 @@ impl Build {
sanity::check(self);
self.verbose("collecting channel variables");
channel::collect(self);
// If local-rust is the same as the current version, then force a local-rebuild
let local_version_verbose = output(
Command::new(&self.rustc).arg("--version").arg("--verbose"));
let local_release = local_version_verbose
.lines().filter(|x| x.starts_with("release:"))
.next().unwrap().trim_left_matches("release:").trim();
if local_release == self.release {
self.verbose(&format!("auto-detected local-rebuild {}", self.release));
self.local_rebuild = true;
}
self.verbose("updating submodules");
self.update_submodules();
@ -525,7 +538,7 @@ impl Build {
.arg("--target").arg(target);
let stage;
if compiler.stage == 0 && self.config.local_rebuild {
if compiler.stage == 0 && self.local_rebuild {
// Assume the local-rebuild rustc already has stage1 features.
stage = 1;
} else {
@ -766,7 +779,7 @@ impl Build {
// In stage0 we're using a previously released stable compiler, so we
// use the stage0 bootstrap key. Otherwise we use our own build's
// bootstrap key.
let bootstrap_key = if compiler.is_snapshot(self) && !self.config.local_rebuild {
let bootstrap_key = if compiler.is_snapshot(self) && !self.local_rebuild {
&self.bootstrap_key_stage0
} else {
&self.bootstrap_key

View 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`.

View 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

View 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

View file

@ -49,6 +49,13 @@ if [ -z $TARG_DIR ]; then
exit 1
fi
case "$TARG_DIR" in
--print-rustc-release)
# not actually copying to TARG_DIR, just print the local rustc version and exit
${PREFIX}/bin/rustc${BIN_SUF} --version --verbose | sed -ne 's/^release: //p'
;;
*)
cp ${PREFIX}/bin/rustc${BIN_SUF} ${TARG_DIR}/stage0/bin/
cp ${PREFIX}/${LIB_DIR}/${RUSTLIBDIR}/${TARG_DIR}/${LIB_DIR}/* ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
@ -66,3 +73,5 @@ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}term*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DI
# do not fail if one of the above fails, as all we need is a working rustc!
exit 0
esac

View file

@ -520,7 +520,7 @@ impl<T> Vec<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.

View file

@ -18,7 +18,7 @@ use ptr;
/// 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 @@ impl 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 @@ impl 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 @@ impl super::Hasher for SipHasher {
}
}
#[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 @@ impl super::Hasher for SipHasher13 {
}
}
#[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]) {

View file

@ -491,8 +491,6 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExactSizeIterator: Iterator {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Returns the exact number of times the iterator will iterate.
///
/// This method has a default implementation, so you usually should not
@ -516,6 +514,8 @@ pub trait ExactSizeIterator: Iterator {
///
/// assert_eq!(5, five.len());
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn len(&self) -> usize {
let (lower, upper) = self.size_hint();
// Note: This assertion is overly defensive, but it checks the invariant
@ -525,6 +525,32 @@ pub trait ExactSizeIterator: Iterator {
assert_eq!(upper, Some(lower));
lower
}
/// Returns whether the iterator is empty.
///
/// This method has a default implementation using `self.len()`, so you
/// don't need to implement it yourself.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(exact_size_is_empty)]
///
/// let mut one_element = 0..1;
/// assert!(!one_element.is_empty());
///
/// assert_eq!(one_element.next(), Some(0));
/// assert!(one_element.is_empty());
///
/// assert_eq!(one_element.next(), None);
/// ```
#[inline]
#[unstable(feature = "exact_size_is_empty", issue = "0")]
fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[stable(feature = "rust1", since = "1.0.0")]

View 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:
//!
@ -34,11 +36,12 @@
//! 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.

View 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);

View file

@ -571,12 +571,21 @@ macro_rules! fnptr_impls_safety_abi {
}
macro_rules! fnptr_impls_args {
($($Arg: ident),*) => {
($($Arg: ident),+) => {
fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),*) -> Ret, $($Arg),* }
fnptr_impls_safety_abi! { extern "C" fn($($Arg),*) -> Ret, $($Arg),* }
fnptr_impls_safety_abi! { extern "C" fn($($Arg),* , ...) -> Ret, $($Arg),* }
fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),*) -> Ret, $($Arg),* }
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),*) -> Ret, $($Arg),* }
}
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),* , ...) -> Ret, $($Arg),* }
};
() => {
// No variadic functions with 0 parameters
fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, }
};
}
fnptr_impls_args! { }

View file

@ -171,3 +171,17 @@ fn test_unsized_unique() {
let zs: &mut [i32] = &mut [1, 2, 3];
assert!(ys == zs);
}
#[test]
fn test_variadic_fnptr() {
use core::hash::{Hash, SipHasher};
extern "C" {
fn printf(_: *const u8, ...);
}
let p: unsafe extern "C" fn(*const u8, ...) = printf;
let q = p.clone();
assert_eq!(p, q);
assert!(!(p < q));
let mut s = SipHasher::new();
assert_eq!(p.hash(&mut s), q.hash(&mut s));
}

View file

@ -94,7 +94,7 @@ use syntax::ast;
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 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
"{}",
trace.origin);
if !is_simple_error || check_old_skool() {
if !is_simple_error || check_old_school() {
err.note_expected_found(&"type", &expected, &found);
}

View file

@ -739,8 +739,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"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,

View file

@ -22,7 +22,8 @@ use mir::transform as mir_pass;
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.

View file

@ -236,8 +236,8 @@ pub fn compile_input(sess: &Session,
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 {

View file

@ -101,6 +101,7 @@ use syntax::feature_gate::{GatedCfg, UnstableFeatures};
use syntax::parse::{self, PResult};
use syntax_pos::MultiSpan;
use errors::emitter::Emitter;
use errors::snippet::FormatMode;
#[cfg(test)]
pub mod test;
@ -139,10 +140,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();
}
}
@ -374,23 +380,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);
}
_ => {},
}
@ -1070,26 +1079,34 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
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);
}

View file

@ -456,7 +456,7 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
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)?;

View file

@ -33,8 +33,8 @@ use syntax::ast;
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);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -49,6 +49,7 @@ use std::thread::panicking;
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 @@ impl<'a> DiagnosticBuilder<'a> {
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 @@ impl<'a> DiagnosticBuilder<'a> {
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 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
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 @@ impl<'a> Drop for DiagnosticBuilder<'a> {
/// 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 @@ impl Handler {
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 @@ impl Handler {
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 @@ impl Handler {
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 @@ impl Handler {
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 @@ impl Handler {
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 @@ impl Handler {
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 @@ impl Handler {
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
}

View file

@ -10,12 +10,10 @@
// 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),
}

View file

@ -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()
}
}

View file

@ -698,7 +698,8 @@ impl LateLintPass for VariantSizeDifferences {
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)
})
});

View 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);

View 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 @@ impl<'a> Resolver<'a> {
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 @@ impl<'a> Folder for NodeIdAssigner<'a> {
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;
}
}

View file

@ -53,7 +53,7 @@ use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace};
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 @@ impl<'a> Resolver<'a> {
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 @@ impl<'a> Resolver<'a> {
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;
}
}
_ => {

View file

@ -19,8 +19,8 @@ use llvm::SMDiagnosticRef;
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 @@ impl SharedEmitter {
}
}
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

View file

@ -2270,12 +2270,9 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
let is_decl = llvm::LLVMIsDeclaration(val) != 0;
if is_decl || is_available_externally {
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes()
.to_vec();
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
declared.insert(name);
}
}
}
@ -2286,21 +2283,21 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
let linkage = llvm::LLVMGetLinkage(val);
let is_external = linkage == llvm::ExternalLinkage as c_uint;
let is_weak_odr = linkage == llvm::WeakODRLinkage as c_uint;
let is_decl = llvm::LLVMIsDeclaration(val) != 0;
let is_externally_visible = (linkage == llvm::ExternalLinkage as c_uint) ||
(linkage == llvm::LinkOnceODRLinkage as c_uint) ||
(linkage == llvm::WeakODRLinkage as c_uint);
let is_definition = llvm::LLVMIsDeclaration(val) != 0;
// We only care about external definitions.
if (is_external || is_weak_odr) && !is_decl {
// If this is a definition (as opposed to just a declaration)
// and externally visible, check if we can internalize it
if is_definition && is_externally_visible {
let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val));
let name_str = name_cstr.to_str().unwrap();
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes()
.to_vec();
let is_referenced_somewhere = declared.contains(&name_cstr);
let is_reachable = reachable.contains(name_str);
let is_declared = declared.contains(&name);
let reachable = reachable.contains(str::from_utf8(&name).unwrap());
if !is_declared && !reachable {
if !is_referenced_somewhere && !is_reachable {
llvm::SetLinkage(val, llvm::InternalLinkage);
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
llvm::UnsetComdat(val);
@ -2488,7 +2485,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Run the translation item collector and partition the collected items into
// codegen units.
let (codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx);
let codegen_unit_count = codegen_units.len();
let symbol_map = Rc::new(symbol_map);
@ -2620,10 +2616,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}));
}
if codegen_unit_count > 1 {
internalize_symbols(&crate_context_list,
&reachable_symbols.iter().map(|x| &x[..]).collect());
}
internalize_symbols(&crate_context_list,
&reachable_symbols.iter().map(|x| &x[..]).collect());
if sess.target.target.options.is_like_msvc &&
sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {

View 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();

View 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 runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
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()));

View file

@ -19,6 +19,7 @@ pub use util::ThinVec;
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;
@ -33,15 +34,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder};
#[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 @@ impl Decodable for Name {
}
}
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 @@ impl Decodable for Ident {
}
}
/// 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,

View file

@ -827,12 +827,6 @@ impl CodeMapper for CodeMap {
#[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 @@ mod tests {
}
}
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 @@ r"blork2.rs:2:1: 2:12
";
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--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--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..]);
}
}

View file

@ -816,6 +816,12 @@ impl<'a> ExtCtxt<'a> {
/// 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 {

View 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_ident(&mut self, mut ident: Ident) -> Ident {
ident.ctxt = ident.ctxt.apply_mark(self.mark);
ident
}
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_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 @@ impl Folder for Marker {
}
// 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})
}

View file

@ -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)
}
}

View file

@ -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....
}
}

View 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 @@ impl JsonEmitter {
}
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> {

View 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;

View file

@ -18,23 +18,43 @@ use parse::token;
use parse::parser::{Parser, TokenType};
use ptr::P;
#[derive(PartialEq, Eq, Debug)]
enum InnerAttributeParsePolicy<'a> {
Permitted,
NotPermitted { reason: &'a str },
}
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &'static str = "an inner attribute is not \
permitted in this context";
impl<'a> Parser<'a> {
/// Parse attributes that appear before an item
pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
let mut attrs: Vec<ast::Attribute> = Vec::new();
let mut just_parsed_doc_comment = false;
loop {
debug!("parse_outer_attributes: self.token={:?}", self.token);
match self.token {
token::Pound => {
attrs.push(self.parse_attribute(false)?);
let inner_error_reason = if just_parsed_doc_comment {
"an inner attribute is not permitted following an outer doc comment"
} else if !attrs.is_empty() {
"an inner attribute is not permitted following an outer attribute"
} else {
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
};
let inner_parse_policy =
InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
attrs.push(self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?);
just_parsed_doc_comment = false;
}
token::DocComment(s) => {
let attr = ::attr::mk_sugared_doc_attr(
attr::mk_attr_id(),
self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)),
self.span.lo,
self.span.hi
);
attr::mk_attr_id(),
self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)),
self.span.lo,
self.span.hi
);
if attr.node.style != ast::AttrStyle::Outer {
let mut err = self.fatal("expected outer doc comment");
err.note("inner doc comments like this (starting with \
@ -43,6 +63,7 @@ impl<'a> Parser<'a> {
}
attrs.push(attr);
self.bump();
just_parsed_doc_comment = true;
}
_ => break,
}
@ -55,26 +76,46 @@ impl<'a> Parser<'a> {
/// If permit_inner is true, then a leading `!` indicates an inner
/// attribute
pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
debug!("parse_attributes: permit_inner={:?} self.token={:?}",
debug!("parse_attribute: permit_inner={:?} self.token={:?}",
permit_inner,
self.token);
let inner_parse_policy = if permit_inner {
InnerAttributeParsePolicy::Permitted
} else {
InnerAttributeParsePolicy::NotPermitted
{ reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
};
self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
}
/// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
/// that prescribes how to handle inner attributes.
fn parse_attribute_with_inner_parse_policy(&mut self,
inner_parse_policy: InnerAttributeParsePolicy)
-> PResult<'a, ast::Attribute> {
debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
inner_parse_policy,
self.token);
let (span, value, mut style) = match self.token {
token::Pound => {
let lo = self.span.lo;
self.bump();
if permit_inner {
if inner_parse_policy == InnerAttributeParsePolicy::Permitted {
self.expected_tokens.push(TokenType::Token(token::Not));
}
let style = if self.token == token::Not {
self.bump();
if !permit_inner {
if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
{
let span = self.span;
self.diagnostic()
.struct_span_err(span,
"an inner attribute is not permitted in this context")
.help("place inner attribute at the top of the module or \
block")
.struct_span_err(span, reason)
.note("inner attributes and doc comments, like `#![no_std]` or \
`//! My crate`, annotate the item enclosing them, and are \
usually found at the beginning of source files. Outer \
attributes and doc comments, like `#[test]` and
`/// My function`, annotate the item following them.")
.emit()
}
ast::AttrStyle::Inner
@ -95,7 +136,8 @@ impl<'a> Parser<'a> {
}
};
if permit_inner && self.token == token::Semi {
if inner_parse_policy == InnerAttributeParsePolicy::Permitted &&
self.token == token::Semi {
self.bump();
self.span_warn(span,
"this inner attribute syntax is deprecated. The new syntax is \

View file

@ -1686,7 +1686,7 @@ mod tests {
// 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))
}

View 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

View file

@ -3789,13 +3789,8 @@ impl<'a> Parser<'a> {
/// Parse a statement. This stops just before trailing semicolons on everything but items.
/// e.g. a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
///
/// Also, if a macro begins an expression statement, this only parses the macro. For example,
/// ```rust
/// vec![1].into_iter(); //< `parse_stmt` only parses the "vec![1]"
/// ```
pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
Ok(self.parse_stmt_())
Ok(self.parse_stmt_(true))
}
// Eat tokens until we can be relatively sure we reached the end of the
@ -3859,15 +3854,15 @@ impl<'a> Parser<'a> {
}
}
fn parse_stmt_(&mut self) -> Option<Stmt> {
self.parse_stmt_without_recovery().unwrap_or_else(|mut e| {
fn parse_stmt_(&mut self, macro_expanded: bool) -> Option<Stmt> {
self.parse_stmt_without_recovery(macro_expanded).unwrap_or_else(|mut e| {
e.emit();
self.recover_stmt_(SemiColonMode::Break);
None
})
}
fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
fn parse_stmt_without_recovery(&mut self, macro_expanded: bool) -> PResult<'a, Option<Stmt>> {
maybe_whole!(Some deref self, NtStmt);
let attrs = self.parse_outer_attributes()?;
@ -3930,10 +3925,34 @@ impl<'a> Parser<'a> {
if id.name == keywords::Invalid.name() {
let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts });
let node = if delim == token::Brace ||
self.token == token::Semi || self.token == token::Eof {
StmtKind::Mac(P((mac, style, attrs.into())))
}
// We used to incorrectly stop parsing macro-expanded statements here.
// If the next token will be an error anyway but could have parsed with the
// earlier behavior, stop parsing here and emit a warning to avoid breakage.
else if macro_expanded && self.token.can_begin_expr() && match self.token {
// These can continue an expression, so we can't stop parsing and warn.
token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
token::BinOp(token::Minus) | token::BinOp(token::Star) |
token::BinOp(token::And) | token::BinOp(token::Or) |
token::AndAnd | token::OrOr |
token::DotDot | token::DotDotDot => false,
_ => true,
} {
self.warn_missing_semicolon();
StmtKind::Mac(P((mac, style, attrs.into())))
} else {
let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new());
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
StmtKind::Expr(e)
};
Stmt {
id: ast::DUMMY_NODE_ID,
node: StmtKind::Mac(P((mac, style, attrs.into()))),
span: mk_sp(lo, hi),
node: node,
}
} else {
// if it has a special ident, it's definitely an item
@ -4061,49 +4080,12 @@ impl<'a> Parser<'a> {
}
/// Parse a statement, including the trailing semicolon.
/// This parses expression statements that begin with macros correctly (c.f. `parse_stmt`).
pub fn parse_full_stmt(&mut self, macro_expanded: bool) -> PResult<'a, Option<Stmt>> {
let mut stmt = match self.parse_stmt_() {
let mut stmt = match self.parse_stmt_(macro_expanded) {
Some(stmt) => stmt,
None => return Ok(None),
};
if let StmtKind::Mac(mac) = stmt.node {
if mac.1 != MacStmtStyle::NoBraces ||
self.token == token::Semi || self.token == token::Eof {
stmt.node = StmtKind::Mac(mac);
} else {
// We used to incorrectly stop parsing macro-expanded statements here.
// If the next token will be an error anyway but could have parsed with the
// earlier behavior, stop parsing here and emit a warning to avoid breakage.
if macro_expanded && self.token.can_begin_expr() && match self.token {
// These tokens can continue an expression, so we can't stop parsing and warn.
token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
token::BinOp(token::Minus) | token::BinOp(token::Star) |
token::BinOp(token::And) | token::BinOp(token::Or) |
token::AndAnd | token::OrOr |
token::DotDot | token::DotDotDot => false,
_ => true,
} {
self.warn_missing_semicolon();
stmt.node = StmtKind::Mac(mac);
return Ok(Some(stmt));
}
let (mac, _style, attrs) = mac.unwrap();
let e = self.mk_mac_expr(stmt.span.lo, stmt.span.hi, mac.node, ThinVec::new());
let e = self.parse_dot_or_call_expr_with(e, stmt.span.lo, attrs)?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
stmt.node = StmtKind::Expr(e);
}
}
stmt = self.handle_trailing_semicolon(stmt, macro_expanded)?;
Ok(Some(stmt))
}
fn handle_trailing_semicolon(&mut self, mut stmt: Stmt, macro_expanded: bool)
-> PResult<'a, Stmt> {
match stmt.node {
StmtKind::Expr(ref expr) if self.token != token::Eof => {
// expression without semicolon
@ -4133,7 +4115,7 @@ impl<'a> Parser<'a> {
}
stmt.span.hi = self.last_span.hi;
Ok(stmt)
Ok(Some(stmt))
}
fn warn_missing_semicolon(&self) {

View 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
}

View file

@ -26,7 +26,7 @@ use std::rc::Rc;
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};

View file

@ -568,7 +568,7 @@ impl Sub for 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>,

View file

@ -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

View file

@ -13,3 +13,7 @@
macro_rules! m {
() => { include!("file.txt"); }
}
macro_rules! n {
() => { unsafe { asm!(include_str!("file.txt")); } }
}

View 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

View file

@ -0,0 +1,17 @@
// 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)]
#[rustc_error]
fn main() { //~ ERROR compilation successful
macro_rules! m { ($s:stmt;) => { $s } }
m!(vec![].push(0););
}

View file

@ -18,7 +18,8 @@ fn foo<F>(f: F) where F: FnMut(Foo) {}
fn main() {
foo(|s| s.is_empty());
//~^ ERROR no method named `is_empty` found
//~^^ HELP #1: `core::slice::SliceExt`
//~^^^ HELP #2: `core::str::StrExt`
//~^^^^ HELP items from traits can only be used if the trait is implemented and in scope; the following traits define an item `is_empty`, perhaps you need to implement one of them:
//~^^ HELP #1: `std::iter::ExactSizeIterator`
//~^^^ HELP #2: `core::slice::SliceExt`
//~^^^^ HELP #3: `core::str::StrExt`
//~^^^^^ HELP items from traits can only be used if the trait is implemented and in scope; the following traits define an item `is_empty`, perhaps you need to implement one of them:
}

View file

@ -31,6 +31,6 @@ use use_from_trait_xc::Bar::new as bnew;
//~^ 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() {}

View file

@ -0,0 +1,20 @@
// 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.
// compile-flags: -Z parse-only
#![feature(lang_items)]
/**
* My module
*/
#![recursion_limit="100"]
//~^ ERROR an inner attribute is not permitted following an outer doc comment
fn main() {}

View file

@ -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.
// compile-flags: -Z parse-only
#[feature(lang_items)]
#![recursion_limit="100"] //~ ERROR an inner attribute is not permitted following an outer attribute
fn main() {}

View file

@ -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 { }
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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());
}

View file

@ -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

View file

@ -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} => {}
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -0,0 +1,8 @@
error[E0425]: unresolved name `bar`
--> $DIR/tab.rs:14:2
|
14 | \tbar;
| \t^^^
error: aborting due to previous error

View file

@ -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() { }

View file

@ -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

View file

@ -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;

View file

@ -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() { }

View file

@ -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

View 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

View 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