+Version 1.20.0 (2017-08-31)
+===========================
+
+Language
+--------
+- [Associated constants in traits is now stabilised.][42809]
+- [A lot of macro bugs are now fixed.][42913]
+
+Compiler
+--------
+
+- [Struct fields are now properly coerced to the expected field type.][42807]
+- [Enabled wasm LLVM backend][42571] WASM can now be built with the
+ `wasm32-experimental-emscripten` target.
+- [Changed some of the error messages to be more helpful.][42033]
+- [Add support for RELRO(RELocation Read-Only) for platforms that support
+ it.][43170]
+- [rustc now reports the total number of errors on compilation failure][43015]
+ previously this was only the number of errors in the pass that failed.
+- [Expansion in rustc has been sped up 29x.][42533]
+- [added `msp430-none-elf` target.][43099]
+- [rustc will now suggest one-argument enum variant to fix type mismatch when
+ applicable][43178]
+- [Fixes backtraces on Redox][43228]
+- [rustc now identifies different versions of same crate when absolute paths of
+ different types match in an error message.][42826]
+
+Libraries
+---------
+
+
+- [Relaxed Debug constraints on `{HashMap,BTreeMap}::{Keys,Values}`.][42854]
+- [Impl `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Debug`, `Hash` for unsized
+ tuples.][43011]
+- [Impl `fmt::{Display, Debug}` for `Ref`, `RefMut`, `MutexGuard`,
+ `RwLockReadGuard`, `RwLockWriteGuard`][42822]
+- [Impl `Clone` for `DefaultHasher`.][42799]
+- [Impl `Sync` for `SyncSender`.][42397]
+- [Impl `FromStr` for `char`][42271]
+- [Fixed how `{f32, f64}::{is_sign_negative, is_sign_positive}` handles
+ NaN.][42431]
+- [allow messages in the `unimplemented!()` macro.][42155]
+ ie. `unimplemented!("Waiting for 1.21 to be stable")`
+- [`pub(restricted)` is now supported in the `thread_local!` macro.][43185]
+- [Upgrade to Unicode 10.0.0][42999]
+- [Reimplemented `{f32, f64}::{min, max}` in Rust instead of using CMath.][42430]
+- [Skip the main thread's manual stack guard on Linux][43072]
+- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in O(1) time][43077]
+- [`#[repr(align(N))]` attribute max number is now 2^31 - 1.][43097] This was
+ previously 2^15.
+- [`{OsStr, Path}::Display` now avoids allocations where possible][42613]
+
+Stabilized APIs
+---------------
+
+- [`CStr::into_c_string`]
+- [`CString::as_c_str`]
+- [`CString::into_boxed_c_str`]
+- [`Chain::get_mut`]
+- [`Chain::get_ref`]
+- [`Chain::into_inner`]
+- [`Option::get_or_insert_with`]
+- [`Option::get_or_insert`]
+- [`OsStr::into_os_string`]
+- [`OsString::into_boxed_os_str`]
+- [`Take::get_mut`]
+- [`Take::get_ref`]
+- [`Utf8Error::error_len`]
+- [`char::EscapeDebug`]
+- [`char::escape_debug`]
+- [`compile_error!`]
+- [`f32::from_bits`]
+- [`f32::to_bits`]
+- [`f64::from_bits`]
+- [`f64::to_bits`]
+- [`mem::ManuallyDrop`]
+- [`slice::sort_unstable_by_key`]
+- [`slice::sort_unstable_by`]
+- [`slice::sort_unstable`]
+- [`ste::from_boxed_utf8_unchecked`]
+- [`str::as_bytes_mut`]
+- [`str::as_bytes_mut`]
+- [`str::from_utf8_mut`]
+- [`str::from_utf8_unchecked_mut`]
+- [`str::get_mut`]
+- [`str::get_unchecked_mut`]
+- [`str::get_unchecked`]
+- [`str::get`]
+- [`str::into_boxed_bytes`]
+
+
+Cargo
+-----
+- [Cargo API token location moved from `~/.cargo/config` to
+ `~/cargo/credentials`.][cargo/3978]
+- [Cargo will now build `main.rs` binaries that are in sub-directories of
+ `src/bin`.][cargo/4214] ie. Having `src/bin/server/main.rs` and
+ `src/bin/client/main.rs` generates `target/debug/server` and `target/debug/client`
+- [You can now specify version of a binary when installed through
+ `cargo install` using `--vers`.][cargo/4229]
+- [Added `--no-fail-fast` flag to cargo to run all benchmarks regardless of
+ failure.][cargo/4248]
+- [Changed the convention around which file is the crate root.][cargo/4259]
+- [The `include`/`exclude` property in `Cargo.toml` now accepts gitignore paths
+ instead of glob patterns][cargo/4270]. Glob patterns are now deprecated.
+
+Compatibility Notes
+-------------------
+
+- [Functions with `'static` in their return types will now not be as usable as
+ if they were using lifetime parameters instead.][42417]
+- [The reimplementation of `{f32, f64}::is_sign_{negative, positive}` now
+ takes the sign of NaN into account where previously didn't.][42430]
+
+[42033]: https://github.com/rust-lang/rust/pull/42033
+[42155]: https://github.com/rust-lang/rust/pull/42155
+[42271]: https://github.com/rust-lang/rust/pull/42271
+[42397]: https://github.com/rust-lang/rust/pull/42397
+[42417]: https://github.com/rust-lang/rust/pull/42417
+[42430]: https://github.com/rust-lang/rust/pull/42430
+[42431]: https://github.com/rust-lang/rust/pull/42431
+[42533]: https://github.com/rust-lang/rust/pull/42533
+[42571]: https://github.com/rust-lang/rust/pull/42571
+[42613]: https://github.com/rust-lang/rust/pull/42613
+[42799]: https://github.com/rust-lang/rust/pull/42799
+[42807]: https://github.com/rust-lang/rust/pull/42807
+[42809]: https://github.com/rust-lang/rust/pull/42809
+[42822]: https://github.com/rust-lang/rust/pull/42822
+[42826]: https://github.com/rust-lang/rust/pull/42826
+[42854]: https://github.com/rust-lang/rust/pull/42854
+[42913]: https://github.com/rust-lang/rust/pull/42913
+[42999]: https://github.com/rust-lang/rust/pull/42999
+[43011]: https://github.com/rust-lang/rust/pull/43011
+[43015]: https://github.com/rust-lang/rust/pull/43015
+[43072]: https://github.com/rust-lang/rust/pull/43072
+[43077]: https://github.com/rust-lang/rust/pull/43077
+[43097]: https://github.com/rust-lang/rust/pull/43097
+[43099]: https://github.com/rust-lang/rust/pull/43099
+[43170]: https://github.com/rust-lang/rust/pull/43170
+[43178]: https://github.com/rust-lang/rust/pull/43178
+[43185]: https://github.com/rust-lang/rust/pull/43185
+[43228]: https://github.com/rust-lang/rust/pull/43228
+[cargo/3978]: https://github.com/rust-lang/cargo/pull/3978
+[cargo/4214]: https://github.com/rust-lang/cargo/pull/4214
+[cargo/4229]: https://github.com/rust-lang/cargo/pull/4229
+[cargo/4248]: https://github.com/rust-lang/cargo/pull/4248
+[cargo/4259]: https://github.com/rust-lang/cargo/pull/4259
+[cargo/4270]: https://github.com/rust-lang/cargo/pull/4270
+[`CStr::into_c_string`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.into_c_string
+[`CString::as_c_str`]: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.as_c_str
+[`CString::into_boxed_c_str`]: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
+[`Chain::get_mut`]: https://doc.rust-lang.org/std/io/struct.Chain.html#method.get_mut
+[`Chain::get_ref`]: https://doc.rust-lang.org/std/io/struct.Chain.html#method.get_ref
+[`Chain::into_inner`]: https://doc.rust-lang.org/std/io/struct.Chain.html#method.into_inner
+[`Option::get_or_insert_with`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.get_or_insert_with
+[`Option::get_or_insert`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.get_or_insert
+[`OsStr::into_os_string`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.into_os_string
+[`OsString::into_boxed_os_str`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html#method.into_boxed_os_str
+[`Take::get_mut`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.get_mut
+[`Take::get_ref`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.get_ref
+[`Utf8Error::error_len`]: https://doc.rust-lang.org/std/str/struct.Utf8Error.html#method.error_len
+[`char::EscapeDebug`]: https://doc.rust-lang.org/std/char/struct.EscapeDebug.html
+[`char::escape_debug`]: https://doc.rust-lang.org/std/primitive.char.html#method.escape_debug
+[`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
+[`f32::from_bits`]: https://doc.rust-lang.org/std/primitive.f32.html#method.from_bits
+[`f32::to_bits`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_bits
+[`f64::from_bits`]: https://doc.rust-lang.org/std/primitive.f64.html#method.from_bits
+[`f64::to_bits`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_bits
+[`mem::ManuallyDrop`]: https://doc.rust-lang.org/std/mem/union.ManuallyDrop.html
+[`slice::sort_unstable_by_key`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable_by_key
+[`slice::sort_unstable_by`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable_by
+[`slice::sort_unstable`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable
+[`ste::from_boxed_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_boxed_utf8_unchecked.html
+[`str::as_bytes_mut`]: https://doc.rust-lang.org/std/primitive.str.html#method.as_bytes_mut
+[`str::as_bytes_mut`]: https://doc.rust-lang.org/std/primitive.str.html#method.as_bytes_mut
+[`str::from_utf8_mut`]: https://doc.rust-lang.org/std/str/fn.from_utf8_mut.html
+[`str::from_utf8_unchecked_mut`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked_mut.html
+[`str::get_mut`]: https://doc.rust-lang.org/std/primitive.str.html#method.get_mut
+[`str::get_unchecked_mut`]: https://doc.rust-lang.org/std/primitive.str.html#method.get_unchecked_mut
+[`str::get_unchecked`]: https://doc.rust-lang.org/std/primitive.str.html#method.get_unchecked
+[`str::get`]: https://doc.rust-lang.org/std/primitive.str.html#method.get
+[`str::into_boxed_bytes`]: https://doc.rust-lang.org/std/primitive.str.html#method.into_boxed_bytes
+
+
Version 1.19.0 (2017-07-20)
===========================
* [Test binaries now support a `--test-threads` argument to specify the number
of threads used to run tests, and which acts the same as the
- `RUST_TEST_THREADS` environment variable](https://github.com/rust-lang/rust/pull/35414)
+ `RUST_TEST_THREADS` environment variable](https://github.com/rust-lang/rust/pull/35414)
* [The test runner now emits a warning when tests run over 60 seconds](https://github.com/rust-lang/rust/pull/35405)
* [rustdoc: Fix methods in search results](https://github.com/rust-lang/rust/pull/34752)
* [`rust-lldb` warns about unsupported versions of LLDB](https://github.com/rust-lang/rust/pull/34646)
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "ar"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "arena"
version = "0.0.0"
name = "rustc_driver"
version = "0.0.0"
dependencies = [
+ "ar 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"arena 0.0.0",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_allocator 0.0.0",
"rustc_back 0.0.0",
"rustc_resolve 0.0.0",
"rustc_save_analysis 0.0.0",
"rustc_trans 0.0.0",
+ "rustc_trans_utils 0.0.0",
"rustc_typeck 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"rustc_incremental 0.0.0",
"rustc_llvm 0.0.0",
"rustc_platform_intrinsics 0.0.0",
+ "rustc_trans_utils 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
+[[package]]
+name = "rustc_trans_utils"
+version = "0.0.0"
+dependencies = [
+ "rustc 0.0.0",
+ "syntax 0.0.0",
+ "syntax_pos 0.0.0",
+]
+
[[package]]
name = "rustc_tsan"
version = "0.0.0"
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
+"checksum ar 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b24e4eef8e3fa7e2ca75b157e6039cdf8d9d3a68213ddc19d0fd9d576b9717c9"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"
pub profiler: bool,
// llvm codegen options
+ pub llvm_enabled: bool,
pub llvm_assertions: bool,
pub llvm_optimize: bool,
pub llvm_release_debuginfo: bool,
#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Llvm {
+ enabled: Option<bool>,
ccache: Option<StringOrBool>,
ninja: Option<bool>,
assertions: Option<bool>,
impl Config {
pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
let mut config = Config::default();
+ config.llvm_enabled = true;
config.llvm_optimize = true;
config.use_jemalloc = true;
config.backtrace = true;
Some(StringOrBool::Bool(false)) | None => {}
}
set(&mut config.ninja, llvm.ninja);
+ set(&mut config.llvm_enabled, llvm.enabled);
set(&mut config.llvm_assertions, llvm.assertions);
set(&mut config.llvm_optimize, llvm.optimize);
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
# =============================================================================
[llvm]
+# Indicates whether rustc will support compilation with LLVM
+# note: rustc does not compile without LLVM at the moment
+#enabled = true
+
# Indicates whether the LLVM build is a Release or Debug build
#optimize = true
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
+ if self.config.llvm_enabled {
+ features.push_str(" llvm");
+ }
features
}
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
+
+ // If we're not compiling for LLVM bail out here.
+ if !build.config.llvm_enabled {
+ return;
+ }
+
// If we're using a custom LLVM bail out here, but we can only use a
// custom LLVM for the build triple.
if let Some(config) = build.config.target_config.get(&target) {
/// # Cloning references
///
/// Creating a new reference from an existing reference counted pointer is done using the
-/// `Clone` trait implemented for [`Arc<T>`][`arc`] and [`Weak<T>`][`weak`].
+/// `Clone` trait implemented for [`Arc<T>`][arc] and [`Weak<T>`][weak].
///
/// ```
/// use std::sync::Arc;
Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
- let (mut keys, mut vals) = self.node.into_slices_mut();
+ let (keys, vals) = self.node.into_slices_mut();
unsafe {
(keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx))
}
impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
pub fn kv_mut(&mut self) -> (&mut K, &mut V) {
unsafe {
- let (mut keys, mut vals) = self.node.reborrow_mut().into_slices_mut();
+ let (keys, vals) = self.node.reborrow_mut().into_slices_mut();
(keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx))
}
}
/// # Deref
///
/// `String`s implement [`Deref`]`<Target=str>`, and so inherit all of [`str`]'s
-/// methods. In addition, this means that you can pass a `String` to any
+/// methods. In addition, this means that you can pass a `String` to a
/// function which takes a [`&str`] by using an ampersand (`&`):
///
/// ```
///
/// This will create a [`&str`] from the `String` and pass it in. This
/// conversion is very inexpensive, and so generally, functions will accept
-/// [`&str`]s as arguments unless they need a `String` for some specific reason.
+/// [`&str`]s as arguments unless they need a `String` for some specific
+/// reason.
///
+/// In certain cases Rust doesn't have enough information to make this
+/// conversion, known as `Deref` coercion. In the following example a string
+/// slice `&'a str` implements the trait `TraitExample`, and the function
+/// `example_func` takes anything that implements the trait. In this case Rust
+/// would need to make two implicit conversions, which Rust doesn't have the
+/// means to do. For that reason, the following example will not compile.
+///
+/// ```compile_fail,E0277
+/// trait TraitExample {}
+///
+/// impl<'a> TraitExample for &'a str {}
+///
+/// fn example_func<A: TraitExample>(example_arg: A) {}
+///
+/// fn main() {
+/// let example_string = String::from("example_string");
+/// example_func(&example_string);
+/// }
+/// ```
+///
+/// There are two options that would work instead. The first would be to
+/// change the line `example_func(&example_string);` to
+/// `example_func(example_string.as_str());`, using the method `as_str()`
+/// to explicitly extract the string slice containing the string. The second
+/// way changes `example_func(&example_string);` to
+/// `example_func(&*example_string);`. In this case we are dereferencing a
+/// `String` to a `str`, then referencing the `str` back to `&str`. The
+/// second way is more idiomatic, however both work to do the conversion
+/// explicitly rather than relying on the implicit conversion.
///
/// # Representation
///
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
- fn into_iter(mut self) -> slice::IterMut<'a, T> {
+ fn into_iter(self) -> slice::IterMut<'a, T> {
self.iter_mut()
}
}
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
- fn into_iter(mut self) -> IterMut<'a, T> {
+ fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
type Owner = &'a mut T;
- unsafe fn finalize(mut self) -> &'a mut T {
+ unsafe fn finalize(self) -> &'a mut T {
let head = self.vec_deque.head;
self.vec_deque.head = self.vec_deque.wrap_add(head, 1);
&mut *(self.vec_deque.ptr().offset(head as isize))
impl<'a, T> InPlace<T> for PlaceFront<'a, T> {
type Owner = &'a mut T;
- unsafe fn finalize(mut self) -> &'a mut T {
+ unsafe fn finalize(self) -> &'a mut T {
self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1);
&mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize))
}
/// Aborts the execution of the process.
pub fn abort() -> !;
- /// Tells LLVM that this point in the code is not reachable,
- /// enabling further optimizations.
+ /// Tells LLVM that this point in the code is not reachable, enabling
+ /// further optimizations.
///
- /// NB: This is very different from the `unreachable!()` macro!
+ /// NB: This is very different from the `unreachable!()` macro: Unlike the
+ /// macro, which panics when it is executed, it is *undefined behavior* to
+ /// reach code marked with this function.
pub fn unreachable() -> !;
/// Informs the optimizer that a condition is always true.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[macro_export]
+// This stability attribute is totally useless.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(stage0)]
+macro_rules! __rust_unstable_column {
+ () => {
+ column!()
+ }
+}
+
/// Entry point of thread panic, for details, see std::macros
#[macro_export]
#[allow_internal_unstable]
);
($msg:expr) => ({
static _MSG_FILE_LINE_COL: (&'static str, &'static str, u32, u32) =
- ($msg, file!(), line!(), column!());
+ ($msg, file!(), line!(), __rust_unstable_column!());
$crate::panicking::panic(&_MSG_FILE_LINE_COL)
});
($fmt:expr, $($arg:tt)*) => ({
// insufficient, since the user may have
// `#[forbid(dead_code)]` and which cannot be overridden.
static _MSG_FILE_LINE_COL: (&'static str, u32, u32) =
- (file!(), line!(), column!());
+ (file!(), line!(), __rust_unstable_column!());
$crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_MSG_FILE_LINE_COL)
});
}
}
}
}
+
+/// Tells LLVM that this point in the code is not reachable, enabling further
+/// optimizations.
+///
+/// NB: This is very different from the `unreachable!()` macro: Unlike the
+/// macro, which panics when it is executed, it is *undefined behavior* to
+/// reach code marked with this function.
+#[inline]
+#[unstable(feature = "unreachable", issue = "43751")]
+pub unsafe fn unreachable() -> ! {
+ intrinsics::unreachable()
+}
where F : FnMut<A>
{
type Output = F::Output;
- extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
+ extern "rust-call" fn call_once(self, args: A) -> F::Output {
(*self).call_mut(args)
}
}
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
- fn into_iter(mut self) -> IterMut<'a, T> {
+ fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
- fn into_iter(mut self) -> IterMut<'a, T> {
+ fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
#[test]
fn test_chunks_mut_count() {
- let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
let c = v.chunks_mut(3);
assert_eq!(c.count(), 2);
- let mut v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
let c2 = v2.chunks_mut(2);
assert_eq!(c2.count(), 3);
- let mut v3: &mut [i32] = &mut [];
+ let v3: &mut [i32] = &mut [];
let c3 = v3.chunks_mut(2);
assert_eq!(c3.count(), 0);
}
#[test]
fn test_chunks_mut_nth() {
- let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
let mut c = v.chunks_mut(2);
assert_eq!(c.nth(1).unwrap()[1], 3);
assert_eq!(c.next().unwrap()[0], 4);
- let mut v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
let mut c2 = v2.chunks_mut(3);
assert_eq!(c2.nth(1).unwrap()[1], 4);
assert_eq!(c2.next(), None);
#[test]
fn get_mut_range() {
- let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..]));
assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..]));
assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..]));
[] IsAllocator(DefId),
[] IsPanicRuntime(DefId),
[] ExternCrate(DefId),
+ [] LintLevels,
);
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::Terminator<'tcx> {
+for mir::Terminator<'gcx> {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::TerminatorKind<'tcx> {
+for mir::TerminatorKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::AssertMessage<'tcx> {
+for mir::AssertMessage<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::StatementKind<'tcx> {
+for mir::StatementKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
- for mir::ValidationOperand<'tcx, T>
+ for mir::ValidationOperand<'gcx, T>
where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(extent) });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Lvalue<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Lvalue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx, B, V, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::Projection<'tcx, B, V, T>
+for mir::Projection<'gcx, B, V, T>
where B: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
}
impl<'a, 'gcx, 'tcx, V, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::ProjectionElem<'tcx, V, T>
+for mir::ProjectionElem<'gcx, V, T>
where V: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>,
T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Operand<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Operand<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
}
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Rvalue<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Rvalue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for mir::AggregateKind<'tcx> {
+for mir::AggregateKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Literal<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::Literal<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
use ty;
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for &'tcx ty::Slice<T>
+for &'gcx ty::Slice<T>
where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::subst::Kind<'tcx> {
+for ty::subst::Kind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
db.depth.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
}
+ ty::ReLateBound(db, ty::BrNamed(def_id, name)) => {
+ db.depth.hash_stable(hcx, hasher);
+ def_id.hash_stable(hcx, hasher);
+ name.hash_stable(hcx, hasher);
+ }
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => {
def_id.hash_stable(hcx, hasher);
index.hash_stable(hcx, hasher);
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::adjustment::AutoBorrow<'tcx> {
+for ty::adjustment::AutoBorrow<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
}
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::adjustment::Adjust<'tcx> {
+for ty::adjustment::Adjust<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::UpvarCapture<'tcx> {
+for ty::UpvarCapture<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx, T> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Binder<T>
- where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>> + ty::fold::TypeFoldable<'tcx>
+ where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
- hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher);
+ let ty::Binder(ref inner) = *self;
+ inner.hash_stable(hcx, hasher);
}
}
impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id });
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Predicate<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Predicate<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ::middle::const_val::ConstVal<'tcx> {
+for ::middle::const_val::ConstVal<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::TypeVariants<'tcx>
+for ty::TypeVariants<'gcx>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::ExistentialPredicate<'tcx>
+for ty::ExistentialPredicate<'gcx>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::TypeckTables<'tcx> {
+for ty::TypeckTables<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
ref cast_kinds,
- // FIXME(#41184): This is still ignored at the moment.
- lints: _,
ref used_trait_imports,
tainted_by_errors,
ref free_region_map,
substs
});
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::InstanceDef<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::InstanceDef<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
/// -------- this type is the same as a type argument in the other type, not highlighted
/// ```
fn highlight_outer(&self,
- mut value: &mut DiagnosticStyledString,
- mut other_value: &mut DiagnosticStyledString,
+ value: &mut DiagnosticStyledString,
+ other_value: &mut DiagnosticStyledString,
name: String,
sub: &ty::subst::Substs<'tcx>,
pos: usize,
//! previous lint state is pushed onto a stack and the ast is then recursed
//! upon. As the ast is traversed, this keeps track of the current lint level
//! for all lint attributes.
+
use self::TargetLint::*;
+use rustc_back::slice;
+use lint::{EarlyLintPassObject, LateLintPassObject};
+use lint::{Level, Lint, LintId, LintPass, LintBuffer};
+use lint::levels::{LintLevelSets, LintLevelsBuilder};
use middle::privacy::AccessLevels;
+use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
+use session::{config, early_error, Session};
use traits::Reveal;
use ty::{self, TyCtxt};
-use session::{config, early_error, Session};
-use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
-use lint::{EarlyLintPassObject, LateLintPassObject};
-use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
-use lint::builtin;
-use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
use util::nodemap::FxHashMap;
-use std::cmp;
use std::default::Default as StdDefault;
-use std::mem;
-use std::fmt;
use std::cell::{Ref, RefCell};
-use syntax::attr;
use syntax::ast;
-use syntax::symbol::Symbol;
use syntax_pos::{MultiSpan, Span};
-use errors::{self, Diagnostic, DiagnosticBuilder};
+use errors::DiagnosticBuilder;
use hir;
use hir::def_id::LOCAL_CRATE;
use hir::intravisit as hir_visit;
/// Lints indexed by name.
by_name: FxHashMap<String, TargetLint>,
- /// Current levels of each lint, and where they were set.
- levels: LintLevels,
-
/// Map of registered lint groups to what lints they expand to. The bool
/// is true if the lint group was added by a plugin.
lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool)>,
future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
}
-
-#[derive(Default)]
-struct LintLevels {
- /// Current levels of each lint, and where they were set.
- levels: FxHashMap<LintId, LevelSource>,
-
- /// Maximum level a lint can be
- lint_cap: Option<Level>,
-}
-
-
pub struct LintSession<'a, PassObject> {
/// Reference to the store of registered lints.
lints: Ref<'a, LintStore>,
- /// The current lint levels.
- levels: LintLevels,
-
- /// When recursing into an attributed node of the ast which modifies lint
- /// levels, this stack keeps track of the previous lint levels of whatever
- /// was modified.
- stack: Vec<(LintId, LevelSource)>,
-
/// Trait objects for each lint pass.
passes: Option<Vec<PassObject>>,
}
-/// When you call `add_lint` on the session, you wind up storing one
-/// of these, which records a "potential lint" at a particular point.
-#[derive(PartialEq, RustcEncodable, RustcDecodable)]
-pub struct EarlyLint {
- /// what lint is this? (e.g., `dead_code`)
- pub id: LintId,
-
- /// the main message
- pub diagnostic: Diagnostic,
-}
-
-impl fmt::Debug for EarlyLint {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("EarlyLint")
- .field("id", &self.id)
- .field("span", &self.diagnostic.span)
- .field("diagnostic", &self.diagnostic)
- .finish()
- }
-}
-
-pub trait IntoEarlyLint {
- fn into_early_lint(self, id: LintId) -> EarlyLint;
-}
-
-impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) {
- fn into_early_lint(self, id: LintId) -> EarlyLint {
- let (span, msg) = self;
- let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg);
- diagnostic.set_span(span);
- EarlyLint {
- id,
- diagnostic,
- }
- }
-}
-
-impl IntoEarlyLint for Diagnostic {
- fn into_early_lint(self, id: LintId) -> EarlyLint {
- EarlyLint {
- id,
- diagnostic: self,
- }
- }
+/// Lints that are buffered up early on in the `Session` before the
+/// `LintLevels` is calculated
+#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
+pub struct BufferedEarlyLint {
+ pub lint_id: LintId,
+ pub ast_id: ast::NodeId,
+ pub span: MultiSpan,
+ pub msg: String,
}
/// Extra information for a future incompatibility lint. See the call
Removed(String),
}
-enum FindLintError {
+pub enum FindLintError {
NotFound,
Removed,
}
+pub enum CheckLintNameResult<'a> {
+ Ok(&'a [LintId]),
+ // Lint doesn't exist
+ NoLint,
+ // The lint is either renamed or removed. This is the warning
+ // message.
+ Warning(String),
+}
+
impl LintStore {
pub fn new() -> LintStore {
LintStore {
early_passes: Some(vec![]),
late_passes: Some(vec![]),
by_name: FxHashMap(),
- levels: LintLevels::default(),
future_incompatible: FxHashMap(),
lint_groups: FxHashMap(),
}
(Some(sess), true) => sess.err(&msg[..]),
}
}
-
- self.levels.set(id, (lint.default_level, Default));
}
}
self.by_name.insert(name.into(), Removed(reason.into()));
}
- fn find_lint(&self, lint_name: &str) -> Result<LintId, FindLintError> {
+ pub fn find_lints(&self, lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
match self.by_name.get(lint_name) {
- Some(&Id(lint_id)) => Ok(lint_id),
+ Some(&Id(lint_id)) => Ok(vec![lint_id]),
Some(&Renamed(_, lint_id)) => {
- Ok(lint_id)
+ Ok(vec![lint_id])
},
Some(&Removed(_)) => {
Err(FindLintError::Removed)
},
- None => Err(FindLintError::NotFound)
- }
- }
-
- pub fn process_command_line(&mut self, sess: &Session) {
- for &(ref lint_name, level) in &sess.opts.lint_opts {
- check_lint_name_cmdline(sess, self,
- &lint_name[..], level);
-
- let lint_flag_val = Symbol::intern(&lint_name);
- match self.find_lint(&lint_name[..]) {
- Ok(lint_id) => self.levels.set(lint_id, (level, CommandLine(lint_flag_val))),
- Err(FindLintError::Removed) => { }
- Err(_) => {
- match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone()))
- .collect::<FxHashMap<&'static str,
- Vec<LintId>>>()
- .get(&lint_name[..]) {
- Some(v) => {
- for lint_id in v {
- self.levels.set(*lint_id, (level, CommandLine(lint_flag_val)));
- }
- }
- None => {
- // The lint or lint group doesn't exist.
- // This is an error, but it was handled
- // by check_lint_name_cmdline.
- }
- }
+ None => {
+ match self.lint_groups.get(lint_name) {
+ Some(v) => Ok(v.0.clone()),
+ None => Err(FindLintError::Removed)
}
}
}
-
- self.levels.set_lint_cap(sess.opts.lint_cap);
}
-}
-
-impl LintLevels {
- fn get_source(&self, lint: LintId) -> LevelSource {
- match self.levels.get(&lint) {
- Some(&s) => s,
- None => (Allow, Default),
- }
- }
+ // Checks the validity of lint names derived from the command line
+ pub fn check_lint_name_cmdline(&self,
+ sess: &Session,
+ lint_name: &str,
+ level: Level) {
+ let db = match self.check_lint_name(lint_name) {
+ CheckLintNameResult::Ok(_) => None,
+ CheckLintNameResult::Warning(ref msg) => {
+ Some(sess.struct_warn(msg))
+ },
+ CheckLintNameResult::NoLint => {
+ Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
+ }
+ };
- fn set(&mut self, lint: LintId, mut lvlsrc: LevelSource) {
- if let Some(cap) = self.lint_cap {
- lvlsrc.0 = cmp::min(lvlsrc.0, cap);
- }
- if lvlsrc.0 == Allow {
- self.levels.remove(&lint);
- } else {
- self.levels.insert(lint, lvlsrc);
+ if let Some(mut db) = db {
+ let msg = format!("requested on the command line with `{} {}`",
+ match level {
+ Level::Allow => "-A",
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ },
+ lint_name);
+ db.note(&msg);
+ db.emit();
}
}
- fn set_lint_cap(&mut self, lint_cap: Option<Level>) {
- self.lint_cap = lint_cap;
- if let Some(cap) = lint_cap {
- for (_, level) in &mut self.levels {
- level.0 = cmp::min(level.0, cap);
+ /// Checks the name of a lint for its existence, and whether it was
+ /// renamed or removed. Generates a DiagnosticBuilder containing a
+ /// warning for renamed and removed lints. This is over both lint
+ /// names from attributes and those passed on the command line. Since
+ /// it emits non-fatal warnings and there are *two* lint passes that
+ /// inspect attributes, this is only run from the late pass to avoid
+ /// printing duplicate warnings.
+ pub fn check_lint_name(&self, lint_name: &str) -> CheckLintNameResult {
+ match self.by_name.get(lint_name) {
+ Some(&Renamed(ref new_name, _)) => {
+ CheckLintNameResult::Warning(
+ format!("lint {} has been renamed to {}", lint_name, new_name)
+ )
+ },
+ Some(&Removed(ref reason)) => {
+ CheckLintNameResult::Warning(
+ format!("lint {} has been removed: {}", lint_name, reason)
+ )
+ },
+ None => {
+ match self.lint_groups.get(lint_name) {
+ None => CheckLintNameResult::NoLint,
+ Some(ids) => CheckLintNameResult::Ok(&ids.0),
+ }
}
+ Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::ref_slice(id)),
}
}
}
-
impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> {
/// Creates a new `LintSession`, by moving out the `LintStore`'s initial
/// lint levels and pass objects. These can be restored using the `restore`
/// method.
fn new(store: &'a RefCell<LintStore>) -> LintSession<'a, PassObject> {
let mut s = store.borrow_mut();
- let levels = mem::replace(&mut s.levels, LintLevels::default());
let passes = PassObject::take_passes(&mut *s);
drop(s);
LintSession {
lints: store.borrow(),
- stack: Vec::new(),
- levels,
passes,
}
}
fn restore(self, store: &RefCell<LintStore>) {
drop(self.lints);
let mut s = store.borrow_mut();
- s.levels = self.levels;
PassObject::restore_passes(&mut *s, self.passes);
}
-
- fn get_source(&self, lint_id: LintId) -> LevelSource {
- self.levels.get_source(lint_id)
- }
}
-
-
/// Context for lint checking after type checking.
pub struct LateContext<'a, 'tcx: 'a> {
/// Type context we're checking in.
/// The store of registered lints and the lint levels.
lint_sess: LintSession<'tcx, LateLintPassObject>,
+
+ last_ast_node_with_lint_attrs: ast::NodeId,
}
/// Context for lint checking of the AST, after expansion, before lowering to
/// The crate being checked.
pub krate: &'a ast::Crate,
+ builder: LintLevelsBuilder<'a>,
+
/// The store of registered lints and the lint levels.
lint_sess: LintSession<'a, EarlyLintPassObject>,
+
+ buffered: LintBuffer,
}
/// Convenience macro for calling a `LintPass` method on every pass in the context.
$cx.lint_sess_mut().passes = Some(passes);
}) }
-/// Parse the lint attributes into a vector, with `Err`s for malformed lint
-/// attributes. Writing this as an iterator is an enormous mess.
-// See also the hir version just below.
-pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec<Result<(ast::Name, Level, Span), Span>> {
- let mut out = vec![];
- for attr in attrs {
- let r = gather_attr(attr);
- out.extend(r.into_iter());
- }
- out
-}
-
-pub fn gather_attr(attr: &ast::Attribute) -> Vec<Result<(ast::Name, Level, Span), Span>> {
- let mut out = vec![];
-
- let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) {
- None => return out,
- Some(lvl) => lvl,
- };
-
- let meta = unwrap_or!(attr.meta(), return out);
- attr::mark_used(attr);
-
- let metas = if let Some(metas) = meta.meta_item_list() {
- metas
- } else {
- out.push(Err(meta.span));
- return out;
- };
-
- for li in metas {
- out.push(li.word().map_or(Err(li.span), |word| Ok((word.name(), level, word.span))));
- }
-
- out
-}
-
-/// Emit a lint as a warning or an error (or not at all)
-/// according to `level`.
-///
-/// This lives outside of `Context` so it can be used by checks
-/// in trans that run after the main lint pass is finished. Most
-/// lints elsewhere in the compiler should call
-/// `Session::add_lint()` instead.
-pub fn raw_emit_lint<S: Into<MultiSpan>>(sess: &Session,
- lints: &LintStore,
- lint: &'static Lint,
- lvlsrc: LevelSource,
- span: Option<S>,
- msg: &str) {
- raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
-}
-
-pub fn raw_struct_lint<'a, S>(sess: &'a Session,
- lints: &LintStore,
- lint: &'static Lint,
- lvlsrc: LevelSource,
- span: Option<S>,
- msg: &str)
- -> DiagnosticBuilder<'a>
- where S: Into<MultiSpan>
-{
- let (level, source) = lvlsrc;
- if level == Allow {
- return sess.diagnostic().struct_dummy();
- }
-
- let name = lint.name_lower();
-
- // Except for possible note details, forbid behaves like deny.
- let effective_level = if level == Forbid { Deny } else { level };
-
- let mut err = match (effective_level, span) {
- (Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
- (Warn, None) => sess.struct_warn(&msg[..]),
- (Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
- (Deny, None) => sess.struct_err(&msg[..]),
- _ => bug!("impossible level in raw_emit_lint"),
- };
-
- match source {
- Default => {
- sess.diag_note_once(&mut err, lint,
- &format!("#[{}({})] on by default", level.as_str(), name));
- },
- CommandLine(lint_flag_val) => {
- let flag = match level {
- Warn => "-W", Deny => "-D", Forbid => "-F",
- Allow => bug!("earlier conditional return should handle Allow case")
- };
- let hyphen_case_lint_name = name.replace("_", "-");
- if lint_flag_val.as_str() == name {
- sess.diag_note_once(&mut err, lint,
- &format!("requested on the command line with `{} {}`",
- flag, hyphen_case_lint_name));
- } else {
- let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
- sess.diag_note_once(&mut err, lint,
- &format!("`{} {}` implied by `{} {}`",
- flag, hyphen_case_lint_name, flag,
- hyphen_case_flag_val));
- }
- },
- Node(lint_attr_name, src) => {
- sess.diag_span_note_once(&mut err, lint, src, "lint level defined here");
- if lint_attr_name.as_str() != name {
- let level_str = level.as_str();
- sess.diag_note_once(&mut err, lint,
- &format!("#[{}({})] implied by #[{}({})]",
- level_str, name, level_str, lint_attr_name));
- }
- }
- }
-
- // Check for future incompatibility lints and issue a stronger warning.
- if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) {
- let explanation = format!("this was previously accepted by the compiler \
- but is being phased out; \
- it will become a hard error in a future release!");
- let citation = format!("for more information, see {}",
- future_incompatible.reference);
- err.warn(&explanation);
- err.note(&citation);
- }
-
- err
-}
-
-
pub trait LintPassObject: Sized {
fn take_passes(store: &mut LintStore) -> Option<Vec<Self>>;
fn restore_passes(store: &mut LintStore, passes: Option<Vec<Self>>);
fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
- /// Get the level of `lint` at the current position of the lint
- /// traversal.
- fn current_level(&self, lint: &'static Lint) -> Level {
- self.lint_sess().get_source(LintId::of(lint)).0
- }
-
- fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
- let ref levels = self.lint_sess().levels;
- levels.levels.get(&LintId::of(lint)).map(|ls| match ls {
- &(Warn, _) => {
- let lint_id = LintId::of(builtin::WARNINGS);
- let warn_src = levels.get_source(lint_id);
- if warn_src.0 != Warn {
- warn_src
- } else {
- *ls
- }
- }
- _ => *ls
- })
- }
-
fn lookup_and_emit<S: Into<MultiSpan>>(&self,
lint: &'static Lint,
span: Option<S>,
msg: &str) {
- let (level, src) = match self.level_src(lint) {
- None => return,
- Some(pair) => pair,
- };
-
- raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
+ self.lookup(lint, span, msg).emit();
}
fn lookup<S: Into<MultiSpan>>(&self,
lint: &'static Lint,
span: Option<S>,
msg: &str)
- -> DiagnosticBuilder {
- let (level, src) = match self.level_src(lint) {
- None => return self.sess().diagnostic().struct_dummy(),
- Some(pair) => pair,
- };
-
- raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg)
- }
+ -> DiagnosticBuilder;
/// Emit a lint at the appropriate level, for a particular span.
fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
self.lookup_and_emit(lint, Some(span), msg);
}
- fn early_lint(&self, early_lint: &EarlyLint) {
- let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span");
- let mut err = self.struct_span_lint(early_lint.id.lint,
- span,
- &early_lint.diagnostic.message());
- err.copy_details_not_message(&early_lint.diagnostic);
- err.emit();
- }
-
fn struct_span_lint<S: Into<MultiSpan>>(&self,
lint: &'static Lint,
span: S,
fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
note_span: Span, note: &str) {
let mut err = self.lookup(lint, Some(span), msg);
- if self.current_level(lint) != Level::Allow {
- if note_span == span {
- err.note(note);
- } else {
- err.span_note(note_span, note);
- }
+ if note_span == span {
+ err.note(note);
+ } else {
+ err.span_note(note_span, note);
}
err.emit();
}
msg: &str, help: &str) {
let mut err = self.lookup(lint, Some(span), msg);
self.span_lint(lint, span, msg);
- if self.current_level(lint) != Level::Allow {
- err.span_help(span, help);
- }
+ err.span_help(span, help);
err.emit();
}
/// current lint context, call the provided function, then reset the
/// lints in effect to their previous state.
fn with_lint_attrs<F>(&mut self,
+ id: ast::NodeId,
attrs: &'tcx [ast::Attribute],
f: F)
- where F: FnOnce(&mut Self),
- {
- // Parse all of the lint attributes, and then add them all to the
- // current dictionary of lint information. Along the way, keep a history
- // of what we changed so we can roll everything back after invoking the
- // specified closure
- let mut pushed = 0;
-
- for result in gather_attrs(attrs) {
- let (is_group, lint_level_spans) = match result {
- Err(span) => {
- span_err!(self.sess(), span, E0452,
- "malformed lint attribute");
- continue;
- }
- Ok((lint_name, level, span)) => {
- match self.lints().find_lint(&lint_name.as_str()) {
- Ok(lint_id) => (false, vec![(lint_id, level, span)]),
- Err(FindLintError::NotFound) => {
- match self.lints().lint_groups.get(&*lint_name.as_str()) {
- Some(&(ref v, _)) => (true,
- v.iter()
- .map(|lint_id: &LintId|
- (*lint_id, level, span))
- .collect()),
- None => {
- // The lint or lint group doesn't exist.
- // This is an error, but it was handled
- // by check_lint_name_attribute.
- continue;
- }
- }
- }
- Err(FindLintError::Removed) => continue,
- }
- }
- };
-
- let lint_attr_name = result.expect("lint attribute should be well-formed").0;
-
- for (lint_id, level, span) in lint_level_spans {
- let (now, now_source) = self.lint_sess().get_source(lint_id);
- if now == Forbid && level != Forbid {
- let forbidden_lint_name = match now_source {
- LintSource::Default => lint_id.to_string(),
- LintSource::Node(name, _) => name.to_string(),
- LintSource::CommandLine(name) => name.to_string(),
- };
- let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
- "{}({}) overruled by outer forbid({})",
- level.as_str(), lint_attr_name,
- forbidden_lint_name);
- diag_builder.span_label(span, "overruled by previous forbid");
- match now_source {
- LintSource::Default => &mut diag_builder,
- LintSource::Node(_, forbid_source_span) => {
- diag_builder.span_label(forbid_source_span,
- "`forbid` level set here")
- },
- LintSource::CommandLine(_) => {
- diag_builder.note("`forbid` lint level was set on command line")
- }
- }.emit();
- if is_group { // don't set a separate error for every lint in the group
- break;
- }
- } else if now != level {
- let cx = self.lint_sess_mut();
- cx.stack.push((lint_id, (now, now_source)));
- pushed += 1;
- cx.levels.set(lint_id, (level, Node(lint_attr_name, span)));
- }
- }
- }
-
- self.enter_attrs(attrs);
- f(self);
- self.exit_attrs(attrs);
-
- // rollback
- let cx = self.lint_sess_mut();
- for _ in 0..pushed {
- let (lint, lvlsrc) = cx.stack.pop().unwrap();
- cx.levels.set(lint, lvlsrc);
- }
- }
+ where F: FnOnce(&mut Self);
}
sess,
krate,
lint_sess: LintSession::new(&sess.lint_store),
+ builder: LintLevelSets::builder(sess),
+ buffered: sess.buffered_lints.borrow_mut().take().unwrap(),
+ }
+ }
+
+ fn check_id(&mut self, id: ast::NodeId) {
+ for early_lint in self.buffered.take(id) {
+ self.lookup_and_emit(early_lint.lint_id.lint,
+ Some(early_lint.span.clone()),
+ &early_lint.msg);
}
}
}
debug!("late context: exit_attrs({:?})", attrs);
run_lints!(self, exit_lint_attrs, late_passes, attrs);
}
+
+ fn lookup<S: Into<MultiSpan>>(&self,
+ lint: &'static Lint,
+ span: Option<S>,
+ msg: &str)
+ -> DiagnosticBuilder {
+ let id = self.last_ast_node_with_lint_attrs;
+ match span {
+ Some(s) => self.tcx.struct_span_lint_node(lint, id, s, msg),
+ None => self.tcx.struct_lint_node(lint, id, msg),
+ }
+ }
+
+ fn with_lint_attrs<F>(&mut self,
+ id: ast::NodeId,
+ attrs: &'tcx [ast::Attribute],
+ f: F)
+ where F: FnOnce(&mut Self)
+ {
+ let prev = self.last_ast_node_with_lint_attrs;
+ self.last_ast_node_with_lint_attrs = id;
+ self.enter_attrs(attrs);
+ f(self);
+ self.exit_attrs(attrs);
+ self.last_ast_node_with_lint_attrs = prev;
+ }
}
impl<'a> LintContext<'a> for EarlyContext<'a> {
debug!("early context: exit_attrs({:?})", attrs);
run_lints!(self, exit_lint_attrs, early_passes, attrs);
}
+
+ fn lookup<S: Into<MultiSpan>>(&self,
+ lint: &'static Lint,
+ span: Option<S>,
+ msg: &str)
+ -> DiagnosticBuilder {
+ self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
+ }
+
+ fn with_lint_attrs<F>(&mut self,
+ id: ast::NodeId,
+ attrs: &'a [ast::Attribute],
+ f: F)
+ where F: FnOnce(&mut Self)
+ {
+ let push = self.builder.push(attrs);
+ self.check_id(id);
+ self.enter_attrs(attrs);
+ f(self);
+ self.exit_attrs(attrs);
+ self.builder.pop(push);
+ }
}
impl<'a, 'tcx> LateContext<'a, 'tcx> {
hir_visit::NestedVisitorMap::All(&self.tcx.hir)
}
- // Output any lints that were previously added to the session.
- fn visit_id(&mut self, id: ast::NodeId) {
- let lints = self.sess().lints.borrow_mut().take(id);
- for early_lint in lints.iter().chain(self.tables.lints.get(id)) {
- debug!("LateContext::visit_id: id={:?} early_lint={:?}", id, early_lint);
- self.early_lint(early_lint);
- }
- }
-
fn visit_nested_body(&mut self, body: hir::BodyId) {
let old_tables = self.tables;
self.tables = self.tcx.body_tables(body);
}
fn visit_item(&mut self, it: &'tcx hir::Item) {
- self.with_lint_attrs(&it.attrs, |cx| {
+ self.with_lint_attrs(it.id, &it.attrs, |cx| {
cx.with_param_env(it.id, |cx| {
run_lints!(cx, check_item, late_passes, it);
hir_visit::walk_item(cx, it);
}
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
- self.with_lint_attrs(&it.attrs, |cx| {
+ self.with_lint_attrs(it.id, &it.attrs, |cx| {
cx.with_param_env(it.id, |cx| {
run_lints!(cx, check_foreign_item, late_passes, it);
hir_visit::walk_foreign_item(cx, it);
}
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
- self.with_lint_attrs(&e.attrs, |cx| {
+ self.with_lint_attrs(e.id, &e.attrs, |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
run_lints!(cx, check_expr_post, late_passes, e);
}
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
- self.with_lint_attrs(&s.attrs, |cx| {
+ self.with_lint_attrs(s.id, &s.attrs, |cx| {
run_lints!(cx, check_struct_field, late_passes, s);
hir_visit::walk_struct_field(cx, s);
})
v: &'tcx hir::Variant,
g: &'tcx hir::Generics,
item_id: ast::NodeId) {
- self.with_lint_attrs(&v.node.attrs, |cx| {
+ self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |cx| {
run_lints!(cx, check_variant, late_passes, v, g);
hir_visit::walk_variant(cx, v, g, item_id);
run_lints!(cx, check_variant_post, late_passes, v, g);
}
fn visit_local(&mut self, l: &'tcx hir::Local) {
- self.with_lint_attrs(&l.attrs, |cx| {
+ self.with_lint_attrs(l.id, &l.attrs, |cx| {
run_lints!(cx, check_local, late_passes, l);
hir_visit::walk_local(cx, l);
})
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
- self.with_lint_attrs(&trait_item.attrs, |cx| {
+ self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
cx.with_param_env(trait_item.id, |cx| {
run_lints!(cx, check_trait_item, late_passes, trait_item);
hir_visit::walk_trait_item(cx, trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
- self.with_lint_attrs(&impl_item.attrs, |cx| {
+ self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
cx.with_param_env(impl_item.id, |cx| {
run_lints!(cx, check_impl_item, late_passes, impl_item);
hir_visit::walk_impl_item(cx, impl_item);
}
fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
- check_lint_name_attribute(self, attr);
run_lints!(self, check_attribute, late_passes, attr);
}
}
impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
fn visit_item(&mut self, it: &'a ast::Item) {
- self.with_lint_attrs(&it.attrs, |cx| {
+ self.with_lint_attrs(it.id, &it.attrs, |cx| {
run_lints!(cx, check_item, early_passes, it);
ast_visit::walk_item(cx, it);
run_lints!(cx, check_item_post, early_passes, it);
}
fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
- self.with_lint_attrs(&it.attrs, |cx| {
+ self.with_lint_attrs(it.id, &it.attrs, |cx| {
run_lints!(cx, check_foreign_item, early_passes, it);
ast_visit::walk_foreign_item(cx, it);
run_lints!(cx, check_foreign_item_post, early_passes, it);
fn visit_pat(&mut self, p: &'a ast::Pat) {
run_lints!(self, check_pat, early_passes, p);
+ self.check_id(p.id);
ast_visit::walk_pat(self, p);
}
fn visit_expr(&mut self, e: &'a ast::Expr) {
- self.with_lint_attrs(&e.attrs, |cx| {
+ self.with_lint_attrs(e.id, &e.attrs, |cx| {
run_lints!(cx, check_expr, early_passes, e);
ast_visit::walk_expr(cx, e);
})
fn visit_stmt(&mut self, s: &'a ast::Stmt) {
run_lints!(self, check_stmt, early_passes, s);
+ self.check_id(s.id);
ast_visit::walk_stmt(self, s);
}
fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl,
span: Span, id: ast::NodeId) {
run_lints!(self, check_fn, early_passes, fk, decl, span, id);
+ self.check_id(id);
ast_visit::walk_fn(self, fk, decl, span);
run_lints!(self, check_fn_post, early_passes, fk, decl, span, id);
}
item_id: ast::NodeId,
_: Span) {
run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
+ self.check_id(s.id());
ast_visit::walk_struct_def(self, s);
run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
}
fn visit_struct_field(&mut self, s: &'a ast::StructField) {
- self.with_lint_attrs(&s.attrs, |cx| {
+ self.with_lint_attrs(s.id, &s.attrs, |cx| {
run_lints!(cx, check_struct_field, early_passes, s);
ast_visit::walk_struct_field(cx, s);
})
}
fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
- self.with_lint_attrs(&v.node.attrs, |cx| {
+ self.with_lint_attrs(item_id, &v.node.attrs, |cx| {
run_lints!(cx, check_variant, early_passes, v, g);
ast_visit::walk_variant(cx, v, g, item_id);
run_lints!(cx, check_variant_post, early_passes, v, g);
fn visit_ty(&mut self, t: &'a ast::Ty) {
run_lints!(self, check_ty, early_passes, t);
+ self.check_id(t.id);
ast_visit::walk_ty(self, t);
}
fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
run_lints!(self, check_mod, early_passes, m, s, n);
+ self.check_id(n);
ast_visit::walk_mod(self, m);
run_lints!(self, check_mod_post, early_passes, m, s, n);
}
fn visit_local(&mut self, l: &'a ast::Local) {
- self.with_lint_attrs(&l.attrs, |cx| {
+ self.with_lint_attrs(l.id, &l.attrs, |cx| {
run_lints!(cx, check_local, early_passes, l);
ast_visit::walk_local(cx, l);
})
fn visit_block(&mut self, b: &'a ast::Block) {
run_lints!(self, check_block, early_passes, b);
+ self.check_id(b.id);
ast_visit::walk_block(self, b);
run_lints!(self, check_block_post, early_passes, b);
}
}
fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
- self.with_lint_attrs(&trait_item.attrs, |cx| {
+ self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
run_lints!(cx, check_trait_item, early_passes, trait_item);
ast_visit::walk_trait_item(cx, trait_item);
run_lints!(cx, check_trait_item_post, early_passes, trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
- self.with_lint_attrs(&impl_item.attrs, |cx| {
+ self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
run_lints!(cx, check_impl_item, early_passes, impl_item);
ast_visit::walk_impl_item(cx, impl_item);
run_lints!(cx, check_impl_item_post, early_passes, impl_item);
fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
run_lints!(self, check_lifetime, early_passes, lt);
+ self.check_id(lt.id);
}
fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) {
fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
run_lints!(self, check_path, early_passes, p, id);
+ self.check_id(id);
ast_visit::walk_path(self, p);
}
fn visit_path_list_item(&mut self, prefix: &'a ast::Path, item: &'a ast::PathListItem) {
run_lints!(self, check_path_list_item, early_passes, item);
+ self.check_id(item.node.id);
ast_visit::walk_path_list_item(self, prefix, item);
}
}
fn visit_mac_def(&mut self, _mac: &'a ast::MacroDef, id: ast::NodeId) {
- let lints = self.sess.lints.borrow_mut().take(id);
- for early_lint in lints {
- self.early_lint(&early_lint);
- }
- }
-}
-
-enum CheckLintNameResult {
- Ok,
- // Lint doesn't exist
- NoLint,
- // The lint is either renamed or removed. This is the warning
- // message.
- Warning(String),
-}
-
-/// Checks the name of a lint for its existence, and whether it was
-/// renamed or removed. Generates a DiagnosticBuilder containing a
-/// warning for renamed and removed lints. This is over both lint
-/// names from attributes and those passed on the command line. Since
-/// it emits non-fatal warnings and there are *two* lint passes that
-/// inspect attributes, this is only run from the late pass to avoid
-/// printing duplicate warnings.
-fn check_lint_name(lint_cx: &LintStore,
- lint_name: &str) -> CheckLintNameResult {
- match lint_cx.by_name.get(lint_name) {
- Some(&Renamed(ref new_name, _)) => {
- CheckLintNameResult::Warning(
- format!("lint {} has been renamed to {}", lint_name, new_name)
- )
- },
- Some(&Removed(ref reason)) => {
- CheckLintNameResult::Warning(
- format!("lint {} has been removed: {}", lint_name, reason)
- )
- },
- None => {
- match lint_cx.lint_groups.get(lint_name) {
- None => {
- CheckLintNameResult::NoLint
- }
- Some(_) => {
- /* lint group exists */
- CheckLintNameResult::Ok
- }
- }
- }
- Some(_) => {
- /* lint exists */
- CheckLintNameResult::Ok
- }
- }
-}
-
-// Checks the validity of lint names derived from attributes
-fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) {
- for result in gather_attr(attr) {
- match result {
- Err(_) => {
- // Malformed lint attr. Reported by with_lint_attrs
- continue;
- }
- Ok((lint_name, _, span)) => {
- match check_lint_name(&cx.lint_sess.lints, &lint_name.as_str()) {
- CheckLintNameResult::Ok => (),
- CheckLintNameResult::Warning(ref msg) => {
- cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS,
- span, msg);
- }
- CheckLintNameResult::NoLint => {
- cx.span_lint(builtin::UNKNOWN_LINTS, span,
- &format!("unknown lint: `{}`",
- lint_name));
- }
- }
- }
- }
- }
-}
-
-// Checks the validity of lint names derived from the command line
-fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
- lint_name: &str, level: Level) {
- let db = match check_lint_name(lint_cx, lint_name) {
- CheckLintNameResult::Ok => None,
- CheckLintNameResult::Warning(ref msg) => {
- Some(sess.struct_warn(msg))
- },
- CheckLintNameResult::NoLint => {
- Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
- }
- };
-
- if let Some(mut db) = db {
- let msg = format!("requested on the command line with `{} {}`",
- match level {
- Level::Allow => "-A",
- Level::Warn => "-W",
- Level::Deny => "-D",
- Level::Forbid => "-F",
- },
- lint_name);
- db.note(&msg);
- db.emit();
+ self.check_id(id);
}
}
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
access_levels,
lint_sess: LintSession::new(&tcx.sess.lint_store),
+ last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID,
};
// Visit the whole crate.
- cx.with_lint_attrs(&krate.attrs, |cx| {
+ cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
// since the root module isn't visited as an item (because it isn't an
// item), warn for it here.
run_lints!(cx, check_crate, late_passes, krate);
run_lints!(cx, check_crate_post, late_passes, krate);
});
- // If we missed any lints added to the session, then there's a bug somewhere
- // in the iteration code.
- if let Some((id, v)) = tcx.sess.lints.borrow().get_any() {
- for early_lint in v {
- span_bug!(early_lint.diagnostic.span.clone(),
- "unprocessed lint {:?} at {}",
- early_lint, tcx.hir.node_to_string(*id));
- }
- }
-
// Put the lint store levels and passes back in the session.
cx.lint_sess.restore(&tcx.sess.lint_store);
}
let mut cx = EarlyContext::new(sess, krate);
// Visit the whole crate.
- cx.with_lint_attrs(&krate.attrs, |cx| {
- // Lints may be assigned to the whole crate.
- let lints = cx.sess.lints.borrow_mut().take(ast::CRATE_NODE_ID);
- for early_lint in lints {
- cx.early_lint(&early_lint);
- }
-
+ cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
// since the root module isn't visited as an item (because it isn't an
// item), warn for it here.
run_lints!(cx, check_crate, early_passes, krate);
// Put the lint store levels and passes back in the session.
cx.lint_sess.restore(&sess.lint_store);
- // If we missed any lints added to the session, then there's a bug somewhere
- // in the iteration code.
- for (_, v) in sess.lints.borrow().get_any() {
- for early_lint in v {
- span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint);
+ // Emit all buffered lints from early on in the session now that we've
+ // calculated the lint levels for all AST nodes.
+ for (_id, lints) in cx.buffered.map {
+ for early_lint in lints {
+ span_bug!(early_lint.span, "failed to process bufferd lint here");
}
}
}
fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> {
let s = d.read_str()?;
ty::tls::with(|tcx| {
- match tcx.sess.lint_store.borrow().find_lint(&s) {
- Ok(id) => Ok(id),
+ match tcx.sess.lint_store.borrow().find_lints(&s) {
+ Ok(ids) => {
+ if ids.len() != 0 {
+ panic!("invalid lint-id `{}`", s);
+ }
+ Ok(ids[0])
+ }
Err(_) => panic!("invalid lint-id `{}`", s),
}
})
--- /dev/null
+// Copyright 2017 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.
+
+use std::cmp;
+
+use errors::DiagnosticBuilder;
+use hir::HirId;
+use lint::builtin;
+use lint::context::CheckLintNameResult;
+use lint::{self, Lint, LintId, Level, LintSource};
+use session::Session;
+use syntax::ast;
+use syntax::attr;
+use syntax::codemap::MultiSpan;
+use syntax::symbol::Symbol;
+use util::nodemap::FxHashMap;
+
+pub struct LintLevelSets {
+ list: Vec<LintSet>,
+ lint_cap: Level,
+}
+
+enum LintSet {
+ CommandLine {
+ // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
+ // flag.
+ specs: FxHashMap<LintId, (Level, LintSource)>,
+ },
+
+ Node {
+ specs: FxHashMap<LintId, (Level, LintSource)>,
+ parent: u32,
+ },
+}
+
+impl LintLevelSets {
+ pub fn new(sess: &Session) -> LintLevelSets {
+ let mut me = LintLevelSets {
+ list: Vec::new(),
+ lint_cap: Level::Forbid,
+ };
+ me.process_command_line(sess);
+ return me
+ }
+
+ pub fn builder(sess: &Session) -> LintLevelsBuilder {
+ LintLevelsBuilder::new(sess, LintLevelSets::new(sess))
+ }
+
+ fn process_command_line(&mut self, sess: &Session) {
+ let store = sess.lint_store.borrow();
+ let mut specs = FxHashMap();
+ self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
+
+ for &(ref lint_name, level) in &sess.opts.lint_opts {
+ store.check_lint_name_cmdline(sess, &lint_name, level);
+
+ // If the cap is less than this specified level, e.g. if we've got
+ // `--cap-lints allow` but we've also got `-D foo` then we ignore
+ // this specification as the lint cap will set it to allow anyway.
+ let level = cmp::min(level, self.lint_cap);
+
+ let lint_flag_val = Symbol::intern(lint_name);
+ let ids = match store.find_lints(&lint_name) {
+ Ok(ids) => ids,
+ Err(_) => continue, // errors handled in check_lint_name_cmdline above
+ };
+ for id in ids {
+ let src = LintSource::CommandLine(lint_flag_val);
+ specs.insert(id, (level, src));
+ }
+ }
+
+ self.list.push(LintSet::CommandLine {
+ specs: specs,
+ });
+ }
+
+ fn get_lint_level(&self, lint: &'static Lint, idx: u32)
+ -> (Level, LintSource)
+ {
+ let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx);
+
+ // If `level` is none then we actually assume the default level for this
+ // lint.
+ let mut level = level.unwrap_or(lint.default_level);
+
+ // If we're about to issue a warning, check at the last minute for any
+ // directives against the warnings "lint". If, for example, there's an
+ // `allow(warnings)` in scope then we want to respect that instead.
+ if level == Level::Warn {
+ let (warnings_level, warnings_src) =
+ self.get_lint_id_level(LintId::of(lint::builtin::WARNINGS), idx);
+ if let Some(configured_warning_level) = warnings_level {
+ if configured_warning_level != Level::Warn {
+ level = configured_warning_level;
+ src = warnings_src;
+ }
+ }
+ }
+
+ // Ensure that we never exceed the `--cap-lints` argument.
+ level = cmp::min(level, self.lint_cap);
+
+ return (level, src)
+ }
+
+ fn get_lint_id_level(&self, id: LintId, mut idx: u32)
+ -> (Option<Level>, LintSource)
+ {
+ loop {
+ match self.list[idx as usize] {
+ LintSet::CommandLine { ref specs } => {
+ if let Some(&(level, src)) = specs.get(&id) {
+ return (Some(level), src)
+ }
+ return (None, LintSource::Default)
+ }
+ LintSet::Node { ref specs, parent } => {
+ if let Some(&(level, src)) = specs.get(&id) {
+ return (Some(level), src)
+ }
+ idx = parent;
+ }
+ }
+ }
+ }
+}
+
+pub struct LintLevelsBuilder<'a> {
+ sess: &'a Session,
+ sets: LintLevelSets,
+ id_to_set: FxHashMap<HirId, u32>,
+ cur: u32,
+ warn_about_weird_lints: bool,
+}
+
+pub struct BuilderPush {
+ prev: u32,
+}
+
+impl<'a> LintLevelsBuilder<'a> {
+ pub fn new(sess: &'a Session, sets: LintLevelSets) -> LintLevelsBuilder<'a> {
+ assert_eq!(sets.list.len(), 1);
+ LintLevelsBuilder {
+ sess,
+ sets,
+ cur: 0,
+ id_to_set: FxHashMap(),
+ warn_about_weird_lints: sess.buffered_lints.borrow().is_some(),
+ }
+ }
+
+ /// Pushes a list of AST lint attributes onto this context.
+ ///
+ /// This function will return a `BuilderPush` object which should be be
+ /// passed to `pop` when this scope for the attributes provided is exited.
+ ///
+ /// This function will perform a number of tasks:
+ ///
+ /// * It'll validate all lint-related attributes in `attrs`
+ /// * It'll mark all lint-related attriutes as used
+ /// * Lint levels will be updated based on the attributes provided
+ /// * Lint attributes are validated, e.g. a #[forbid] can't be switched to
+ /// #[allow]
+ ///
+ /// Don't forget to call `pop`!
+ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
+ let mut specs = FxHashMap();
+ let store = self.sess.lint_store.borrow();
+ let sess = self.sess;
+ let bad_attr = |span| {
+ span_err!(sess, span, E0452,
+ "malformed lint attribute");
+ };
+ for attr in attrs {
+ let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) {
+ None => continue,
+ Some(lvl) => lvl,
+ };
+
+ let meta = unwrap_or!(attr.meta(), continue);
+ attr::mark_used(attr);
+
+ let metas = if let Some(metas) = meta.meta_item_list() {
+ metas
+ } else {
+ bad_attr(meta.span);
+ continue
+ };
+
+ for li in metas {
+ let word = match li.word() {
+ Some(word) => word,
+ None => {
+ bad_attr(li.span);
+ continue
+ }
+ };
+ let name = word.name();
+ match store.check_lint_name(&name.as_str()) {
+ CheckLintNameResult::Ok(ids) => {
+ let src = LintSource::Node(name, li.span);
+ for id in ids {
+ specs.insert(*id, (level, src));
+ }
+ }
+ CheckLintNameResult::Warning(ref msg) => {
+ if self.warn_about_weird_lints {
+ self.struct_lint(builtin::RENAMED_AND_REMOVED_LINTS,
+ Some(li.span.into()),
+ msg)
+ .emit();
+ }
+ }
+ CheckLintNameResult::NoLint => {
+ if self.warn_about_weird_lints {
+ self.struct_lint(builtin::UNKNOWN_LINTS,
+ Some(li.span.into()),
+ &format!("unknown lint: `{}`", name))
+ .emit();
+ }
+ }
+ }
+ }
+ }
+
+ for (id, &(level, ref src)) in specs.iter() {
+ if level == Level::Forbid {
+ continue
+ }
+ let forbid_src = match self.sets.get_lint_id_level(*id, self.cur) {
+ (Some(Level::Forbid), src) => src,
+ _ => continue,
+ };
+ let forbidden_lint_name = match forbid_src {
+ LintSource::Default => id.to_string(),
+ LintSource::Node(name, _) => name.to_string(),
+ LintSource::CommandLine(name) => name.to_string(),
+ };
+ let (lint_attr_name, lint_attr_span) = match *src {
+ LintSource::Node(name, span) => (name, span),
+ _ => continue,
+ };
+ let mut diag_builder = struct_span_err!(self.sess,
+ lint_attr_span,
+ E0453,
+ "{}({}) overruled by outer forbid({})",
+ level.as_str(),
+ lint_attr_name,
+ forbidden_lint_name);
+ diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
+ match forbid_src {
+ LintSource::Default => &mut diag_builder,
+ LintSource::Node(_, forbid_source_span) => {
+ diag_builder.span_label(forbid_source_span,
+ "`forbid` level set here")
+ },
+ LintSource::CommandLine(_) => {
+ diag_builder.note("`forbid` lint level was set on command line")
+ }
+ }.emit();
+ // don't set a separate error for every lint in the group
+ break
+ }
+
+ let prev = self.cur;
+ if specs.len() > 0 {
+ self.cur = self.sets.list.len() as u32;
+ self.sets.list.push(LintSet::Node {
+ specs: specs,
+ parent: prev,
+ });
+ }
+
+ BuilderPush {
+ prev: prev,
+ }
+ }
+
+ /// Called after `push` when the scope of a set of attributes are exited.
+ pub fn pop(&mut self, push: BuilderPush) {
+ self.cur = push.prev;
+ }
+
+ /// Used to emit a lint-related diagnostic based on the current state of
+ /// this lint context.
+ pub fn struct_lint(&self,
+ lint: &'static Lint,
+ span: Option<MultiSpan>,
+ msg: &str)
+ -> DiagnosticBuilder<'a>
+ {
+ let (level, src) = self.sets.get_lint_level(lint, self.cur);
+ lint::struct_lint_level(self.sess, lint, level, src, span, msg)
+ }
+
+ /// Registers the ID provided with the current set of lints stored in
+ /// this context.
+ pub fn register_id(&mut self, id: HirId) {
+ self.id_to_set.insert(id, self.cur);
+ }
+
+ pub fn build(self) -> LintLevelSets {
+ self.sets
+ }
+
+ pub fn build_map(self) -> LintLevelMap {
+ LintLevelMap {
+ sets: self.sets,
+ id_to_set: self.id_to_set,
+ }
+ }
+}
+
+pub struct LintLevelMap {
+ sets: LintLevelSets,
+ id_to_set: FxHashMap<HirId, u32>,
+}
+
+impl LintLevelMap {
+ /// If the `id` was previously registered with `register_id` when building
+ /// this `LintLevelMap` this returns the corresponding lint level and source
+ /// of the lint level for the lint provided.
+ ///
+ /// If the `id` was not previously registered, returns `None`. If `None` is
+ /// returned then the parent of `id` should be acquired and this function
+ /// should be called again.
+ pub fn level_and_source(&self, lint: &'static Lint, id: HirId)
+ -> Option<(Level, LintSource)>
+ {
+ self.id_to_set.get(&id).map(|idx| {
+ self.sets.get_lint_level(lint, *idx)
+ })
+ }
+}
pub use self::Level::*;
pub use self::LintSource::*;
+use std::rc::Rc;
+
+use errors::DiagnosticBuilder;
+use hir::def_id::{CrateNum, LOCAL_CRATE};
+use hir::intravisit::{self, FnKind};
use hir;
-use hir::intravisit::FnKind;
-use std::hash;
+use session::Session;
use std::ascii::AsciiExt;
-use syntax_pos::Span;
-use syntax::visit as ast_visit;
+use std::hash;
use syntax::ast;
+use syntax::codemap::MultiSpan;
use syntax::symbol::Symbol;
+use syntax::visit as ast_visit;
+use syntax_pos::Span;
+use ty::TyCtxt;
+use ty::maps::Providers;
+use util::nodemap::NodeMap;
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
- raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
- raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint};
-
-pub use lint::table::LintTable;
+ check_crate, check_ast_crate,
+ FutureIncompatibleInfo, BufferedEarlyLint};
/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
pub mod builtin;
mod context;
-mod table;
+mod levels;
+
+pub use self::levels::{LintLevelSets, LintLevelMap};
+
+pub struct LintBuffer {
+ map: NodeMap<Vec<BufferedEarlyLint>>,
+}
+
+impl LintBuffer {
+ pub fn new() -> LintBuffer {
+ LintBuffer { map: NodeMap() }
+ }
+
+ pub fn add_lint(&mut self,
+ lint: &'static Lint,
+ id: ast::NodeId,
+ sp: MultiSpan,
+ msg: &str) {
+ let early_lint = BufferedEarlyLint {
+ lint_id: LintId::of(lint),
+ ast_id: id,
+ span: sp,
+ msg: msg.to_string(),
+ };
+ let arr = self.map.entry(id).or_insert(Vec::new());
+ if !arr.contains(&early_lint) {
+ arr.push(early_lint);
+ }
+ }
+
+ pub fn take(&mut self, id: ast::NodeId) -> Vec<BufferedEarlyLint> {
+ self.map.remove(&id).unwrap_or(Vec::new())
+ }
+
+ pub fn get_any(&self) -> Option<&[BufferedEarlyLint]> {
+ let key = self.map.keys().next().map(|k| *k);
+ key.map(|k| &self.map[&k][..])
+ }
+}
+
+pub fn struct_lint_level<'a>(sess: &'a Session,
+ lint: &'static Lint,
+ level: Level,
+ src: LintSource,
+ span: Option<MultiSpan>,
+ msg: &str)
+ -> DiagnosticBuilder<'a>
+{
+ let mut err = match (level, span) {
+ (Level::Allow, _) => return sess.diagnostic().struct_dummy(),
+ (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
+ (Level::Warn, None) => sess.struct_warn(msg),
+ (Level::Deny, Some(span)) |
+ (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
+ (Level::Deny, None) |
+ (Level::Forbid, None) => sess.struct_err(msg),
+ };
+
+ let name = lint.name_lower();
+ match src {
+ LintSource::Default => {
+ sess.diag_note_once(
+ &mut err,
+ lint,
+ &format!("#[{}({})] on by default", level.as_str(), name));
+ }
+ LintSource::CommandLine(lint_flag_val) => {
+ let flag = match level {
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ Level::Allow => panic!(),
+ };
+ let hyphen_case_lint_name = name.replace("_", "-");
+ if lint_flag_val.as_str() == name {
+ sess.diag_note_once(
+ &mut err,
+ lint,
+ &format!("requested on the command line with `{} {}`",
+ flag, hyphen_case_lint_name));
+ } else {
+ let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
+ sess.diag_note_once(
+ &mut err,
+ lint,
+ &format!("`{} {}` implied by `{} {}`",
+ flag, hyphen_case_lint_name, flag,
+ hyphen_case_flag_val));
+ }
+ }
+ LintSource::Node(lint_attr_name, src) => {
+ sess.diag_span_note_once(&mut err, lint, src, "lint level defined here");
+ if lint_attr_name.as_str() != name {
+ let level_str = level.as_str();
+ sess.diag_note_once(&mut err, lint,
+ &format!("#[{}({})] implied by #[{}({})]",
+ level_str, name, level_str, lint_attr_name));
+ }
+ }
+ }
+
+ // Check for future incompatibility lints and issue a stronger warning.
+ let lints = sess.lint_store.borrow();
+ if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) {
+ let explanation = format!("this was previously accepted by the compiler \
+ but is being phased out; \
+ it will become a hard error in a future release!");
+ let citation = format!("for more information, see {}",
+ future_incompatible.reference);
+ err.warn(&explanation);
+ err.note(&citation);
+ }
+
+ return err
+}
+
+fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
+ -> Rc<LintLevelMap>
+{
+ assert_eq!(cnum, LOCAL_CRATE);
+ let mut builder = LintLevelMapBuilder {
+ levels: LintLevelSets::builder(tcx.sess),
+ tcx: tcx,
+ };
+ let krate = tcx.hir.krate();
+
+ builder.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |builder| {
+ intravisit::walk_crate(builder, krate);
+ });
+
+ Rc::new(builder.levels.build_map())
+}
+
+struct LintLevelMapBuilder<'a, 'tcx: 'a> {
+ levels: levels::LintLevelsBuilder<'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+impl<'a, 'tcx> LintLevelMapBuilder<'a, 'tcx> {
+ fn with_lint_attrs<F>(&mut self,
+ id: ast::NodeId,
+ attrs: &[ast::Attribute],
+ f: F)
+ where F: FnOnce(&mut Self)
+ {
+ let push = self.levels.push(attrs);
+ self.levels.register_id(self.tcx.hir.definitions().node_to_hir_id(id));
+ f(self);
+ self.levels.pop(push);
+ }
+}
+
+impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+ intravisit::NestedVisitorMap::All(&self.tcx.hir)
+ }
+
+ fn visit_item(&mut self, it: &'tcx hir::Item) {
+ self.with_lint_attrs(it.id, &it.attrs, |builder| {
+ intravisit::walk_item(builder, it);
+ });
+ }
+
+ fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
+ self.with_lint_attrs(it.id, &it.attrs, |builder| {
+ intravisit::walk_foreign_item(builder, it);
+ })
+ }
+
+ fn visit_expr(&mut self, e: &'tcx hir::Expr) {
+ self.with_lint_attrs(e.id, &e.attrs, |builder| {
+ intravisit::walk_expr(builder, e);
+ })
+ }
+
+ fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
+ self.with_lint_attrs(s.id, &s.attrs, |builder| {
+ intravisit::walk_struct_field(builder, s);
+ })
+ }
+
+ fn visit_variant(&mut self,
+ v: &'tcx hir::Variant,
+ g: &'tcx hir::Generics,
+ item_id: ast::NodeId) {
+ self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |builder| {
+ intravisit::walk_variant(builder, v, g, item_id);
+ })
+ }
+
+ fn visit_local(&mut self, l: &'tcx hir::Local) {
+ self.with_lint_attrs(l.id, &l.attrs, |builder| {
+ intravisit::walk_local(builder, l);
+ })
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.with_lint_attrs(trait_item.id, &trait_item.attrs, |builder| {
+ intravisit::walk_trait_item(builder, trait_item);
+ });
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+ self.with_lint_attrs(impl_item.id, &impl_item.attrs, |builder| {
+ intravisit::walk_impl_item(builder, impl_item);
+ });
+ }
+}
+
+pub fn provide(providers: &mut Providers) {
+ providers.lint_levels = lint_levels;
+}
+++ /dev/null
-// 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.
-
-use syntax::ast;
-use syntax_pos::MultiSpan;
-use util::nodemap::NodeMap;
-
-use super::{Lint, LintId, EarlyLint, IntoEarlyLint};
-
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct LintTable {
- map: NodeMap<Vec<EarlyLint>>
-}
-
-impl LintTable {
- pub fn new() -> Self {
- LintTable { map: NodeMap() }
- }
-
- pub fn add_lint<S: Into<MultiSpan>>(&mut self,
- lint: &'static Lint,
- id: ast::NodeId,
- sp: S,
- msg: String)
- {
- self.add_lint_diagnostic(lint, id, (sp, &msg[..]))
- }
-
- pub fn add_lint_diagnostic<M>(&mut self,
- lint: &'static Lint,
- id: ast::NodeId,
- msg: M)
- where M: IntoEarlyLint,
- {
- let lint_id = LintId::of(lint);
- let early_lint = msg.into_early_lint(lint_id);
- let arr = self.map.entry(id).or_insert(vec![]);
- if !arr.contains(&early_lint) {
- arr.push(early_lint);
- }
- }
-
- pub fn get(&self, id: ast::NodeId) -> &[EarlyLint] {
- self.map.get(&id).map(|v| &v[..]).unwrap_or(&[])
- }
-
- pub fn take(&mut self, id: ast::NodeId) -> Vec<EarlyLint> {
- self.map.remove(&id).unwrap_or(vec![])
- }
-
- pub fn transfer(&mut self, into: &mut LintTable) {
- into.map.extend(self.map.drain());
- }
-
- /// Returns the first (id, lint) pair that is non-empty. Used to
- /// implement a sanity check in lints that all node-ids are
- /// visited.
- pub fn get_any(&self) -> Option<(&ast::NodeId, &Vec<EarlyLint>)> {
- self.map.iter()
- .filter(|&(_, v)| !v.is_empty())
- .next()
- }
-}
-
#[macro_export]
macro_rules! impl_stable_hash_for {
(enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
- impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $enum_name {
+ impl<'a, 'tcx, 'lcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx, 'lcx>> for $enum_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
- __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx, 'lcx>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
use $enum_name::*;
::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
}
};
(struct $struct_name:path { $($field:ident),* }) => {
- impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $struct_name {
+ impl<'a, 'tcx, 'lcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx, 'lcx>> for $struct_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
- __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx, 'lcx>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name {
$(ref $field),*
}
};
(tuple_struct $struct_name:path { $($field:ident),* }) => {
- impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $struct_name {
+ impl<'a, 'tcx, 'lcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx, 'lcx>> for $struct_name {
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
- __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx, 'lcx>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name (
$(ref $field),*
macro_rules! impl_stable_hash_for_spanned {
($T:path) => (
- impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ::syntax::codemap::Spanned<$T>
+ impl<'a, 'tcx, 'lcx> HashStable<StableHashingContext<'a, 'tcx, 'lcx>> for ::syntax::codemap::Spanned<$T>
{
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
+ hcx: &mut StableHashingContext<'a, 'tcx, 'lcx>,
hasher: &mut StableHasher<W>) {
self.node.hash_stable(hcx, hasher);
self.span.hash_stable(hcx, hasher);
use hir::intravisit::{self, Visitor, NestedVisitorMap};
use hir::itemlikevisit::ItemLikeVisitor;
-use middle::privacy;
-use ty::{self, TyCtxt};
use hir::def::Def;
use hir::def_id::{DefId, LOCAL_CRATE};
use lint;
+use middle::privacy;
+use ty::{self, TyCtxt};
use util::nodemap::FxHashSet;
use syntax::{ast, codemap};
}
}
-fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
+fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
+ id: ast::NodeId,
+ attrs: &[ast::Attribute]) -> bool {
if attr::contains_name(attrs, "lang") {
return true;
}
return true;
}
- let dead_code = lint::builtin::DEAD_CODE.name_lower();
- for attr in lint::gather_attrs(attrs) {
- match attr {
- Ok((name, lint::Allow, _)) if name == &*dead_code => return true,
- _ => (),
- }
- }
- false
+ tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
}
// This visitor seeds items that
// or
// 2) We are not sure to be live or not
// * Implementation of a trait method
-struct LifeSeeder<'k> {
+struct LifeSeeder<'k, 'tcx: 'k> {
worklist: Vec<ast::NodeId>,
krate: &'k hir::Crate,
+ tcx: TyCtxt<'k, 'tcx, 'tcx>,
}
-impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
+impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
- let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs);
+ let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx,
+ item.id,
+ &item.attrs);
if allow_dead_code {
self.worklist.push(item.id);
}
match trait_item.node {
hir::TraitItemKind::Const(_, Some(_)) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
- if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
+ if has_allow_dead_code_or_lang_attr(self.tcx,
+ trait_item.id,
+ &trait_item.attrs) {
self.worklist.push(trait_item.id);
}
}
for impl_item_ref in impl_item_refs {
let impl_item = self.krate.impl_item(impl_item_ref.id);
if opt_trait.is_some() ||
- has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
+ has_allow_dead_code_or_lang_attr(self.tcx,
+ impl_item.id,
+ &impl_item.attrs) {
self.worklist.push(impl_item_ref.id.node_id);
}
}
let mut life_seeder = LifeSeeder {
worklist,
krate,
+ tcx,
};
krate.visit_all_item_likes(&mut life_seeder);
!field.is_positional()
&& !self.symbol_is_live(field.id, None)
&& !is_marker_field
- && !has_allow_dead_code_or_lang_attr(&field.attrs)
+ && !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs)
}
fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool {
!self.symbol_is_live(variant.data.id(), None)
- && !has_allow_dead_code_or_lang_attr(&variant.attrs)
+ && !has_allow_dead_code_or_lang_attr(self.tcx,
+ variant.data.id(),
+ &variant.attrs)
}
fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool {
!self.symbol_is_live(fi.id, None)
- && !has_allow_dead_code_or_lang_attr(&fi.attrs)
+ && !has_allow_dead_code_or_lang_attr(self.tcx, fi.id, &fi.attrs)
}
// id := node id of an item's definition.
node_type: &str) {
if !name.as_str().starts_with("_") {
self.tcx
- .sess
- .add_lint(lint::builtin::DEAD_CODE,
- id,
- span,
- format!("{} is never used: `{}`", node_type, name));
+ .lint_node(lint::builtin::DEAD_CODE,
+ id,
+ span,
+ &format!("{} is never used: `{}`", node_type, name));
}
}
}
match self.unsafe_context.root {
SafeContext => {
if is_lint {
- self.tcx.sess.add_lint(lint::builtin::SAFE_EXTERN_STATICS,
- node_id,
- span,
- format!("{} requires unsafe function or \
- block (error E0133)", description));
+ self.tcx.lint_node(lint::builtin::SAFE_EXTERN_STATICS,
+ node_id,
+ span,
+ &format!("{} requires unsafe function or \
+ block (error E0133)", description));
} else {
// Report an error.
struct_span_err!(
};
if is_assigned {
- self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_VARIABLES, id, sp,
- format!("variable `{}` is assigned to, but never used",
- name));
+ self.ir.tcx.lint_node(lint::builtin::UNUSED_VARIABLES, id, sp,
+ &format!("variable `{}` is assigned to, but never used",
+ name));
} else if name != "self" {
- self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_VARIABLES, id, sp,
- format!("unused variable: `{}`", name));
+ self.ir.tcx.lint_node(lint::builtin::UNUSED_VARIABLES, id, sp,
+ &format!("unused variable: `{}`", name));
}
}
true
fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) {
if let Some(name) = self.should_warn(var) {
if is_argument {
- self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
- format!("value passed to `{}` is never read", name));
+ self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
+ &format!("value passed to `{}` is never read", name));
} else {
- self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
- format!("value assigned to `{}` is never read", name));
+ self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
+ &format!("value assigned to `{}` is never read", name));
}
}
}
format!("use of deprecated item")
};
- self.sess.add_lint(lint::builtin::DEPRECATED, id, span, msg);
+ self.lint_node(lint::builtin::DEPRECATED, id, span, &msg);
};
// Deprecated attributes apply in-crate and cross-crate.
for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features {
let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str())
.expect("unexpectedly couldn't find version feature was stabilized");
- sess.add_lint(lint::builtin::STABLE_FEATURES,
+ tcx.lint_node(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
- format_stable_since_msg(version));
+ &format_stable_since_msg(version));
}
let index = tcx.stability.borrow();
match remaining_lib_features.remove(used_lib_feature) {
Some(span) => {
if let &attr::StabilityLevel::Stable { since: ref version } = level {
- sess.add_lint(lint::builtin::STABLE_FEATURES,
+ tcx.lint_node(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
- format_stable_since_msg(&version.as_str()));
+ &format_stable_since_msg(&version.as_str()));
}
}
None => ( /* used but undeclared, handled during the previous ast visit */ )
}
for &span in remaining_lib_features.values() {
- sess.add_lint(lint::builtin::UNUSED_FEATURES,
+ tcx.lint_node(lint::builtin::UNUSED_FEATURES,
ast::CRATE_NODE_ID,
span,
- "unused or unknown feature".to_string());
+ "unused or unknown feature");
}
}
make_mir_visitor!(Visitor,);
make_mir_visitor!(MutVisitor,mut);
+#[derive(Copy, Clone, Debug)]
pub enum Lookup {
Loc(Location),
Src(SourceInfo),
// if the value stored here has been affected by path remapping.
pub working_dir: (String, bool),
pub lint_store: RefCell<lint::LintStore>,
- pub lints: RefCell<lint::LintTable>,
+ pub buffered_lints: RefCell<Option<lint::LintBuffer>>,
/// Set of (LintId, Option<Span>, message) tuples tracking lint
/// (sub)diagnostics that have been set once, but should not be set again,
/// in order to avoid redundantly verbose output (Issue #24690).
self.diagnostic().unimpl(msg)
}
- pub fn add_lint<S: Into<MultiSpan>>(&self,
- lint: &'static lint::Lint,
- id: ast::NodeId,
- sp: S,
- msg: String)
- {
- self.lints.borrow_mut().add_lint(lint, id, sp, msg);
- }
-
- pub fn add_lint_diagnostic<M>(&self,
- lint: &'static lint::Lint,
- id: ast::NodeId,
- msg: M)
- where M: lint::IntoEarlyLint,
- {
- self.lints.borrow_mut().add_lint_diagnostic(lint, id, msg);
+ pub fn buffer_lint<S: Into<MultiSpan>>(&self,
+ lint: &'static lint::Lint,
+ id: ast::NodeId,
+ sp: S,
+ msg: &str) {
+ match *self.buffered_lints.borrow_mut() {
+ Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg),
+ None => bug!("can't buffer lints after HIR lowering"),
+ }
}
pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId {
local_crate_source_file,
working_dir,
lint_store: RefCell::new(lint::LintStore::new()),
- lints: RefCell::new(lint::LintTable::new()),
+ buffered_lints: RefCell::new(Some(lint::LintBuffer::new())),
one_time_diagnostics: RefCell::new(FxHashSet()),
plugin_llvm_passes: RefCell::new(Vec::new()),
plugin_attributes: RefCell::new(Vec::new()),
// weird effect -- the diagnostic is reported as a lint, and
// the builder which is returned is marked as canceled.
- let mut err =
- struct_span_err!(self.tcx.sess,
- error_span,
- E0276,
- "impl has stricter requirements than trait");
+ let msg = "impl has stricter requirements than trait";
+ let mut err = match lint_id {
+ Some(node_id) => {
+ self.tcx.struct_span_lint_node(EXTRA_REQUIREMENT_IN_IMPL,
+ node_id,
+ error_span,
+ msg)
+ }
+ None => {
+ struct_span_err!(self.tcx.sess,
+ error_span,
+ E0276,
+ "{}", msg)
+ }
+ };
if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) {
let span = self.tcx.sess.codemap().def_span(trait_item_span);
error_span,
format!("impl has extra requirement {}", requirement));
- if let Some(node_id) = lint_id {
- self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL,
- node_id,
- (*err).clone());
- err.cancel();
- }
-
err
}
{
debug!("fully_normalize(value={:?})", value);
- let mut selcx = &mut SelectionContext::new(infcx);
+ let selcx = &mut SelectionContext::new(infcx);
// FIXME (@jroesch) ISSUE 26721
// I'm not sure if this is a bug or not, needs further investigation.
// It appears that by reusing the fulfillment_cx here we incur more
never_obligation.predicate = never_obligation.predicate.map_bound(|mut trait_pred| {
// Swap out () with ! so we can check if the trait is impld for !
{
- let mut trait_ref = &mut trait_pred.trait_ref;
+ let trait_ref = &mut trait_pred.trait_ref;
let unit_substs = trait_ref.substs;
let mut never_substs = Vec::with_capacity(unit_substs.len());
never_substs.push(From::from(tcx.types.never));
}
if raise_warning {
- tcx.sess.add_lint(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
- obligation.cause.body_id,
- obligation.cause.span,
- format!("code relies on type inference rules which are likely \
- to change"));
+ tcx.lint_node(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
+ obligation.cause.body_id,
+ obligation.cause.span,
+ &format!("code relies on type inference rules which are likely \
+ to change"));
}
}
Ok(ret)
//! type context book-keeping
use dep_graph::DepGraph;
+use errors::DiagnosticBuilder;
use session::Session;
-use lint;
use middle;
use hir::TraitMap;
use hir::def::{Def, ExportMap};
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use hir::map as hir_map;
use hir::map::DefPathHash;
+use lint::{self, Lint};
use middle::free_region::FreeRegionMap;
use middle::lang_items;
use middle::resolve_lifetime;
use syntax::abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
+use syntax::codemap::MultiSpan;
use syntax::symbol::{Symbol, keywords};
use syntax_pos::Span;
/// *from* expression of the cast, not the cast itself.
pub cast_kinds: NodeMap<ty::cast::CastKind>,
- /// Lints for the body of this fn generated by typeck.
- pub lints: lint::LintTable,
-
/// Set of trait imports actually used in the method resolution.
/// This is used for warning unused imports.
pub used_trait_imports: DefIdSet,
liberated_fn_sigs: NodeMap(),
fru_field_types: NodeMap(),
cast_kinds: NodeMap(),
- lints: lint::LintTable::new(),
used_trait_imports: DefIdSet(),
tainted_by_errors: false,
free_region_map: FreeRegionMap::new(),
{
self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
}
+
+ pub fn lint_node<S: Into<MultiSpan>>(self,
+ lint: &'static Lint,
+ id: NodeId,
+ span: S,
+ msg: &str) {
+ self.struct_span_lint_node(lint, id, span.into(), msg).emit()
+ }
+
+ pub fn lint_level_at_node(self, lint: &'static Lint, mut id: NodeId)
+ -> (lint::Level, lint::LintSource)
+ {
+ // Right now we insert a `with_ignore` node in the dep graph here to
+ // ignore the fact that `lint_levels` below depends on the entire crate.
+ // For now this'll prevent false positives of recompiling too much when
+ // anything changes.
+ //
+ // Once red/green incremental compilation lands we should be able to
+ // remove this because while the crate changes often the lint level map
+ // will change rarely.
+ self.dep_graph.with_ignore(|| {
+ let sets = self.lint_levels(LOCAL_CRATE);
+ loop {
+ let hir_id = self.hir.definitions().node_to_hir_id(id);
+ if let Some(pair) = sets.level_and_source(lint, hir_id) {
+ return pair
+ }
+ let next = self.hir.get_parent_node(id);
+ if next == id {
+ bug!("lint traversal reached the root of the crate");
+ }
+ id = next;
+ }
+ })
+ }
+
+ pub fn struct_span_lint_node<S: Into<MultiSpan>>(self,
+ lint: &'static Lint,
+ id: NodeId,
+ span: S,
+ msg: &str)
+ -> DiagnosticBuilder<'tcx>
+ {
+ let (level, src) = self.lint_level_at_node(lint, id);
+ lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
+ }
+
+ pub fn struct_lint_node(self, lint: &'static Lint, id: NodeId, msg: &str)
+ -> DiagnosticBuilder<'tcx>
+ {
+ let (level, src) = self.lint_level_at_node(lint, id);
+ lint::struct_lint_level(self.sess, lint, level, src, None, msg)
+ }
}
pub trait InternAs<T: ?Sized, R> {
match self.sty {
TyAdt(def, substs) => {
{
- let mut substs_set = visited.entry(def.did).or_insert(FxHashSet::default());
+ let substs_set = visited.entry(def.did).or_insert(FxHashSet::default());
if !substs_set.insert(substs) {
// We are already calculating the inhabitedness of this type.
// The type must contain a reference to itself. Break the
}
}
let ret = def.uninhabited_from(visited, tcx, substs);
- let mut substs_set = visited.get_mut(&def.did).unwrap();
+ let substs_set = visited.get_mut(&def.did).unwrap();
substs_set.remove(substs);
ret
},
let tcx = cx.tcx();
let ptr_field_type = |pointee: Ty<'tcx>| {
+ assert!(i < 2);
let slice = |element: Ty<'tcx>| {
- assert!(i < 2);
if i == 0 {
tcx.mk_mut_ptr(element)
} else {
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use hir::def::Def;
use hir;
+use lint;
use middle::const_val;
use middle::cstore::{ExternCrate, LinkagePreference};
use middle::privacy::AccessLevels;
}
}
+impl<'tcx> QueryDescription for queries::lint_levels<'tcx> {
+ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+ format!("computing the lint levels for items in this crate")
+ }
+}
+
macro_rules! define_maps {
(<$tcx:tt>
$($(#[$attr:meta])*
[] is_panic_runtime: IsPanicRuntime(DefId) -> bool,
[] extern_crate: ExternCrate(DefId) -> Rc<Option<ExternCrate>>,
+
+ [] lint_levels: lint_levels(CrateNum) -> Rc<lint::LintLevelMap>,
}
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
fn layout_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
DepConstructor::Layout
}
+
+fn lint_levels<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+ DepConstructor::LintLevels
+}
TypeVariants::TyFnPtr(..) |
TypeVariants::TyDynamic(..) |
TypeVariants::TyClosure(..) |
+ TypeVariants::TyInfer(..) |
TypeVariants::TyProjection(..) => false,
_ => true,
}
}
}
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::TyS<'tcx> {
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::TyS<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
hasher: &mut StableHasher<W>) {
let mut hasher = StableHasher::new();
let mut hcx = StableHashingContext::new(self);
+ // We want the type_id be independent of the types free regions, so we
+ // erase them. The erase_regions() call will also anonymize bound
+ // regions, which is desirable too.
+ let ty = self.erase_regions(&ty);
+
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
ty.hash_stable(hcx, &mut hasher);
fn arg_ty(&self,
ty: &AllocatorTy,
args: &mut Vec<Arg>,
- mut ident: &mut FnMut() -> Ident) -> P<Expr> {
+ ident: &mut FnMut() -> Ident) -> P<Expr> {
match *ty {
AllocatorTy::Layout => {
let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
fn ret_ty(&self,
ty: &AllocatorTy,
args: &mut Vec<Arg>,
- mut ident: &mut FnMut() -> Ident,
+ ident: &mut FnMut() -> Ident,
expr: P<Expr>) -> (P<Ty>, P<Expr>)
{
match *ty {
//! For mutable loans of content whose mutability derives
//! from a local variable, mark the mutability decl as necessary.
- match loan_path.kind {
- LpVar(local_id) |
- LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
- self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
- }
- LpDowncast(ref base, _) |
- LpExtend(ref base, mc::McInherited, _) |
- LpExtend(ref base, mc::McDeclared, _) => {
- self.mark_loan_path_as_mutated(&base);
- }
- LpExtend(_, mc::McImmutable, _) => {
- // Nothing to do.
+ let mut wrapped_path = Some(loan_path);
+ let mut through_borrow = false;
+
+ while let Some(current_path) = wrapped_path {
+ wrapped_path = match current_path.kind {
+ LpVar(local_id) => {
+ if !through_borrow {
+ self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+ }
+ None
+ }
+ LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
+ self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+ None
+ }
+ LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) |
+ LpExtend(ref base, mc::McDeclared, LpDeref(pointer_kind)) => {
+ if pointer_kind != mc::Unique {
+ through_borrow = true;
+ }
+ Some(base)
+ }
+ LpDowncast(ref base, _) |
+ LpExtend(ref base, mc::McInherited, _) |
+ LpExtend(ref base, mc::McDeclared, _) => {
+ Some(base)
+ }
+ LpExtend(_, mc::McImmutable, _) => {
+ // Nothing to do.
+ None
+ }
}
}
+
}
pub fn compute_gen_scope(&self,
let body_id = tcx.hir.body_owned_by(owner_id);
let tables = tcx.typeck_tables_of(owner_def_id);
let region_maps = tcx.region_maps(owner_def_id);
- let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
+ let bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
let body = bccx.tcx.hir.body(body_id);
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::lint;
-use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
+use rustc_errors::DiagnosticBuilder;
use rustc::hir::def::*;
use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
match arm_index {
// The arm with the user-specified pattern.
0 => {
- let mut diagnostic = Diagnostic::new(Level::Warning,
- "unreachable pattern");
- diagnostic.set_span(pat.span);
- cx.tcx.sess.add_lint_diagnostic(
+ cx.tcx.lint_node(
lint::builtin::UNREACHABLE_PATTERNS,
- hir_pat.id, diagnostic);
+ hir_pat.id, pat.span,
+ "unreachable pattern");
},
// The arm with the wildcard pattern.
1 => {
hir::MatchSource::ForLoopDesugar |
hir::MatchSource::Normal => {
- let mut diagnostic = Diagnostic::new(Level::Warning,
- "unreachable pattern");
- diagnostic.set_span(pat.span);
+ let mut err = cx.tcx.struct_span_lint_node(
+ lint::builtin::UNREACHABLE_PATTERNS,
+ hir_pat.id,
+ pat.span,
+ "unreachable pattern",
+ );
// if we had a catchall pattern, hint at that
if let Some(catchall) = catchall {
- diagnostic.span_label(pat.span, "this is an unreachable pattern");
- diagnostic.span_note(catchall, "this pattern matches any value");
+ err.span_label(pat.span, "this is an unreachable pattern");
+ err.span_note(catchall, "this pattern matches any value");
}
- cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS,
- hir_pat.id, diagnostic);
+ err.emit();
},
// Unreachable patterns in try expressions occur when one of the arms
let start = source_array_vec.len();
let tail = self.tail_start;
{
- let mut arr = &mut source_array_vec.values as &mut [ManuallyDrop<_>];
+ let arr = &mut source_array_vec.values as &mut [ManuallyDrop<_>];
let src = arr.as_ptr().offset(tail as isize);
let dst = arr.as_mut_ptr().offset(start as isize);
ptr::copy(src, dst, self.tail_len);
pub fn add(&mut self, source: usize, target: usize) -> bool {
let (start, _) = self.range(source);
let (word, mask) = word_mask(target);
- let mut vector = &mut self.vector[..];
+ let vector = &mut self.vector[..];
let v1 = vector[start + word];
let v2 = v1 | mask;
vector[start + word] = v2;
type IntoIter = slice::IterMut<'a, T>;
#[inline]
- fn into_iter(mut self) -> slice::IterMut<'a, T> {
+ fn into_iter(self) -> slice::IterMut<'a, T> {
self.raw.iter_mut()
}
}
arena = { path = "../libarena" }
graphviz = { path = "../libgraphviz" }
log = { version = "0.3", features = ["release_max_level_info"] }
+owning_ref = "0.3.3"
env_logger = { version = "0.4", default-features = false }
rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" }
rustc_privacy = { path = "../librustc_privacy" }
rustc_resolve = { path = "../librustc_resolve" }
rustc_save_analysis = { path = "../librustc_save_analysis" }
-rustc_trans = { path = "../librustc_trans" }
+rustc_trans = { path = "../librustc_trans", optional = true }
+rustc_trans_utils = { path = "../librustc_trans_utils" }
rustc_typeck = { path = "../librustc_typeck" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
+
+ar = "0.3.0"
+
+[features]
+llvm = ["rustc_trans"]
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
use rustc::lint;
-use rustc::middle::{self, dependency_format, stability, reachable};
+use rustc::middle::{self, stability, reachable};
+#[cfg(feature="llvm")]
+use rustc::middle::dependency_format;
use rustc::middle::privacy::AccessLevels;
use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc_resolve::{MakeGlobMap, Resolver};
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::{self, CStore};
+#[cfg(feature="llvm")]
use rustc_trans::back::{link, write};
+#[cfg(feature="llvm")]
use rustc_trans as trans;
use rustc_typeck as typeck;
use rustc_privacy;
output: &Option<PathBuf>,
addl_plugins: Option<Vec<String>>,
control: &CompileController) -> CompileResult {
+ #[cfg(feature="llvm")]
+ use rustc_trans::back::write::OngoingCrateTranslation;
+ #[cfg(not(feature="llvm"))]
+ type OngoingCrateTranslation = ();
+
macro_rules! controller_entry_point {
($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
let state = &mut $make_state;
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans) = {
- let krate = match phase_1_parse_input(sess, input) {
+ let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
+ let krate = match phase_1_parse_input(control, sess, input) {
Ok(krate) => krate,
Err(mut parse_error) => {
parse_error.emit();
};
let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
- let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input);
+ let crate_name =
+ ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
phase_2_configure_and_expand(
sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
println!("Pre-trans");
tcx.print_debug_stats();
}
+
+ #[cfg(feature="llvm")]
let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
&outputs);
}
}
+ #[cfg(not(feature="llvm"))]
+ {
+ let _ = incremental_hashes_map;
+ sess.err(&format!("LLVM is not supported by this rustc"));
+ sess.abort_if_errors();
+ unreachable!();
+ }
+
+ #[cfg(feature="llvm")]
Ok((outputs, trans))
})??
};
- if sess.opts.debugging_opts.print_type_sizes {
- sess.code_stats.borrow().print_type_sizes();
+ #[cfg(not(feature="llvm"))]
+ {
+ let _ = outputs;
+ let _ = trans;
+ unreachable!();
}
- let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
+ #[cfg(feature="llvm")]
+ {
+ if sess.opts.debugging_opts.print_type_sizes {
+ sess.code_stats.borrow().print_type_sizes();
+ }
- controller_entry_point!(after_llvm,
- sess,
- CompileState::state_after_llvm(input, sess, outdir, output, &trans),
- phase5_result);
- phase5_result?;
+ let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
- phase_6_link_output(sess, &trans, &outputs);
+ controller_entry_point!(after_llvm,
+ sess,
+ CompileState::state_after_llvm(input, sess, outdir, output, &trans),
+ phase5_result);
+ phase5_result?;
- // Now that we won't touch anything in the incremental compilation directory
- // any more, we can finalize it (which involves renaming it)
- rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+ phase_6_link_output(sess, &trans, &outputs);
- if sess.opts.debugging_opts.perf_stats {
- sess.print_perf_stats();
- }
+ // Now that we won't touch anything in the incremental compilation directory
+ // any more, we can finalize it (which involves renaming it)
+ rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
- controller_entry_point!(compilation_done,
- sess,
- CompileState::state_when_compilation_done(input, sess, outdir, output),
- Ok(()));
+ if sess.opts.debugging_opts.perf_stats {
+ sess.print_perf_stats();
+ }
+
+ controller_entry_point!(
+ compilation_done,
+ sess,
+ CompileState::state_when_compilation_done(input, sess, outdir, output),
+ Ok(())
+ );
- Ok(())
+ Ok(())
+ }
}
fn keep_hygiene_data(sess: &Session) -> bool {
pub after_llvm: PhaseController<'a>,
pub compilation_done: PhaseController<'a>,
+ // FIXME we probably want to group the below options together and offer a
+ // better API, rather than this ad-hoc approach.
pub make_glob_map: MakeGlobMap,
// Whether the compiler should keep the ast beyond parsing.
pub keep_ast: bool,
+ // -Zcontinue-parse-after-error
+ pub continue_parse_after_error: bool,
}
impl<'a> CompileController<'a> {
compilation_done: PhaseController::basic(),
make_glob_map: MakeGlobMap::No,
keep_ast: false,
+ continue_parse_after_error: false,
}
}
}
pub resolutions: Option<&'a Resolutions>,
pub analysis: Option<&'a ty::CrateAnalysis>,
pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
+ #[cfg(feature="llvm")]
pub trans: Option<&'a trans::CrateTranslation>,
}
resolutions: None,
analysis: None,
tcx: None,
+ #[cfg(feature="llvm")]
trans: None,
}
}
}
}
-
+ #[cfg(feature="llvm")]
fn state_after_llvm(input: &'a Input,
session: &'tcx Session,
out_dir: &'a Option<PathBuf>,
}
}
+ #[cfg(feature="llvm")]
fn state_when_compilation_done(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>)
- -> Self {
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>)
+ -> Self {
CompileState {
out_file: out_file.as_ref().map(|s| &**s),
..CompileState::empty(input, session, out_dir)
}
}
-pub fn phase_1_parse_input<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
- let continue_after_error = sess.opts.debugging_opts.continue_parse_after_error;
- sess.diagnostic().set_continue_after_error(continue_after_error);
+pub fn phase_1_parse_input<'a>(control: &CompileController,
+ sess: &'a Session,
+ input: &Input)
+ -> PResult<'a, ast::Crate> {
+ sess.diagnostic().set_continue_after_error(control.continue_parse_after_error);
let krate = time(sess.time_passes(), "parsing", || {
match *input {
super::describe_lints(&sess.lint_store.borrow(), true);
return Err(CompileIncomplete::Stopped);
}
- sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?;
// Currently, we ignore the name resolution data structures for the purposes of dependency
// tracking. Instead we will run name resolution and include its output in the hash of each
missing_fragment_specifiers.sort();
for span in missing_fragment_specifiers {
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
- let msg = "missing fragment specifier".to_string();
- sess.add_lint(lint, ast::CRATE_NODE_ID, span, msg);
+ let msg = "missing fragment specifier";
+ sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg);
}
if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
ecx.parse_sess.span_diagnostic.abort_if_errors();
"checking for inline asm in case the target doesn't support it",
|| no_asm::check_crate(sess, &krate));
- time(time_passes,
- "early lint checks",
- || lint::check_ast_crate(sess, &krate));
-
time(time_passes,
"AST validation",
|| ast_validation::check_crate(sess, &krate));
})
})?;
+ time(time_passes,
+ "early lint checks",
+ || lint::check_ast_crate(sess, &krate));
+
// Lower ast -> hir.
let hir_forest = time(time_passes, "lowering ast -> hir", || {
let hir_crate = lower_crate(sess, &krate, &mut resolver);
mir::provide(&mut local_providers);
reachable::provide(&mut local_providers);
rustc_privacy::provide(&mut local_providers);
+ #[cfg(feature="llvm")]
trans::provide(&mut local_providers);
typeck::provide(&mut local_providers);
ty::provide(&mut local_providers);
rustc_const_eval::provide(&mut local_providers);
middle::region::provide(&mut local_providers);
cstore::provide_local(&mut local_providers);
+ lint::provide(&mut local_providers);
let mut extern_providers = ty::maps::Providers::default();
cstore::provide(&mut extern_providers);
+ #[cfg(feature="llvm")]
trans::provide(&mut extern_providers);
ty::provide_extern(&mut extern_providers);
traits::provide_extern(&mut extern_providers);
// These next passes must be executed together
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+ // AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
+ // an AllCallEdges pass right before it.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AllCallEdges);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
// No lifetime analysis based on borrowing can be done from here on out.
- // AddValidation needs to run after ElaborateDrops and before EraseRegions.
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
-
// From here on out, regions are gone.
passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
TyCtxt::create_and_enter(sess,
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
+#[cfg(feature="llvm")]
pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis: ty::CrateAnalysis,
incremental_hashes_map: IncrementalHashesMap,
/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
+#[cfg(feature="llvm")]
pub fn phase_5_run_llvm_passes(sess: &Session,
trans: write::OngoingCrateTranslation)
-> (CompileResult, trans::CrateTranslation) {
/// Run the linker on any artifacts that resulted from the LLVM run.
/// This should produce either a finished executable or library.
+#[cfg(feature="llvm")]
pub fn phase_6_link_output(sess: &Session,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) {
match *output_type {
OutputType::Exe => {
for output in sess.crate_types.borrow().iter() {
- let p = link::filename_for_input(sess, *output, crate_name, outputs);
+ let p = ::rustc_trans_utils::link::filename_for_input(
+ sess,
+ *output,
+ crate_name,
+ outputs
+ );
out_filenames.push(p);
}
}
}
Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
Some(_) => {
- session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
- ast::CRATE_NODE_ID,
- a.span,
- "invalid `crate_type` value".to_string());
+ session.buffer_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
+ ast::CRATE_NODE_ID,
+ a.span,
+ "invalid `crate_type` value");
None
}
_ => {
if base.is_empty() {
base.extend(attr_types);
if base.is_empty() {
- base.push(link::default_output_for_target(session));
+ base.push(::rustc_trans_utils::link::default_output_for_target(session));
}
base.sort();
base.dedup();
base.into_iter()
.filter(|crate_type| {
- let res = !link::invalid_output_for_target(session, *crate_type);
+ let res = !::rustc_trans_utils::link::invalid_output_for_target(session, *crate_type);
if !res {
session.warn(&format!("dropping unsupported crate type `{}` for target `{}`",
#![feature(rustc_diagnostic_macros)]
#![feature(set_stdio)]
+#[cfg(not(feature="llvm"))]
+extern crate ar;
+
extern crate arena;
extern crate getopts;
extern crate graphviz;
extern crate env_logger;
+#[cfg(not(feature="llvm"))]
+extern crate owning_ref;
extern crate libc;
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_mir;
extern crate rustc_resolve;
extern crate rustc_save_analysis;
+#[cfg(feature="llvm")]
extern crate rustc_trans;
+extern crate rustc_trans_utils;
extern crate rustc_typeck;
extern crate serialize;
#[macro_use]
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc_trans::back::link;
+#[cfg(feature="llvm")]
use rustc_trans::back::write::{RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::{early_error, early_warn};
use rustc::lint::Lint;
use rustc::lint;
+#[cfg(not(feature="llvm"))]
+use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait;
use rustc_metadata::locator;
use rustc_metadata::cstore::CStore;
use rustc::util::common::{time, ErrorReported};
+#[cfg(not(feature="llvm"))]
+use rustc_back::target::Target;
use serialize::json::ToJson;
use std::io::{self, Read, Write};
use std::iter::repeat;
use std::path::PathBuf;
+#[cfg(not(feature="llvm"))]
+use std::path::Path;
use std::process::{self, Command, Stdio};
use std::rc::Rc;
use std::str;
use syntax::parse::{self, PResult};
use syntax_pos::{DUMMY_SP, MultiSpan};
+#[cfg(not(feature="llvm"))]
+use owning_ref::{OwningRef, ErasedBoxRef};
+
#[cfg(test)]
pub mod test;
pub mod driver;
pub mod pretty;
+#[cfg(feature="llvm")]
pub mod target_features;
mod derive_registrar;
0
}
+#[cfg(not(feature="llvm"))]
+pub struct NoLLvmMetadataLoader;
+
+#[cfg(not(feature="llvm"))]
+pub use NoLLvmMetadataLoader as MetadataLoader;
+#[cfg(feature="llvm")]
+pub use rustc_trans::LlvmMetadataLoader as MetadataLoader;
+
+#[cfg(not(feature="llvm"))]
+impl MetadataLoaderTrait for NoLLvmMetadataLoader {
+ fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
+ use std::fs::File;
+ use std::io;
+ use self::ar::Archive;
+
+ let file = File::open(filename).map_err(|e|format!("metadata file open err: {:?}", e))?;
+ let mut archive = Archive::new(file);
+
+ while let Some(entry_result) = archive.next_entry() {
+ let mut entry = entry_result.map_err(|e|format!("metadata section read err: {:?}", e))?;
+ if entry.header().identifier() == "rust.metadata.bin" {
+ let mut buf = Vec::new();
+ io::copy(&mut entry, &mut buf).unwrap();
+ let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
+ return Ok(buf.map_owner_box().erase_owner());
+ }
+ }
+
+ Err("Couldnt find metadata section".to_string())
+ }
+
+ fn get_dylib_metadata(&self,
+ _target: &Target,
+ _filename: &Path)
+ -> Result<ErasedBoxRef<[u8]>, String> {
+ panic!("Dylib metadata loading not supported without LLVM")
+ }
+}
+
// Parse args and run the compiler. This is the primary entry point for rustc.
// See comments on CompilerCalls below for details about the callbacks argument.
// The FileLoader provides a way to load files from sources other than the file system.
+#[cfg_attr(not(feature="llvm"), allow(unused_mut))]
pub fn run_compiler<'a>(args: &[String],
callbacks: &mut CompilerCalls<'a>,
file_loader: Option<Box<FileLoader + 'static>>,
let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
if sopts.debugging_opts.debug_llvm {
+ #[cfg(feature="llvm")]
rustc_trans::enable_llvm_debug();
}
};
let dep_graph = DepGraph::new(sopts.build_dep_graph());
- let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
+ let cstore = Rc::new(CStore::new(&dep_graph, box ::MetadataLoader));
let loader = file_loader.unwrap_or(box RealFileLoader);
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
let mut sess = session::build_session_with_codemap(
sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest,
);
+ #[cfg(feature="llvm")]
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, cfg);
+ #[cfg(feature="llvm")]
target_features::add_configuration(&mut cfg, &sess);
sess.parse_sess.config = cfg;
match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
Ok(mut pager) => {
- if let Some(mut pipe) = pager.stdin.as_mut() {
+ if let Some(pipe) = pager.stdin.as_mut() {
if pipe.write_all(content.as_bytes()).is_err() {
fallback_to_println = true;
}
Compilation::Continue
}
+ #[cfg_attr(not(feature="llvm"), allow(unused_mut))]
fn no_input(&mut self,
matches: &getopts::Matches,
sopts: &config::Options,
return None;
}
let dep_graph = DepGraph::new(sopts.build_dep_graph());
- let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
+ let cstore = Rc::new(CStore::new(&dep_graph, box ::MetadataLoader));
let mut sess = build_session(sopts.clone(),
&dep_graph,
None,
descriptions.clone(),
cstore.clone());
+ #[cfg(feature="llvm")]
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, cfg.clone());
+ #[cfg(feature="llvm")]
target_features::add_configuration(&mut cfg, &sess);
sess.parse_sess.config = cfg;
let should_stop =
-> CompileController<'a> {
let mut control = CompileController::basic();
- control.keep_ast = sess.opts.debugging_opts.keep_ast || save_analysis(sess);
+ control.keep_ast = sess.opts.debugging_opts.keep_ast;
+ control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error;
if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) {
if ppm.needs_ast_map(&opt_uii) {
}
if save_analysis(sess) {
- control.after_analysis.callback = box |state| {
- time(state.session.time_passes(), "save analysis", || {
- save::process_crate(state.tcx.unwrap(),
- state.expanded_crate.unwrap(),
- state.analysis.unwrap(),
- state.crate_name.unwrap(),
- None,
- DumpHandler::new(state.out_dir,
- state.crate_name.unwrap()))
- });
- };
- control.after_analysis.run_callback_on_error = true;
- control.make_glob_map = resolve::MakeGlobMap::Yes;
+ enable_save_analysis(&mut control);
}
if sess.print_fuel_crate.is_some() {
}
}
+pub fn enable_save_analysis(control: &mut CompileController) {
+ control.keep_ast = true;
+ control.after_analysis.callback = box |state| {
+ time(state.session.time_passes(), "save analysis", || {
+ save::process_crate(state.tcx.unwrap(),
+ state.expanded_crate.unwrap(),
+ state.analysis.unwrap(),
+ state.crate_name.unwrap(),
+ None,
+ DumpHandler::new(state.out_dir,
+ state.crate_name.unwrap()))
+ });
+ };
+ control.after_analysis.run_callback_on_error = true;
+ control.make_glob_map = resolve::MakeGlobMap::Yes;
+}
+
fn save_analysis(sess: &Session) -> bool {
sess.opts.debugging_opts.save_analysis
}
};
let attrs = attrs.as_ref().unwrap();
let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
- let id = link::find_crate_name(Some(sess), attrs, input);
+ let id = rustc_trans_utils::link::find_crate_name(Some(sess), attrs, input);
if *req == PrintRequest::CrateName {
println!("{}", id);
continue;
}
let crate_types = driver::collect_crate_types(sess, attrs);
for &style in &crate_types {
- let fname = link::filename_for_input(sess, style, &id, &t_outputs);
+ let fname = rustc_trans_utils::link::filename_for_input(
+ sess,
+ style,
+ &id,
+ &t_outputs
+ );
println!("{}",
fname.file_name()
.unwrap()
}
PrintRequest::RelocationModels => {
println!("Available relocation models:");
+ #[cfg(feature="llvm")]
for &(name, _) in RELOC_MODEL_ARGS.iter() {
println!(" {}", name);
}
}
PrintRequest::CodeModels => {
println!("Available code models:");
+ #[cfg(feature="llvm")]
for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){
println!(" {}", name);
}
println!("");
}
PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => {
+ #[cfg(feature="llvm")]
rustc_trans::print(*req, sess);
+ #[cfg(not(feature="llvm"))]
+ panic!("LLVM not supported by this rustc")
}
}
}
println!("commit-date: {}", unw(commit_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(release_str()));
+ #[cfg(feature="llvm")]
rustc_trans::print_version();
}
}
}
if cg_flags.contains(&"passes=list".to_string()) {
+ #[cfg(feature="llvm")]
rustc_trans::print_passes();
return None;
}
all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
+ #[cfg(feature="llvm")]
all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
Registry::new(&all_errors)
}
-fn get_args() -> Vec<String> {
+pub fn get_args() -> Vec<String> {
env::args_os().enumerate()
.map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
early_error(ErrorOutputType::default(),
use rustc::dep_graph::DepGraph;
use rustc_lint;
use rustc_resolve::MakeGlobMap;
+#[cfg(feature="llvm")]
use rustc_trans;
use rustc::middle::lang_items;
use rustc::middle::free_region::FreeRegionMap;
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
- let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
+ let cstore = Rc::new(CStore::new(&dep_graph, box ::MetadataLoader));
let sess = session::build_session_(options,
&dep_graph,
None,
diagnostic_handler,
Rc::new(CodeMap::new(FilePathMapping::empty())),
cstore.clone());
+ #[cfg(feature="llvm")]
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let input = config::Input::Str {
name: driver::anon_src(),
input: source_string.to_string(),
};
- let krate = driver::phase_1_parse_input(&sess, &input).unwrap();
+ let krate = driver::phase_1_parse_input(&driver::CompileController::basic(),
+ &sess,
+ &input).unwrap();
let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
driver::phase_2_configure_and_expand(&sess,
&cstore,
use rustc::traits::{self, Reveal};
use rustc::hir::map as hir_map;
use util::nodemap::NodeSet;
-use lint::{Level, LateContext, LintContext, LintArray};
+use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
use std::collections::HashSet;
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
sp,
"function cannot return without recurring");
-
// FIXME #19668: these could be span_lint_note's instead of this manual guard.
- if cx.current_level(UNCONDITIONAL_RECURSION) != Level::Allow {
- // offer some help to the programmer.
- for call in &self_call_spans {
- db.span_note(*call, "recursive call site");
- }
- db.help("a `loop` may express intention \
- better if this is on purpose");
+ // offer some help to the programmer.
+ for call in &self_call_spans {
+ db.span_note(*call, "recursive call site");
}
+ db.help("a `loop` may express intention \
+ better if this is on purpose");
db.emit();
}
_ => {},
}
- let mut bfs_queue = &mut VecDeque::new();
+ let bfs_queue = &mut VecDeque::new();
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: def::Export, parent: DefId| {
let child = child.def.def_id();
Entry {
kind: EntryKind::Mod(self.lazy(&data)),
visibility: self.lazy(&ty::Visibility::from_hir(vis, id, tcx)),
- span: self.lazy(&md.inner),
+ span: self.lazy(&tcx.def_span(def_id)),
attributes: self.encode_attributes(attrs),
children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
tcx.hir.local_def_id(item_id.id).index
self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty);
}
- pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F)
+ pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>)
{
match *pattern.kind {
debug!("make_shim({:?}) = untransformed {:?}", instance, result);
no_landing_pads::no_landing_pads(tcx, &mut result);
simplify::simplify_cfg(&mut result);
- add_call_guards::add_call_guards(&mut result);
+ add_call_guards::CriticalCallEdges.add_call_guards(&mut result);
debug!("make_shim({:?}) = {:?}", instance, result);
tcx.alloc_mir(result)
use rustc::mir::transform::{MirPass, MirSource};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-pub struct AddCallGuards;
+#[derive(PartialEq)]
+pub enum AddCallGuards {
+ AllCallEdges,
+ CriticalCallEdges,
+}
+pub use self::AddCallGuards::*;
/**
* Breaks outgoing critical edges for call terminators in the MIR.
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
- add_call_guards(mir);
+ self.add_call_guards(mir);
}
}
-pub fn add_call_guards(mir: &mut Mir) {
- let pred_count: IndexVec<_, _> =
- mir.predecessors().iter().map(|ps| ps.len()).collect();
+impl AddCallGuards {
+ pub fn add_call_guards(&self, mir: &mut Mir) {
+ let pred_count: IndexVec<_, _> =
+ mir.predecessors().iter().map(|ps| ps.len()).collect();
- // We need a place to store the new blocks generated
- let mut new_blocks = Vec::new();
+ // We need a place to store the new blocks generated
+ let mut new_blocks = Vec::new();
- let cur_len = mir.basic_blocks().len();
+ let cur_len = mir.basic_blocks().len();
- for block in mir.basic_blocks_mut() {
- match block.terminator {
- Some(Terminator {
- kind: TerminatorKind::Call {
- destination: Some((_, ref mut destination)),
- cleanup: Some(_),
- ..
- }, source_info
- }) if pred_count[*destination] > 1 => {
- // It's a critical edge, break it
- let call_guard = BasicBlockData {
- statements: vec![],
- is_cleanup: block.is_cleanup,
- terminator: Some(Terminator {
- source_info: source_info,
- kind: TerminatorKind::Goto { target: *destination }
- })
- };
+ for block in mir.basic_blocks_mut() {
+ match block.terminator {
+ Some(Terminator {
+ kind: TerminatorKind::Call {
+ destination: Some((_, ref mut destination)),
+ cleanup,
+ ..
+ }, source_info
+ }) if pred_count[*destination] > 1 &&
+ (cleanup.is_some() || self == &AllCallEdges) =>
+ {
+ // It's a critical edge, break it
+ let call_guard = BasicBlockData {
+ statements: vec![],
+ is_cleanup: block.is_cleanup,
+ terminator: Some(Terminator {
+ source_info: source_info,
+ kind: TerminatorKind::Goto { target: *destination }
+ })
+ };
- // Get the index it will be when inserted into the MIR
- let idx = cur_len + new_blocks.len();
- new_blocks.push(call_guard);
- *destination = BasicBlock::new(idx);
+ // Get the index it will be when inserted into the MIR
+ let idx = cur_len + new_blocks.len();
+ new_blocks.push(call_guard);
+ *destination = BasicBlock::new(idx);
+ }
+ _ => {}
}
- _ => {}
}
- }
- debug!("Broke {} N edges", new_blocks.len());
+ debug!("Broke {} N edges", new_blocks.len());
- mir.basic_blocks_mut().extend(new_blocks);
+ mir.basic_blocks_mut().extend(new_blocks);
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::ty::TyCtxt;
-use rustc::mir::Mir;
-use rustc::mir::visit::MutVisitor;
+use rustc::ty::TypeFoldable;
+use rustc::ty::subst::{Kind, Substs};
+use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind};
+use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind};
+use rustc::mir::visit::{MutVisitor, Lookup};
use rustc::mir::transform::{MirPass, MirSource};
+use rustc::infer::{self, InferCtxt};
+use syntax_pos::DUMMY_SP;
+use std::collections::HashMap;
#[allow(dead_code)]
-struct NLLVisitor<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
+struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+ lookup_map: HashMap<RegionVid, Lookup>,
+ infcx: InferCtxt<'a, 'gcx, 'tcx>,
}
-impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
+ pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
NLLVisitor {
- tcx: tcx
+ infcx: infcx,
+ lookup_map: HashMap::new(),
+ }
+ }
+
+ pub fn into_results(self) -> HashMap<RegionVid, Lookup> {
+ self.lookup_map
+ }
+
+ fn renumber_regions<T>(&self, value: &T) -> T where T: TypeFoldable<'tcx> {
+ self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
+ self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP))
+ })
+ }
+
+ fn store_region(&mut self, region: &RegionKind, lookup: Lookup) {
+ if let RegionKind::ReVar(rid) = *region {
+ self.lookup_map.entry(rid).or_insert(lookup);
+ }
+ }
+
+ fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) {
+ for region in ty.regions() {
+ self.store_region(region, lookup);
+ }
+ }
+
+ fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) {
+ if let Some(ty) = kind.as_type() {
+ self.store_ty_regions(&ty, lookup);
+ } else if let Some(region) = kind.as_region() {
+ self.store_region(region, lookup);
}
}
}
-impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
- // FIXME: Nashenas88: implement me!
+impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
+ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) {
+ let old_ty = *ty;
+ *ty = self.renumber_regions(&old_ty);
+ self.store_ty_regions(ty, lookup);
+ }
+
+ fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
+ *substs = self.renumber_regions(&{*substs});
+ let lookup = Lookup::Loc(location);
+ for kind in *substs {
+ self.store_kind_regions(kind, lookup);
+ }
+ }
+
+ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
+ match *rvalue {
+ Rvalue::Ref(ref mut r, _, _) => {
+ let old_r = *r;
+ *r = self.renumber_regions(&old_r);
+ let lookup = Lookup::Loc(location);
+ self.store_region(r, lookup);
+ }
+ Rvalue::Use(..) |
+ Rvalue::Repeat(..) |
+ Rvalue::Len(..) |
+ Rvalue::Cast(..) |
+ Rvalue::BinaryOp(..) |
+ Rvalue::CheckedBinaryOp(..) |
+ Rvalue::UnaryOp(..) |
+ Rvalue::Discriminant(..) |
+ Rvalue::NullaryOp(..) |
+ Rvalue::Aggregate(..) => {
+ // These variants don't contain regions.
+ }
+ }
+ self.super_rvalue(rvalue, location);
+ }
+
+ fn visit_closure_substs(&mut self,
+ substs: &mut ClosureSubsts<'tcx>,
+ location: Location) {
+ *substs = self.renumber_regions(substs);
+ let lookup = Lookup::Loc(location);
+ for kind in substs.substs {
+ self.store_kind_regions(kind, lookup);
+ }
+ }
+
+ fn visit_statement(&mut self,
+ block: BasicBlock,
+ statement: &mut Statement<'tcx>,
+ location: Location) {
+ if let StatementKind::EndRegion(_) = statement.kind {
+ statement.kind = StatementKind::Nop;
+ }
+ self.super_statement(block, statement, location);
+ }
}
// MIR Pass for non-lexical lifetimes
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
- if tcx.sess.opts.debugging_opts.nll {
- // Clone mir so we can mutate it without disturbing the rest
- // of the compiler
- NLLVisitor::new(tcx).visit_mir(&mut mir.clone());
+ if !tcx.sess.opts.debugging_opts.nll {
+ return;
}
+
+ tcx.infer_ctxt().enter(|infcx| {
+ // Clone mir so we can mutate it without disturbing the rest of the compiler
+ let mut renumbered_mir = mir.clone();
+ let mut visitor = NLLVisitor::new(infcx);
+ visitor.visit_mir(&mut renumbered_mir);
+ let _results = visitor.into_results();
+ })
}
}
\ No newline at end of file
value,
obligations);
- let mut fulfill_cx = &mut self.fulfillment_cx;
+ let fulfill_cx = &mut self.fulfillment_cx;
for obligation in obligations {
fulfill_cx.register_predicate_obligation(self.infcx, obligation);
}
self.check_trait_fn_not_const(sig.constness);
if block.is_none() {
self.check_decl_no_pat(&sig.decl, |span, _| {
- self.session.add_lint(lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
- trait_item.id, span,
- "patterns aren't allowed in methods \
- without bodies".to_string());
+ self.session.buffer_lint(
+ lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
+ trait_item.id, span,
+ "patterns aren't allowed in methods \
+ without bodies");
});
}
}
if item.attrs.iter().any(|attr| attr.check_name("warn_directory_ownership")) {
let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
let msg = "cannot declare a new module at this location";
- self.session.add_lint(lint, item.id, item.span, msg.to_string());
+ self.session.buffer_lint(lint, item.id, item.span, msg);
}
}
ItemKind::Union(ref vdata, _) => {
ErroneousReferencedConstant(_) => {}
TypeckError => {}
_ => {
- self.tcx.sess.add_lint(CONST_ERR,
- expr.id,
- expr.span,
- format!("constant evaluation error: {}. This will \
- become a HARD ERROR in the future",
- err.description().into_oneline()))
+ self.tcx.lint_node(CONST_ERR,
+ expr.id,
+ expr.span,
+ &format!("constant evaluation error: {}. This will \
+ become a HARD ERROR in the future",
+ err.description().into_oneline()));
}
}
}
kind: LayoutError(ty::layout::LayoutError::Unknown(_)), ..
}) => {}
Err(msg) => {
- self.tcx.sess.add_lint(CONST_ERR,
- ex.id,
- msg.span,
- msg.description().into_oneline().into_owned())
+ self.tcx.lint_node(CONST_ERR,
+ ex.id,
+ msg.span,
+ &msg.description().into_oneline().into_owned());
}
}
}
```
'foo: while break 'foo {}
```
+"##,
+
+E0571: r##"
+A `break` statement with an argument appeared in a non-`loop` loop.
+
+Example of erroneous code:
+
+```compile_fail,E0571
+# let mut i = 1;
+# fn satisfied(n: usize) -> bool { n % 23 == 0 }
+let result = while true {
+ if satisfied(i) {
+ break 2*i; // error: `break` with value from a `while` loop
+ }
+ i += 1;
+};
+```
+
+The `break` statement can take an argument (which will be the value of the loop
+expression if the `break` statement is executed) in `loop` loops, but not
+`for`, `while`, or `while let` loops.
+
+Make sure `break value;` statements only occur in `loop` loops:
+
+```
+# let mut i = 1;
+# fn satisfied(n: usize) -> bool { n % 23 == 0 }
+let result = loop { // ok!
+ if satisfied(i) {
+ break 2*i;
+ }
+ i += 1;
+};
+```
"##
}
E0226, // only a single explicit lifetime bound is permitted
E0472, // asm! is unsupported on this target
E0561, // patterns aren't allowed in function pointer types
- E0571, // `break` with a value in a non-`loop`-loop
}
hir::ItemTrait(.., ref trait_item_refs) => {
self.check_item(item.id).generics().predicates();
for trait_item_ref in trait_item_refs {
- let mut check = self.check_item(trait_item_ref.id.node_id);
+ let check = self.check_item(trait_item_ref.id.node_id);
check.generics().predicates();
if trait_item_ref.kind != hir::AssociatedItemKind::Type ||
trait_item_ref.defaultness.has_value() {
}
hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
{
- let mut check = self.check_item(item.id);
+ let check = self.check_item(item.id);
check.ty().generics().predicates();
if trait_ref.is_some() {
check.impl_trait_ref();
"private trait can't be public"))
.emit();
} else {
- self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
- node_id,
- self.span,
- format!("private trait `{}` in public \
- interface (error E0445)", trait_ref));
+ self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC,
+ node_id,
+ self.span,
+ &format!("private trait `{}` in public \
+ interface (error E0445)", trait_ref));
}
}
}
err.span_label(self.span, "can't leak private type");
err.emit();
} else {
- self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
- node_id,
- self.span,
- format!("private type `{}` in public \
- interface (error E0446)", ty));
+ self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC,
+ node_id,
+ self.span,
+ &format!("private type `{}` in public \
+ interface (error E0446)", ty));
}
}
}
directive.span.source_equal(&DUMMY_SP) => {}
ImportDirectiveSubclass::ExternCrate => {
let lint = lint::builtin::UNUSED_EXTERN_CRATES;
- let msg = "unused extern crate".to_string();
- resolver.session.add_lint(lint, directive.id, directive.span, msg);
+ let msg = "unused extern crate";
+ ; resolver.session.buffer_lint(lint, directive.id, directive.span, msg)
}
ImportDirectiveSubclass::MacroUse => {
let lint = lint::builtin::UNUSED_IMPORTS;
- let msg = "unused `#[macro_use]` import".to_string();
- resolver.session.add_lint(lint, directive.id, directive.span, msg);
+ let msg = "unused `#[macro_use]` import";
+ resolver.session.buffer_lint(lint, directive.id, directive.span, msg);
}
_ => {}
}
} else {
String::new()
});
- visitor.session.add_lint(lint::builtin::UNUSED_IMPORTS,
- *id,
- ms,
- msg);
+ visitor.session.buffer_lint(lint::builtin::UNUSED_IMPORTS, *id, ms, &msg);
}
}
= self.struct_constructors.get(&def_id).cloned() {
if is_expected(ctor_def) && self.is_accessible(ctor_vis) {
let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
- self.session.add_lint(lint, id, span,
+ self.session.buffer_lint(lint, id, span,
"private struct constructors are not usable through \
- reexports in outer modules".to_string());
+ reexports in outer modules",
+ );
res = Some(PathResolution::new(ctor_def));
}
}
};
if result.base_def() == unqualified_result {
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
- self.session.add_lint(lint, id, span, "unnecessary qualification".to_string());
+ self.session.buffer_lint(lint, id, span, "unnecessary qualification")
}
}
span.push_span_label(b1.span, msg1);
span.push_span_label(b2.span, msg2);
let msg = format!("`{}` is ambiguous", name);
- self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
+ self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, &msg);
} else {
let mut err =
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name));
fn warn_legacy_self_import(&self, directive: &'a ImportDirective<'a>) {
let (id, span) = (directive.id, directive.span);
- let msg = "`self` no longer imports values".to_string();
- self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
+ let msg = "`self` no longer imports values";
+ self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
}
fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) {
};
if let Some((id, span)) = id_span {
let lint = lint::builtin::UNUSED_MACROS;
- let msg = "unused macro definition".to_string();
- self.session.add_lint(lint, id, span, msg);
+ let msg = "unused macro definition";
+ self.session.buffer_lint(lint, id, span, msg);
} else {
bug!("attempted to create unused macro error, but span not available");
}
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
let (binding, t) = {
- let mut resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
+ let resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
let msg = format!("extern crate `{}` is private, and cannot be reexported \
(error E0365), consider declaring with `pub`",
ident);
- self.session.add_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
- directive.id, directive.span, msg);
+ self.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+ directive.id,
+ directive.span,
+ &msg);
} else if ns == TypeNS {
struct_span_err!(self.session, directive.span, E0365,
"`{}` is private, and cannot be reexported", ident)
rustc_incremental = { path = "../librustc_incremental" }
rustc_llvm = { path = "../librustc_llvm" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
+rustc_trans_utils = { path = "../librustc_trans_utils" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+extern crate rustc_trans_utils;
+
use super::archive::{ArchiveBuilder, ArchiveConfig};
use super::linker::Linker;
use super::rpath::RPathConfig;
use super::rpath;
use metadata::METADATA_FILENAME;
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType};
+use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType};
use rustc::session::filesearch;
use rustc::session::search_paths::PathKind;
use rustc::session::Session;
-use rustc::middle::cstore::{self, LinkMeta, NativeLibrary, LibSource, LinkagePreference,
+use rustc::middle::cstore::{LinkMeta, NativeLibrary, LibSource, LinkagePreference,
NativeLibraryKind};
use rustc::middle::dependency_format::Linkage;
use CrateTranslation;
use std::str;
use flate2::Compression;
use flate2::write::DeflateEncoder;
-use syntax::ast;
use syntax::attr;
-use syntax_pos::Span;
/// The LLVM module name containing crate-metadata. This includes a `.` on
/// purpose, so it cannot clash with the name of a user-defined module.
pub const RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET: usize =
RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8;
-
-pub fn find_crate_name(sess: Option<&Session>,
- attrs: &[ast::Attribute],
- input: &Input) -> String {
- let validate = |s: String, span: Option<Span>| {
- cstore::validate_crate_name(sess, &s, span);
- s
- };
-
- // Look in attributes 100% of the time to make sure the attribute is marked
- // as used. After doing this, however, we still prioritize a crate name from
- // the command line over one found in the #[crate_name] attribute. If we
- // find both we ensure that they're the same later on as well.
- let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
- .and_then(|at| at.value_str().map(|s| (at, s)));
-
- if let Some(sess) = sess {
- if let Some(ref s) = sess.opts.crate_name {
- if let Some((attr, name)) = attr_crate_name {
- if name != &**s {
- let msg = format!("--crate-name and #[crate_name] are \
- required to match, but `{}` != `{}`",
- s, name);
- sess.span_err(attr.span, &msg);
- }
- }
- return validate(s.clone(), None);
- }
- }
-
- if let Some((attr, s)) = attr_crate_name {
- return validate(s.to_string(), Some(attr.span));
- }
- if let Input::File(ref path) = *input {
- if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
- if s.starts_with("-") {
- let msg = format!("crate names cannot start with a `-`, but \
- `{}` has a leading hyphen", s);
- if let Some(sess) = sess {
- sess.err(&msg);
- }
- } else {
- return validate(s.replace("-", "_"), None);
- }
- }
- }
-
- "rust_out".to_string()
-}
+pub use self::rustc_trans_utils::link::{find_crate_name, filename_for_input,
+ default_output_for_target, invalid_output_for_target};
pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta {
let krate_dep_node = &DepNode::new_no_params(DepKind::Krate);
out_filenames
}
-
-/// Returns default crate type for target
-///
-/// Default crate type is used when crate type isn't provided neither
-/// through cmd line arguments nor through crate attributes
-///
-/// It is CrateTypeExecutable for all platforms but iOS as there is no
-/// way to run iOS binaries anyway without jailbreaking and
-/// interaction with Rust code through static library is the only
-/// option for now
-pub fn default_output_for_target(sess: &Session) -> config::CrateType {
- if !sess.target.target.options.executables {
- config::CrateTypeStaticlib
- } else {
- config::CrateTypeExecutable
- }
-}
-
-/// Checks if target supports crate_type as output
-pub fn invalid_output_for_target(sess: &Session,
- crate_type: config::CrateType) -> bool {
- match (sess.target.target.options.dynamic_linking,
- sess.target.target.options.executables, crate_type) {
- (false, _, config::CrateTypeCdylib) |
- (false, _, config::CrateTypeProcMacro) |
- (false, _, config::CrateTypeDylib) => true,
- (_, false, config::CrateTypeExecutable) => true,
- _ => false
- }
-}
-
fn is_writeable(p: &Path) -> bool {
match p.metadata() {
Err(..) => true,
out_filename
}
-pub fn filename_for_input(sess: &Session,
- crate_type: config::CrateType,
- crate_name: &str,
- outputs: &OutputFilenames) -> PathBuf {
- let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
-
- match crate_type {
- config::CrateTypeRlib => {
- outputs.out_directory.join(&format!("lib{}.rlib", libname))
- }
- config::CrateTypeCdylib |
- config::CrateTypeProcMacro |
- config::CrateTypeDylib => {
- let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
- &sess.target.target.options.dll_suffix);
- outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
- suffix))
- }
- config::CrateTypeStaticlib => {
- let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
- &sess.target.target.options.staticlib_suffix);
- outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
- suffix))
- }
- config::CrateTypeExecutable => {
- let suffix = &sess.target.target.options.exe_suffix;
- let out_filename = outputs.path(OutputType::Exe);
- if suffix.is_empty() {
- out_filename.to_path_buf()
- } else {
- out_filename.with_extension(&suffix[1..])
- }
- }
- }
-}
-
pub fn each_linked_rlib(sess: &Session,
f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> {
let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter();
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
use rustc::session::config;
use rustc::ty::TyCtxt;
+use rustc_allocator::ALLOCATOR_METHODS;
use syntax::attr;
/// The SymbolExportLevel of a symbols specifies from which kinds of crates
SymbolExportLevel::C));
}
+ if tcx.sess.allocator_kind.get().is_some() {
+ for method in ALLOCATOR_METHODS {
+ local_crate.push((format!("__rust_{}", method.name),
+ INVALID_DEF_ID,
+ SymbolExportLevel::Rust));
+ }
+ }
+
if let Some(id) = tcx.sess.derive_registrar_fn.get() {
let def_id = tcx.hir.local_def_id(id);
let idx = def_id.index;
let mut output = i.to_string(scx.tcx());
output.push_str(" @@");
let mut empty = Vec::new();
- let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
+ let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone());
cgus.dedup();
for &(ref cgu_name, (linkage, _)) in cgus.iter() {
CodegenUnit::empty(codegen_unit_name.clone())
};
- let mut codegen_unit = codegen_units.entry(codegen_unit_name.clone())
+ let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
.or_insert_with(make_codegen_unit);
let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
{
let mut table = self.data.lock().unwrap();
- let mut data = table.entry(timeline).or_insert(PerThread {
+ let data = table.entry(timeline).or_insert(PerThread {
timings: Vec::new(),
open_work_package: None,
});
let end = Instant::now();
let mut table = self.data.lock().unwrap();
- let mut data = table.get_mut(&timeline).unwrap();
+ let data = table.get_mut(&timeline).unwrap();
if let Some((start, work_package_kind)) = data.open_work_package {
data.timings.push(Timing {
--- /dev/null
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_trans_utils"
+version = "0.0.0"
+
+[lib]
+name = "rustc_trans_utils"
+path = "lib.rs"
+crate-type = ["dylib"]
+test = false
+
+[dependencies]
+rustc = { path = "../librustc" }
+syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
--- /dev/null
+// Copyright 2017 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.
+
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![crate_name = "rustc_trans_utils"]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![deny(warnings)]
+
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(const_fn)]
+#![feature(custom_attribute)]
+#![allow(unused_attributes)]
+#![feature(i128_type)]
+#![feature(quote)]
+#![feature(rustc_diagnostic_macros)]
+#![feature(slice_patterns)]
+#![feature(conservative_impl_trait)]
+
+extern crate rustc;
+extern crate syntax;
+extern crate syntax_pos;
+
+pub mod link;
--- /dev/null
+// Copyright 2017 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.
+
+use rustc::session::config::{self, /*NoDebugInfo,*/ OutputFilenames, Input, OutputType};
+/*use rustc::session::filesearch;
+use rustc::session::search_paths::PathKind;
+*/use rustc::session::Session;
+use rustc::middle::cstore;/*::{self, LinkMeta, NativeLibrary, LibSource, LinkagePreference,
+ NativeLibraryKind};*/
+/*use rustc::middle::dependency_format::Linkage;
+use rustc::util::common::time;
+use rustc::util::fs::fix_windows_verbatim_for_gcc;
+use rustc::dep_graph::{DepKind, DepNode};
+use rustc::hir::def_id::CrateNum;
+use rustc::hir::svh::Svh;
+use rustc_back::tempdir::TempDir;
+use rustc_back::{PanicStrategy, RelroLevel};
+use rustc_incremental::IncrementalHashesMap;*/
+
+/*use std::ascii;
+use std::char;
+use std::env;
+use std::ffi::OsString;
+use std::fs;
+use std::io::{self, Read, Write};
+use std::mem;
+*/use std::path::PathBuf;/*{Path, PathBuf};
+use std::process::Command;
+use std::str;*/
+use syntax::ast;
+//use syntax::attr;
+use syntax_pos::Span;
+
+pub fn find_crate_name(sess: Option<&Session>,
+ attrs: &[ast::Attribute],
+ input: &Input) -> String {
+ let validate = |s: String, span: Option<Span>| {
+ cstore::validate_crate_name(sess, &s, span);
+ s
+ };
+
+ // Look in attributes 100% of the time to make sure the attribute is marked
+ // as used. After doing this, however, we still prioritize a crate name from
+ // the command line over one found in the #[crate_name] attribute. If we
+ // find both we ensure that they're the same later on as well.
+ let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
+ .and_then(|at| at.value_str().map(|s| (at, s)));
+
+ if let Some(sess) = sess {
+ if let Some(ref s) = sess.opts.crate_name {
+ if let Some((attr, name)) = attr_crate_name {
+ if name != &**s {
+ let msg = format!("--crate-name and #[crate_name] are \
+ required to match, but `{}` != `{}`",
+ s, name);
+ sess.span_err(attr.span, &msg);
+ }
+ }
+ return validate(s.clone(), None);
+ }
+ }
+
+ if let Some((attr, s)) = attr_crate_name {
+ return validate(s.to_string(), Some(attr.span));
+ }
+ if let Input::File(ref path) = *input {
+ if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
+ if s.starts_with("-") {
+ let msg = format!("crate names cannot start with a `-`, but \
+ `{}` has a leading hyphen", s);
+ if let Some(sess) = sess {
+ sess.err(&msg);
+ }
+ } else {
+ return validate(s.replace("-", "_"), None);
+ }
+ }
+ }
+
+ "rust_out".to_string()
+}
+
+pub fn filename_for_input(sess: &Session,
+ crate_type: config::CrateType,
+ crate_name: &str,
+ outputs: &OutputFilenames) -> PathBuf {
+ let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
+
+ match crate_type {
+ config::CrateTypeRlib => {
+ outputs.out_directory.join(&format!("lib{}.rlib", libname))
+ }
+ config::CrateTypeCdylib |
+ config::CrateTypeProcMacro |
+ config::CrateTypeDylib => {
+ let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
+ &sess.target.target.options.dll_suffix);
+ outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
+ suffix))
+ }
+ config::CrateTypeStaticlib => {
+ let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
+ &sess.target.target.options.staticlib_suffix);
+ outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
+ suffix))
+ }
+ config::CrateTypeExecutable => {
+ let suffix = &sess.target.target.options.exe_suffix;
+ let out_filename = outputs.path(OutputType::Exe);
+ if suffix.is_empty() {
+ out_filename.to_path_buf()
+ } else {
+ out_filename.with_extension(&suffix[1..])
+ }
+ }
+ }
+}
+
+/// Returns default crate type for target
+///
+/// Default crate type is used when crate type isn't provided neither
+/// through cmd line arguments nor through crate attributes
+///
+/// It is CrateTypeExecutable for all platforms but iOS as there is no
+/// way to run iOS binaries anyway without jailbreaking and
+/// interaction with Rust code through static library is the only
+/// option for now
+pub fn default_output_for_target(sess: &Session) -> config::CrateType {
+ if !sess.target.target.options.executables {
+ config::CrateTypeStaticlib
+ } else {
+ config::CrateTypeExecutable
+ }
+}
+
+/// Checks if target supports crate_type as output
+pub fn invalid_output_for_target(sess: &Session,
+ crate_type: config::CrateType) -> bool {
+ match (sess.target.target.options.dynamic_linking,
+ sess.target.target.options.executables, crate_type) {
+ (false, _, config::CrateTypeCdylib) |
+ (false, _, config::CrateTypeProcMacro) |
+ (false, _, config::CrateTypeDylib) => true,
+ (_, false, config::CrateTypeExecutable) => true,
+ _ => false
+ }
+}
.span_label(data.span, "only traits may use parentheses")
.emit();
} else {
- let msg = "parenthesized parameters may only be used with a trait".to_string();
- self.tcx().sess.add_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
- ast::CRATE_NODE_ID, data.span, msg);
+ let msg = "parenthesized parameters may only be used with a trait";
+ self.tcx().lint_node(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
+ ast::CRATE_NODE_ID, data.span, msg);
}
}
}
let t_cast = self.cast_ty;
let t_expr = self.expr_ty;
if t_cast.is_numeric() && t_expr.is_numeric() {
- fcx.tables.borrow_mut().lints.add_lint(
+ fcx.tcx.lint_node(
lint::builtin::TRIVIAL_NUMERIC_CASTS,
self.expr.id,
self.span,
- format!("trivial numeric cast: `{}` as `{}`. Cast can be \
- replaced by coercion, this might require type \
- ascription or a temporary variable",
- fcx.ty_to_string(t_expr),
- fcx.ty_to_string(t_cast)));
+ &format!("trivial numeric cast: `{}` as `{}`. Cast can be \
+ replaced by coercion, this might require type \
+ ascription or a temporary variable",
+ fcx.ty_to_string(t_expr),
+ fcx.ty_to_string(t_cast)));
} else {
- fcx.tables.borrow_mut().lints.add_lint(
+ fcx.tcx.lint_node(
lint::builtin::TRIVIAL_CASTS,
self.expr.id,
self.span,
- format!("trivial cast: `{}` as `{}`. Cast can be \
- replaced by coercion, this might require type \
- ascription or a temporary variable",
- fcx.ty_to_string(t_expr),
- fcx.ty_to_string(t_cast)));
+ &format!("trivial cast: `{}` as `{}`. Cast can be \
+ replaced by coercion, this might require type \
+ ascription or a temporary variable",
+ fcx.ty_to_string(t_expr),
+ fcx.ty_to_string(t_cast)));
}
}
}
}
- if let Some(mut augment_error) = augment_error {
+ if let Some(augment_error) = augment_error {
augment_error(&mut db);
}
ClosureAmbiguity(// DefId of fn trait
DefId),
- // Found an applicable method, but it is not visible.
- PrivateMatch(Def),
+ // Found an applicable method, but it is not visible. The second argument contains a list of
+ // not-in-scope traits which may work.
+ PrivateMatch(Def, Vec<DefId>),
// Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
// forgotten to import a trait.
// We can't use normalize_associated_types_in as it will pollute the
// fcx's fulfillment context after this probe is over.
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let mut selcx = &mut traits::SelectionContext::new(self.fcx);
+ let selcx = &mut traits::SelectionContext::new(self.fcx);
let traits::Normalized { value: xform_self_ty, obligations } =
traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
// as it will pollute the fcx's fulfillment context after this probe
// is over.
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let mut selcx = &mut traits::SelectionContext::new(self.fcx);
+ let selcx = &mut traits::SelectionContext::new(self.fcx);
let traits::Normalized { value: xform_self_ty, obligations } =
traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
};
if let Some(def) = private_candidate {
- return Err(MethodError::PrivateMatch(def));
+ return Err(MethodError::PrivateMatch(def, out_of_scope_traits));
}
Err(MethodError::NoMatch(NoMatchData::new(static_candidates,
self.sess().span_err(span, &msg);
}
- MethodError::PrivateMatch(def) => {
- struct_span_err!(self.tcx.sess, span, E0624,
- "{} `{}` is private", def.kind_name(), item_name).emit();
+ MethodError::PrivateMatch(def, out_of_scope_traits) => {
+ let mut err = struct_span_err!(self.tcx.sess, span, E0624,
+ "{} `{}` is private", def.kind_name(), item_name);
+ self.suggest_valid_traits(&mut err, out_of_scope_traits);
+ err.emit();
}
MethodError::IllegalSizedBound(candidates) => {
err.note(&msg[..]);
}
- fn suggest_traits_to_import(&self,
- err: &mut DiagnosticBuilder,
- span: Span,
- rcvr_ty: Ty<'tcx>,
- item_name: ast::Name,
- rcvr_expr: Option<&hir::Expr>,
- valid_out_of_scope_traits: Vec<DefId>) {
+ fn suggest_valid_traits(&self,
+ err: &mut DiagnosticBuilder,
+ valid_out_of_scope_traits: Vec<DefId>) -> bool {
if !valid_out_of_scope_traits.is_empty() {
let mut candidates = valid_out_of_scope_traits;
candidates.sort();
});
self.suggest_use_candidates(err, msg, candidates);
+ true
+ } else {
+ false
+ }
+ }
+
+ fn suggest_traits_to_import(&self,
+ err: &mut DiagnosticBuilder,
+ span: Span,
+ rcvr_ty: Ty<'tcx>,
+ item_name: ast::Name,
+ rcvr_expr: Option<&hir::Expr>,
+ valid_out_of_scope_traits: Vec<DefId>) {
+ if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
return;
}
debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
- self.tables.borrow_mut().lints.add_lint(
+ self.tcx().lint_node(
lint::builtin::UNREACHABLE_CODE,
id, span,
- format!("unreachable {}", kind));
+ &format!("unreachable {}", kind));
}
}
// inside a loop at all, which is caught by the
// loop-checking pass.
assert!(self.tcx.sess.err_count() > 0);
+
+ // We still need to assign a type to the inner expression to
+ // prevent the ICE in #43162.
+ if let Some(ref e) = *expr_opt {
+ self.check_expr_with_hint(e, tcx.types.err);
+
+ // ... except when we try to 'break rust;'.
+ // ICE this expression in particular (see #43162).
+ if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = e.node {
+ if path.segments.len() == 1 && path.segments[0].name == "rust" {
+ fatally_break_rust(self.tcx.sess);
+ }
+ }
+ }
}
// the type of a `break` is always `!`, since it diverges
Ok(def) => def,
Err(error) => {
let def = match error {
- method::MethodError::PrivateMatch(def) => def,
+ method::MethodError::PrivateMatch(def, _) => def,
_ => Def::Err,
};
if item_name != keywords::Invalid.name() {
let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
- let mut ctxt = enclosing_breakables.find_breakable(blk.id);
- let mut coerce = ctxt.coerce.as_mut().unwrap();
+ let ctxt = enclosing_breakables.find_breakable(blk.id);
+ let coerce = ctxt.coerce.as_mut().unwrap();
if let Some(tail_expr_ty) = tail_expr_ty {
let tail_expr = tail_expr.unwrap();
let cause = self.cause(tail_expr.span,
ty
}
- /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
- /// `fn main` if it is a method, `None` otherwise.
+ /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
+ /// suggetion can be made, `None` otherwise.
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
// `while` before reaching it, as block tail returns are not available in them.
name, node: hir::ItemFn(ref decl, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
- // This is less than ideal, it will not present the return type span on any
- // method called `main`, regardless of whether it is actually the entry point.
- Some((decl, name == Symbol::intern("main")))
+ // This is less than ideal, it will not suggest a return type span on any
+ // method called `main`, regardless of whether it is actually the entry point,
+ // but it will still present it as the reason for the expected type.
+ Some((decl, name != Symbol::intern("main")))
})
} else if let Node::NodeTraitItem(&hir::TraitItem {
node: hir::TraitItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
+ }) = parent {
+ decl.clone().and_then(|decl| {
+ Some((decl, true))
+ })
+ } else if let Node::NodeImplItem(&hir::ImplItem {
+ node: hir::ImplItemKind::Method(hir::MethodSig {
+ ref decl, ..
+ }, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
Some((decl, false))
blk_id: ast::NodeId) {
self.suggest_missing_semicolon(err, expression, expected, cause_span);
- if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
- // `fn main()` must return `()`, do not suggest changing return type
- if !is_main {
- self.suggest_missing_return_type(err, &fn_decl, found);
- }
+ if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+ self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
}
}
fn suggest_missing_return_type(&self,
err: &mut DiagnosticBuilder<'tcx>,
fn_decl: &hir::FnDecl,
- ty: Ty<'tcx>) {
-
- // Only recommend changing the return type for methods that
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ can_suggest: bool) {
+ // Only suggest changing the return type for methods that
// haven't set a return type at all (and aren't `fn main()` or an impl).
- if let &hir::FnDecl {
- output: hir::FunctionRetTy::DefaultReturn(span), ..
- } = fn_decl {
- if ty.is_suggestable() {
+ match (&fn_decl.output, found.is_suggestable(), can_suggest) {
+ (&hir::FunctionRetTy::DefaultReturn(span), true, true) => {
err.span_suggestion(span,
"try adding a return type",
- format!("-> {} ", ty));
- } else {
+ format!("-> {} ", found));
+ }
+ (&hir::FunctionRetTy::DefaultReturn(span), false, true) => {
err.span_label(span, "possibly return type missing here?");
}
+ (&hir::FunctionRetTy::DefaultReturn(span), _, _) => {
+ // `fn main()` must return `()`, do not suggest changing return type
+ err.span_label(span, "expected `()` because of default return type");
+ }
+ (&hir::FunctionRetTy::Return(ref ty), _, _) => {
+ // Only point to return type if the expected type is the return type, as if they
+ // are not, the expectation must have been caused by something else.
+ debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node);
+ let sp = ty.span;
+ let ty = AstConv::ast_ty_to_ty(self, ty);
+ debug!("suggest_missing_return_type: return type sty {:?}", ty.sty);
+ debug!("suggest_missing_return_type: expected type sty {:?}", ty.sty);
+ if ty.sty == expected.sty {
+ err.span_label(sp, format!("expected `{}` because of return type",
+ expected));
+ }
+ }
}
}
} else {
let mut multispan = MultiSpan::from_span(lifetimes[0].span);
multispan.push_span_label(span_late, note_msg.to_string());
- self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
- lifetimes[0].id, multispan, primary_msg.to_string());
+ self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
+ lifetimes[0].id, multispan, primary_msg);
}
return;
}
}
}
}
+
+fn fatally_break_rust(sess: &Session) {
+ let handler = sess.diagnostic();
+ handler.span_bug_no_panic(
+ MultiSpan::new(),
+ "It looks like you're trying to break rust; would you like some ICE?",
+ );
+ handler.note_without_error("the compiler expectedly panicked. this is a feature.");
+ handler.note_without_error(
+ "we would appreciate a joke overview: \
+ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675"
+ );
+ handler.note_without_error(&format!("rustc {} running on {}",
+ option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+ ::session::config::host_triple(),
+ ));
+}
lhs_expr: &'gcx hir::Expr,
lhs_ty: Ty<'tcx>,
rhs_ty: Ty<'tcx>,
- mut err: &mut errors::DiagnosticBuilder) -> bool {
+ err: &mut errors::DiagnosticBuilder) -> bool {
// If this function returns true it means a note was printed, so we don't need
// to print the normal "implementation of `std::ops::Add` might be missing" note
let mut is_string_addition = false;
wbcx.visit_fru_field_types();
wbcx.visit_anon_types();
wbcx.visit_cast_types();
- wbcx.visit_lints();
wbcx.visit_free_region_map();
let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
}
- fn visit_lints(&mut self) {
- self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
- }
-
fn visit_free_region_map(&mut self) {
let free_region_map = self.tcx().lift_to_global(&self.fcx.tables.borrow().free_region_map);
let free_region_map = free_region_map.expect("all regions in free-region-map are global");
} else {
"unused import".to_string()
};
- self.tcx.sess.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, msg);
+ self.tcx.lint_node(lint::builtin::UNUSED_IMPORTS, id, span, &msg);
}
}
if !allow_defaults && p.default.is_some() {
if !tcx.sess.features.borrow().default_type_parameter_fallback {
- tcx.sess.add_lint(
+ tcx.lint_node(
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
p.id,
p.span,
- format!("defaults for type parameters are only allowed in `struct`, \
- `enum`, `type`, or `trait` definitions."));
+ &format!("defaults for type parameters are only allowed in `struct`, \
+ `enum`, `type`, or `trait` definitions."));
}
}
"##,
E0122: r##"
-An attempt was made to add a generic constraint to a type alias. While Rust will
-allow this with a warning, it will not currently enforce the constraint.
-Consider the example below:
+An attempt was made to add a generic constraint to a type alias. This constraint
+is entirely ignored. For backwards compatibility, Rust still allows this with a
+warning. Consider the example below:
```
trait Foo{}
target_features::add_configuration(&mut cfg, &sess);
sess.parse_sess.config = cfg;
- let krate = panictry!(driver::phase_1_parse_input(&sess, &input));
+ let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
+ &sess,
+ &input));
let name = link::find_crate_name(Some(&sess), &krate.attrs, &input);
if !types.is_empty() {
write!(w, "
- <h2 id='associated-types' class='section-header'>
- <a href='#associated-types'>Associated Types</a>
+ <h2 id='associated-types' class='small-section-header'>
+ Associated Types<a href='#associated-types' class='anchor'></a>
</h2>
<div class='methods'>
")?;
if !consts.is_empty() {
write!(w, "
- <h2 id='associated-const' class='section-header'>
- <a href='#associated-const'>Associated Constants</a>
+ <h2 id='associated-const' class='small-section-header'>
+ Associated Constants<a href='#associated-const' class='anchor'></a>
</h2>
<div class='methods'>
")?;
// Output the documentation for each function individually
if !required.is_empty() {
write!(w, "
- <h2 id='required-methods' class='section-header'>
- <a href='#required-methods'>Required Methods</a>
+ <h2 id='required-methods' class='small-section-header'>
+ Required Methods<a href='#required-methods' class='anchor'></a>
</h2>
<div class='methods'>
")?;
}
if !provided.is_empty() {
write!(w, "
- <h2 id='provided-methods' class='section-header'>
- <a href='#provided-methods'>Provided Methods</a>
+ <h2 id='provided-methods' class='small-section-header'>
+ Provided Methods<a href='#provided-methods' class='anchor'></a>
</h2>
<div class='methods'>
")?;
let cache = cache();
write!(w, "
- <h2 id='implementors' class='section-header'>
- <a href='#implementors'>Implementors</a>
+ <h2 id='implementors' class='small-section-header'>
+ Implementors<a href='#implementors' class='anchor'></a>
</h2>
<ul class='item-list' id='implementors-list'>
")?;
}).peekable();
if let doctree::Plain = s.struct_type {
if fields.peek().is_some() {
- write!(w, "<h2 id='fields' class='fields section-header'>
- <a href='#fields'>Fields</a></h2>")?;
+ write!(w, "<h2 id='fields' class='fields small-section-header'>
+ Fields<a href='#fields' class='anchor'></a></h2>")?;
for (field, ty) in fields {
let id = derive_id(format!("{}.{}",
ItemType::StructField,
}
}).peekable();
if fields.peek().is_some() {
- write!(w, "<h2 id='fields' class='fields section-header'>
- <a href='#fields'>Fields</a></h2>")?;
+ write!(w, "<h2 id='fields' class='fields small-section-header'>
+ Fields<a href='#fields' class='anchor'></a></h2>")?;
for (field, ty) in fields {
write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
</span>",
document(w, cx, it)?;
if !e.variants.is_empty() {
- write!(w, "<h2 id='variants' class='variants section-header'>
- <a href='#variants'>Variants</a></h2>\n")?;
+ write!(w, "<h2 id='variants' class='variants small-section-header'>
+ Variants<a href='#variants' class='anchor'></a></h2>\n")?;
for variant in &e.variants {
let id = derive_id(format!("{}.{}",
ItemType::Variant,
let render_mode = match what {
AssocItemRender::All => {
write!(w, "
- <h2 id='methods' class='section-header'>
- <a href='#methods'>Methods</a>
+ <h2 id='methods' class='small-section-header'>
+ Methods<a href='#methods' class='anchor'></a>
</h2>
")?;
RenderMode::Normal
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
write!(w, "
- <h2 id='deref-methods' class='section-header'>
- <a href='#deref-methods'>Methods from {}<Target = {}></a>
+ <h2 id='deref-methods' class='small-section-header'>
+ Methods from {}<Target = {}><a href='#deref-methods' class='anchor'></a>
</h2>
", trait_, type_)?;
RenderMode::ForDeref { mut_: deref_mut_ }
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?;
}
write!(w, "
- <h2 id='implementations' class='section-header'>
- <a href='#implementations'>Trait Implementations</a>
+ <h2 id='implementations' class='small-section-header'>
+ Trait Implementations<a href='#implementations' class='anchor'></a>
</h2>
")?;
for i in &traits {
background: transparent;
}
+.small-section-header:hover > .anchor {
+ display: initial;
+}
+.anchor {
+ display: none;
+}
+.anchor:after {
+ content: '\2002\00a7\2002';
+}
+
.docblock a:hover, .docblock-short a:hover, .stability a {
text-decoration: underline;
}
left: 0;
}
+.variant + .toggle-wrapper + .docblock > p {
+ margin-top: 5px;
+}
+
.variant + .toggle-wrapper > a {
margin-top: 5px;
}
margin-bottom: 25px;
}
-.enum .variant, .struct .structfield, .union .structfield {
+#main > .variant, #main > .structfield {
display: block;
}
sess.parse_sess.config =
config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
- let krate = panictry!(driver::phase_1_parse_input(&sess, &input));
+ let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
+ &sess,
+ &input));
let driver::ExpansionResult { defs, mut hir_forest, .. } = {
phase_2_configure_and_expand(
&sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
- fn into_iter(mut self) -> IterMut<'a, K, V> {
+ fn into_iter(self) -> IterMut<'a, K, V> {
self.iter_mut()
}
}
///
/// This works similarly to `put`, building an `EmptyBucket` out of the
/// taken bucket.
- pub fn take(mut self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
+ pub fn take(self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
self.table.size -= 1;
unsafe {
#[test]
fn downcasting() {
let mut a = A;
- let mut a = &mut a as &mut (Error + 'static);
+ let a = &mut a as &mut (Error + 'static);
assert_eq!(a.downcast_ref::<A>(), Some(&A));
assert_eq!(a.downcast_ref::<B>(), None);
assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
/// A reference to an open file on the filesystem.
///
/// An instance of a `File` can be read and/or written depending on what options
-/// it was opened with. Files also implement `Seek` to alter the logical cursor
+/// it was opened with. Files also implement [`Seek`] to alter the logical cursor
/// that the file contains internally.
///
/// Files are automatically closed when they go out of scope.
/// # }
/// ```
///
-/// Read the contents of a file into a `String`:
+/// Read the contents of a file into a [`String`]:
///
/// ```no_run
/// use std::fs::File;
/// # }
/// ```
///
+/// [`Seek`]: ../io/trait.Seek.html
+/// [`String`]: ../string/struct.String.html
/// [`Read`]: ../io/trait.Read.html
/// [`BufReader<R>`]: ../io/struct.BufReader.html
#[stable(feature = "rust1", since = "1.0.0")]
/// Iterator over the entries in a directory.
///
/// This iterator is returned from the [`read_dir`] function of this module and
-/// will yield instances of `io::Result<DirEntry>`. Through a [`DirEntry`]
+/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`]
/// information like the entry's path and possibly other metadata can be
/// learned.
///
-/// [`read_dir`]: fn.read_dir.html
-/// [`DirEntry`]: struct.DirEntry.html
-///
/// # Errors
///
-/// This [`io::Result`] will be an `Err` if there's some sort of intermittent
+/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
/// IO error during iteration.
///
+/// [`read_dir`]: fn.read_dir.html
+/// [`DirEntry`]: struct.DirEntry.html
/// [`io::Result`]: ../io/type.Result.html
+/// [`Err`]: ../result/enum.Result.html#variant.Err
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct ReadDir(fs_imp::ReadDir);
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = &mut &in_buf[..];
+ let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
-/// This type is broadly used across `std::io` for any operation which may
+/// This type is broadly used across [`std::io`] for any operation which may
/// produce an error.
///
-/// This typedef is generally used to avoid writing out `io::Error` directly and
-/// is otherwise a direct mapping to `Result`.
+/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// is otherwise a direct mapping to [`Result`].
///
-/// While usual Rust style is to import types directly, aliases of `Result`
-/// often are not, to make it easier to distinguish between them. `Result` is
-/// generally assumed to be `std::result::Result`, and so users of this alias
+/// While usual Rust style is to import types directly, aliases of [`Result`]
+/// often are not, to make it easier to distinguish between them. [`Result`] is
+/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
-/// of `std::result::Result`.
+/// of [`std::result::Result`][`Result`].
+///
+/// [`std::io`]: ../io/index.html
+/// [`io::Error`]: ../io/struct.Error.html
+/// [`Result`]: ../result/enum.Result.html
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;
-/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
+/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`Seek`]: ../io/trait.Seek.html
/// [`ErrorKind`]: enum.ErrorKind.html
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
-//! `File`s:
+//! [`File`]s:
//!
//! ```
//! use std::io;
//! # }
//! ```
//!
-//! Note that you cannot use the `?` operator in functions that do not return
-//! a `Result<T, E>` (e.g. `main`). Instead, you can call `.unwrap()` or `match`
-//! on the return value to catch any possible errors:
+//! Note that you cannot use the [`?` operator] in functions that do not return
+//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`]
+//! or `match` on the return value to catch any possible errors:
//!
//! ```
//! use std::io;
//! [`io::Result`]: type.Result.html
//! [`?` operator]: ../../book/first-edition/syntax-index.html
//! [`Read::read`]: trait.Read.html#tymethod.read
+//! [`Result`]: ../result/enum.Result.html
+//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
#![stable(feature = "rust1", since = "1.0.0")]
#![default_lib_allocator]
+// Always use alloc_system during stage0 since we don't know if the alloc_*
+// crate the stage0 compiler will pick by default is enabled (e.g.
+// if the user has disabled jemalloc in `./configure`).
+// `force_alloc_system` is *only* intended as a workaround for local rebuilds
+// with a rustc without jemalloc.
+// The not(stage0+msvc) gates will only last until the next stage0 bump
+#![cfg_attr(all(
+ not(all(stage0, target_env = "msvc")),
+ any(stage0, feature = "force_alloc_system")),
+ feature(global_allocator))]
+#[cfg(all(
+ not(all(stage0, target_env = "msvc")),
+ any(stage0, feature = "force_alloc_system")))]
+#[global_allocator]
+static ALLOC: alloc_system::System = alloc_system::System;
+
// Explicitly import the prelude. The compiler uses this same unstable attribute
// to import the prelude implicitly when building crates that depend on std.
#[prelude_import]
//! library. Each macro is available for use when linking against the standard
//! library.
+#[macro_export]
+// This stability attribute is totally useless.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(stage0)]
+macro_rules! __rust_unstable_column {
+ () => {
+ column!()
+ }
+}
+
/// The entry point for panic of Rust threads.
///
/// This macro is used to inject panic into a Rust thread, causing the thread to
($msg:expr) => ({
$crate::rt::begin_panic($msg, {
// static requires less code at runtime, more constant data
- static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
+ static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(),
+ __rust_unstable_column!());
&_FILE_LINE_COL
})
});
// used inside a dead function. Just `#[allow(dead_code)]` is
// insufficient, since the user may have
// `#[forbid(dead_code)]` and which cannot be overridden.
- static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
+ static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(),
+ __rust_unstable_column!());
&_FILE_LINE_COL
})
});
/// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24)
/// - the unspecified address (0.0.0.0)
///
- /// [ipv4-sr]: http://goo.gl/RaZ7lg
+ /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
/// [`true`]: ../../std/primitive.bool.html
///
/// # Examples
#[cold]
fn call_inner(&'static self,
ignore_poisoning: bool,
- mut init: &mut FnMut(bool)) {
+ init: &mut FnMut(bool)) {
let mut state = self.state.load(Ordering::SeqCst);
'outer: loop {
/// Accepts a new incoming connection to this listener.
///
/// This function will block the calling thread until a new Unix connection
- /// is established. When established, the corersponding [`UnixStream`] and
+ /// is established. When established, the corresponding [`UnixStream`] and
/// the remote peer's address will be returned.
///
/// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
use mem;
-fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
+fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 {
let mut buf: [u8; 4] = [0; 4];
fill_buf(&mut buf);
unsafe { mem::transmute::<[u8; 4], u32>(buf) }
}
-fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
+fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 {
let mut buf: [u8; 8] = [0; 8];
fill_buf(&mut buf);
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
unsafe {
let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
- let mut db = data.as_mut_ptr()
- as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
+ let db = data.as_mut_ptr()
+ as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
let buf = &mut (*db).ReparseTarget as *mut _;
let mut i = 0;
// FIXME: this conversion is very hacky
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,
+E0552: r##"
+A unrecognized representation attribute was used.
+
+Erroneous code example:
+
+```compile_fail,E0552
+#[repr(D)] // error: unrecognized representation hint
+struct MyStruct {
+ my_field: usize
+}
+```
+
+You can use a `repr` attribute to tell the compiler how you want a struct or
+enum to be laid out in memory.
+
+Make sure you're using one of the supported options:
+
+```
+#[repr(C)] // ok!
+struct MyStruct {
+ my_field: usize
+}
+```
+
+For more information about specifying representations, see the ["Alternative
+Representations" section] of the Rustonomicon.
+
+["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html
+"##,
+
+E0554: r##"
+Feature attributes are only allowed on the nightly release channel. Stable or
+beta compilers will not comply.
+
+Example of erroneous code (on a stable compiler):
+
+```ignore (depends on release channel)
+#![feature(non_ascii_idents)] // error: #![feature] may not be used on the
+ // stable release channel
+```
+
+If you need the feature, make sure to use a nightly release of the compiler
+(but be warned that the feature may be removed or altered in the future).
+"##,
+
+E0557: r##"
+A feature attribute named a feature that has been removed.
+
+Erroneous code example:
+
+```compile_fail,E0557
+#![feature(managed_boxes)] // error: feature has been removed
+```
+
+Delete the offending feature attribute.
+"##,
+
E0558: r##"
The `export_name` attribute was malformed.
E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
E0550, // multiple deprecated attributes
E0551, // incorrect meta item
- E0552, // unrecognized representation hint
- E0554, // #[feature] may not be used on the [] release channel
E0555, // malformed feature attribute, expected #![feature(...)]
E0556, // malformed feature, expected just one word
- E0557, // feature has been removed
E0584, // file for module `..` found at both .. and ..
E0589, // invalid `repr(align)` attribute
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
+pub use self::SyntaxExtension::*;
use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
let item = match self.cx.resolver.resolve_macro(
Mark::root(), path, MacroKind::Derive, false) {
Ok(ext) => match *ext {
- SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(),
+ BuiltinDerive(..) => item_with_markers.clone(),
_ => item.clone(),
},
_ => item.clone(),
items.push(item);
kind.expect_from_annotatables(items)
}
- SyntaxExtension::AttrProcMacro(ref mac) => {
+ AttrProcMacro(ref mac) => {
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) => token::NtTraitItem(item.unwrap()),
let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
}
- SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
+ ProcMacroDerive(..) | BuiltinDerive(..) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
kind.dummy(attr.span)
}
};
let opt_expanded = match *ext {
- SyntaxExtension::DeclMacro(ref expand, def_span) => {
+ DeclMacro(ref expand, def_span) => {
if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
false) {
self.cx.span_err(path.span, &msg);
kind.make_from(expander.expand(self.cx, span, ident, input))
}
- MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
+ MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
return kind.dummy(span);
}
- SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
+ ProcMacroDerive(..) | BuiltinDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
return kind.dummy(span);
}
- SyntaxExtension::ProcMacro(ref expandfun) => {
+ ProcMacro(ref expandfun) => {
if ident.name != keywords::Invalid.name() {
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
};
match *ext {
- SyntaxExtension::ProcMacroDerive(ref ext, _) => {
+ ProcMacroDerive(ref ext, _) => {
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = Span { ctxt: self.cx.backtrace(), ..span };
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
};
kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item))
}
- SyntaxExtension::BuiltinDerive(func) => {
+ BuiltinDerive(func) => {
expn_info.callee.allow_internal_unstable = true;
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = Span { ctxt: self.cx.backtrace(), ..span };
base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32))
}
+/* __rust_unstable_column!(): expands to the current column number */
+pub fn expand_column_gated(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<base::MacResult+'static> {
+ if sp.allows_unstable() {
+ expand_column(cx, sp, tts)
+ } else {
+ cx.span_fatal(sp, "the __rust_unstable_column macro is unstable");
+ }
+}
+
/// file!(): expands to the current filename */
/// The filemap (`loc.file`) contains a bunch more information we could spit
/// out if we wanted.
fn nameize<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, ms: &[TokenTree], mut res: I)
-> NamedParseResult {
- fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, mut res: &mut I,
+ fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, res: &mut I,
ret_val: &mut HashMap<Ident, Rc<NamedMatch>>)
-> Result<(), (syntax_pos::Span, String)> {
match *m {
/* error messages here could be improved with links to orig. rules */
if token_name_eq(&parser.token, &token::Eof) {
if eof_items.len() == 1 {
- let matches = eof_items[0].matches.iter_mut().map(|mut dv| {
+ let matches = eof_items[0].matches.iter_mut().map(|dv| {
Rc::make_mut(dv).pop().unwrap()
});
return nameize(sess, ms, matches);
fn trace_macros_note(cx: &mut ExtCtxt, sp: Span, message: String) {
let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp);
- let mut values: &mut Vec<String> = cx.expansions.entry(sp).or_insert_with(Vec::new);
+ let values: &mut Vec<String> = cx.expansions.entry(sp).or_insert_with(Vec::new);
values.push(message);
}
if attr.check_name("feature") {
let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
span_err!(span_handler, attr.span, E0554,
- "#[feature] may not be used on the {} release channel",
+ "#![feature] may not be used on the {} release channel",
release_channel);
}
}
('։', "Armenian Full Stop", ':'),
('܃', "Syriac Supralinear Colon", ':'),
('܄', "Syriac Sublinear Colon", ':'),
- ('᛬', "Runic Multiple Ponctuation", ':'),
+ ('᛬', "Runic Multiple Punctuation", ':'),
('︰', "Presentation Form For Vertical Two Dot Leader", ':'),
('᠃', "Mongolian Full Stop", ':'),
('᠉', "Mongolian Manchu Full Stop", ':'),
('ꝸ', "Latin Small Letter Um", '&'),
('&', "Fullwidth Ampersand", '&'),
- ('᛭', "Runic Cros Punctuation", '+'),
+ ('᛭', "Runic Cross Punctuation", '+'),
('➕', "Heavy Plus Sign", '+'),
('𐊛', "Lycian Letter H", '+'),
('﬩', "Hebrew Letter Alternative Plus Sign", '+'),
})
}
- /// Parse a static item from a foreign module
+ /// Parse a static item from a foreign module.
+ /// Assumes that the `static` keyword is already parsed.
fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
-> PResult<'a, ForeignItem> {
- self.expect_keyword(keywords::Static)?;
let mutbl = self.eat_keyword(keywords::Mut);
-
let ident = self.parse_ident()?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
let lo = self.span;
let visibility = self.parse_visibility(false)?;
- if self.check_keyword(keywords::Static) {
- // FOREIGN STATIC ITEM
+ // FOREIGN STATIC ITEM
+ // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
+ if self.check_keyword(keywords::Static) || self.token.is_keyword(keywords::Const) {
+ if self.token.is_keyword(keywords::Const) {
+ self.diagnostic()
+ .struct_span_err(self.span, "extern items cannot be `const`")
+ .span_suggestion(self.span, "instead try using", "static".to_owned())
+ .emit();
+ }
+ self.bump(); // `static` or `const`
return Ok(Some(self.parse_item_foreign_static(visibility, lo, attrs)?));
}
+ // FOREIGN FUNCTION ITEM
if self.check_keyword(keywords::Fn) {
- // FOREIGN FUNCTION ITEM
return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?));
}
- if self.check_keyword(keywords::Const) {
- return Err(self.span_fatal(self.span, "extern items cannot be `const`"));
- }
-
// FIXME #5668: this will occur for a macro invocation:
match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
Some(item) => {
/// Actually builds the expression which the format_args! block will be
/// expanded to
- fn into_expr(mut self) -> P<ast::Expr> {
+ fn into_expr(self) -> P<ast::Expr> {
let mut locals = Vec::new();
let mut counts = Vec::new();
let mut pats = Vec::new();
use syntax::ext::source_util::*;
register! {
line: expand_line,
+ __rust_unstable_column: expand_column_gated,
column: expand_column,
file: expand_file,
stringify: expand_stringify,
[features]
jemalloc = ["rustc_back/jemalloc"]
+llvm = ["rustc_driver/llvm"]
return Reloc::RWPI;
case LLVMRustRelocMode::ROPIRWPI:
return Reloc::ROPI_RWPI;
-#endif
+#else
default:
- llvm_unreachable("Bad RelocModel.");
+ break;
+#endif
}
+ llvm_unreachable("Bad RelocModel.");
}
#if LLVM_RUSTLLVM
// except according to those terms.
// aux-build:attribute-with-error.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:attributes-included.rs
+// ignore-stage1
#![feature(proc_macro, rustc_attrs)]
+#![warn(unused)]
extern crate attributes_included;
// except according to those terms.
// aux-build:derive-bad.rs
+// ignore-stage1
#[macro_use]
extern crate derive_bad;
// except according to those terms.
// aux-build:derive-unstable-2.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:derive-unstable.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:issue_38586.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:derive-b.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:bang_proc_macro2.rs
+// ignore-stage1
#![feature(proc_macro)]
#![allow(unused_macros)]
// except according to those terms.
// aux-build:derive-b.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
#![feature(box_syntax)]
+#![allow(warnings)]
const CON : Box<i32> = box 0; //~ ERROR E0010
//~| NOTE allocation not allowed in
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(warnings)]
+
static A: u32 = 0;
static B: u32 = A;
//~^ ERROR E0394
// compile-flags: --cap-lints deny
+#![warn(unused)]
#![deny(warnings)]
use std::option; //~ ERROR
// compile-flags: --cap-lints warn
+#![warn(unused)]
#![deny(warnings)]
#![feature(rustc_attrs)]
// gate-test-drop_types_in_const
+#![allow(warnings)]
#![feature(box_syntax)]
use std::marker;
// Evaluation of constants in refutable patterns goes through
// different compiler control-flow paths.
-#![allow(unused_imports)]
+#![allow(unused_imports, warnings)]
use std::fmt;
use std::{i8, i16, i32, i64, isize};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(warnings)]
+
const x: bool = match Some(true) {
Some(value) => true,
//~^ ERROR: constant contains unimplemented expression type [E0019]
impl<T> Drop for Foo<T> {
#[unsafe_destructor_blind_to_params] // This is the UGEH attribute
//~^ ERROR unsafe_destructor_blind_to_params has been replaced
- //~^^ WARN: use of deprecated attribute
fn drop(&mut self) { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(safe_extern_statics, warnings)]
+
extern {
pub static symbol: ();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(safe_extern_statics)]
+
mod Y {
pub type X = usize;
extern {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(dead_code)]
+#![allow(dead_code, warnings)]
static mut x: isize = 3;
static mut y: isize = unsafe {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused)]
#[deny(warnings)]
const foo: isize = 3;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(warnings)]
+
struct Struct { a: usize }
const C: usize = 1;
}
impl<'a> A<'a> for B {
- fn foo<F>(&mut self, f: F) //~ ERROR E0276
+ fn foo<F>(&mut self, f: F) //~ ERROR impl has stricter
//~^ WARNING future release
where F: fmt::Debug + 'static,
{
// aux-build:lint_stability.rs
-#![allow(unused_imports)]
+#![allow(warnings)]
extern crate lint_stability;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(warnings)]
+
const X: u8 =
|| -> u8 { 5 }()
//~^ ERROR calls in constants are limited to constant functions
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(safe_extern_statics)]
+
extern {
static error_message_count: u32;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused)]
#![deny(warnings)] //~ NOTE: lint level defined here
use std::thread;
//~^ ERROR: unused import
// except according to those terms.
#![feature(rustc_attrs)]
+#![warn(unused)]
type Z = for<'x> Send;
//~^ WARN type alias is never used
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo() -> bool {
+ break true; //~ ERROR E0268
+}
+
+fn main() {
+ break {}; //~ ERROR E0268
+}
#![feature(box_syntax)]
#![feature(const_fn)]
+#![allow(warnings)]
use std::cell::RefCell;
// No warnings about removed lint when
// allow(renamed_and_removed_lints)
+#![allow(renamed_and_removed_lints)]
+
#[deny(raw_pointer_derive)]
-#[allow(renamed_and_removed_lints)]
#[deny(unused_variables)]
fn main() { let unused = (); } //~ ERROR unused
// error-pattern:lint raw_pointer_derive has been removed
// error-pattern:requested on the command line with `-D raw_pointer_derive`
+#![warn(unused)]
+
#[deny(warnings)]
fn main() { let unused = (); }
// No warnings about renamed lint when
// allow(renamed_and_removed_lints)
+#![allow(renamed_and_removed_lints)]
+
#[deny(unknown_features)]
-#[allow(renamed_and_removed_lints)]
#[deny(unused)]
fn main() { let unused = (); } //~ ERROR unused
// aux-build:stability_cfg1.rs
// aux-build:stability_cfg2.rs
-#![deny(deprecated)]
+#![warn(deprecated)]
#![allow(dead_code)]
-#![feature(staged_api, test_feature)]
+#![feature(staged_api, test_feature, rustc_attrs)]
#![stable(feature = "rust1", since = "1.0.0")]
type Foo = MethodTester;
let foo = MethodTester;
- deprecated(); //~ ERROR use of deprecated item
- foo.method_deprecated(); //~ ERROR use of deprecated item
- Foo::method_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo>::method_deprecated(&foo); //~ ERROR use of deprecated item
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
-
- deprecated_text(); //~ ERROR use of deprecated item: text
- foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
- Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
-
- deprecated_unstable(); //~ ERROR use of deprecated item
- foo.method_deprecated_unstable(); //~ ERROR use of deprecated item
- Foo::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- <Foo>::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item
- Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- <Foo>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- <Foo as Trait>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
-
- deprecated_unstable_text(); //~ ERROR use of deprecated item: text
- foo.method_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
- Foo::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
- foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
- Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
- <Foo as Trait>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ deprecated(); //~ WARN use of deprecated item
+ foo.method_deprecated(); //~ WARN use of deprecated item
+ Foo::method_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo>::method_deprecated(&foo); //~ WARN use of deprecated item
+ foo.trait_deprecated(); //~ WARN use of deprecated item
+ Trait::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ WARN use of deprecated item
+
+ deprecated_text(); //~ WARN use of deprecated item: text
+ foo.method_deprecated_text(); //~ WARN use of deprecated item: text
+ Foo::method_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::method_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ foo.trait_deprecated_text(); //~ WARN use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+
+ deprecated_unstable(); //~ WARN use of deprecated item
+ foo.method_deprecated_unstable(); //~ WARN use of deprecated item
+ Foo::method_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ <Foo>::method_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ foo.trait_deprecated_unstable(); //~ WARN use of deprecated item
+ Trait::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ <Foo>::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ <Foo as Trait>::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item
+
+ deprecated_unstable_text(); //~ WARN use of deprecated item: text
+ foo.method_deprecated_unstable_text(); //~ WARN use of deprecated item: text
+ Foo::method_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::method_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
+ foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item: text
+ Trait::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
unstable();
foo.method_unstable();
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
- //~^ ERROR use of deprecated item
+ //~^ WARN use of deprecated item
- let _ = DeprecatedStruct { //~ ERROR use of deprecated item
- i: 0 //~ ERROR use of deprecated item
+ let _ = DeprecatedStruct { //~ WARN use of deprecated item
+ i: 0 //~ WARN use of deprecated item
};
let _ = DeprecatedUnstableStruct {
- //~^ ERROR use of deprecated item
- i: 0 //~ ERROR use of deprecated item
+ //~^ WARN use of deprecated item
+ i: 0 //~ WARN use of deprecated item
};
let _ = UnstableStruct { i: 0 };
let _ = StableStruct { i: 0 };
- let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
- let _ = DeprecatedUnstableUnitStruct; //~ ERROR use of deprecated item
+ let _ = DeprecatedUnitStruct; //~ WARN use of deprecated item
+ let _ = DeprecatedUnstableUnitStruct; //~ WARN use of deprecated item
let _ = UnstableUnitStruct;
let _ = StableUnitStruct;
- let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
- let _ = Enum::DeprecatedUnstableVariant; //~ ERROR use of deprecated item
+ let _ = Enum::DeprecatedVariant; //~ WARN use of deprecated item
+ let _ = Enum::DeprecatedUnstableVariant; //~ WARN use of deprecated item
let _ = Enum::UnstableVariant;
let _ = Enum::StableVariant;
- let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
- let _ = DeprecatedUnstableTupleStruct (1); //~ ERROR use of deprecated item
+ let _ = DeprecatedTupleStruct (1); //~ WARN use of deprecated item
+ let _ = DeprecatedUnstableTupleStruct (1); //~ WARN use of deprecated item
let _ = UnstableTupleStruct (1);
let _ = StableTupleStruct (1);
// Eventually, we will want to lint the contents of the
// macro in the module *defining* it. Also, stability levels
// on macros themselves are not yet linted.
- macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text
- macro_test_arg!(deprecated_unstable_text()); //~ ERROR use of deprecated item: text
- macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text
+ macro_test_arg!(deprecated_text()); //~ WARN use of deprecated item: text
+ macro_test_arg!(deprecated_unstable_text()); //~ WARN use of deprecated item: text
+ macro_test_arg!(macro_test_arg!(deprecated_text())); //~ WARN use of deprecated item: text
}
fn test_method_param<Foo: Trait>(foo: Foo) {
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item
- Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- <Foo>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- <Foo as Trait>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
- foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
- Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
- <Foo as Trait>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ foo.trait_deprecated(); //~ WARN use of deprecated item
+ Trait::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ WARN use of deprecated item
+ foo.trait_deprecated_text(); //~ WARN use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ foo.trait_deprecated_unstable(); //~ WARN use of deprecated item
+ Trait::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ <Foo>::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ <Foo as Trait>::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item
+ foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item: text
+ Trait::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text
foo.trait_unstable();
Trait::trait_unstable(&foo);
<Foo>::trait_unstable(&foo);
}
fn test_method_object(foo: &Trait) {
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item
- foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
+ foo.trait_deprecated(); //~ WARN use of deprecated item
+ foo.trait_deprecated_text(); //~ WARN use of deprecated item: text
+ foo.trait_deprecated_unstable(); //~ WARN use of deprecated item
+ foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item: text
foo.trait_unstable();
foo.trait_unstable_text();
foo.trait_stable();
struct S;
impl UnstableTrait for S { }
- impl DeprecatedTrait for S {} //~ ERROR use of deprecated item: text
+ impl DeprecatedTrait for S {} //~ WARN use of deprecated item: text
trait LocalTrait : UnstableTrait { }
- trait LocalTrait2 : DeprecatedTrait { } //~ ERROR use of deprecated item: text
+ trait LocalTrait2 : DeprecatedTrait { } //~ WARN use of deprecated item: text
impl Trait for S {
fn trait_stable(&self) {}
stable_mod::unstable();
stable_mod::stable();
- unstable_mod::deprecated(); //~ ERROR use of deprecated item
+ unstable_mod::deprecated(); //~ WARN use of deprecated item
unstable_mod::unstable();
let _ = Unstable::UnstableVariant;
type Foo = MethodTester;
let foo = MethodTester;
- deprecated(); //~ ERROR use of deprecated item
- foo.method_deprecated(); //~ ERROR use of deprecated item
- Foo::method_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo>::method_deprecated(&foo); //~ ERROR use of deprecated item
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
-
- deprecated_text(); //~ ERROR use of deprecated item: text
- foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
- Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ deprecated(); //~ WARN use of deprecated item
+ foo.method_deprecated(); //~ WARN use of deprecated item
+ Foo::method_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo>::method_deprecated(&foo); //~ WARN use of deprecated item
+ foo.trait_deprecated(); //~ WARN use of deprecated item
+ Trait::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ WARN use of deprecated item
+
+ deprecated_text(); //~ WARN use of deprecated item: text
+ foo.method_deprecated_text(); //~ WARN use of deprecated item: text
+ Foo::method_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::method_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ foo.trait_deprecated_text(); //~ WARN use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
unstable();
foo.method_unstable();
<Foo as Trait>::trait_stable_text(&foo);
let _ = DeprecatedStruct {
- //~^ ERROR use of deprecated item
- i: 0 //~ ERROR use of deprecated item
+ //~^ WARN use of deprecated item
+ i: 0 //~ WARN use of deprecated item
};
let _ = UnstableStruct { i: 0 };
let _ = StableStruct { i: 0 };
- let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
+ let _ = DeprecatedUnitStruct; //~ WARN use of deprecated item
let _ = UnstableUnitStruct;
let _ = StableUnitStruct;
- let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
+ let _ = Enum::DeprecatedVariant; //~ WARN use of deprecated item
let _ = Enum::UnstableVariant;
let _ = Enum::StableVariant;
- let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
+ let _ = DeprecatedTupleStruct (1); //~ WARN use of deprecated item
let _ = UnstableTupleStruct (1);
let _ = StableTupleStruct (1);
}
fn test_method_param<Foo: Trait>(foo: Foo) {
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
- <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
- <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ foo.trait_deprecated(); //~ WARN use of deprecated item
+ Trait::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ WARN use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ WARN use of deprecated item
+ foo.trait_deprecated_text(); //~ WARN use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text
foo.trait_unstable();
Trait::trait_unstable(&foo);
<Foo>::trait_unstable(&foo);
}
fn test_method_object(foo: &Trait) {
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+ foo.trait_deprecated(); //~ WARN use of deprecated item
+ foo.trait_deprecated_text(); //~ WARN use of deprecated item: text
foo.trait_unstable();
foo.trait_unstable_text();
foo.trait_stable();
#[rustc_deprecated(since = "1.0.0", reason = "text")]
fn test_fn_body() {
fn fn_in_body() {}
- fn_in_body(); //~ ERROR use of deprecated item: text
+ fn_in_body(); //~ WARN use of deprecated item: text
}
impl MethodTester {
#[rustc_deprecated(since = "1.0.0", reason = "text")]
fn test_method_body(&self) {
fn fn_in_body() {}
- fn_in_body(); //~ ERROR use of deprecated item: text
+ fn_in_body(); //~ WARN use of deprecated item: text
}
}
struct S;
- impl DeprecatedTrait for S { } //~ ERROR use of deprecated item
+ impl DeprecatedTrait for S { } //~ WARN use of deprecated item
- trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item
+ trait LocalTrait : DeprecatedTrait { } //~ WARN use of deprecated item
}
-fn main() {}
+#[rustc_error] fn main() {} //~ ERROR: compilation successful
// except according to those terms.
//
-#![deny(overflowing_literals)]
-#![deny(const_err)]
+#![warn(overflowing_literals)]
+#![warn(const_err)]
+#![feature(rustc_attrs)]
#[allow(unused_variables)]
-fn main() {
- let x2: i8 = --128; //~ error: literal out of range for i8
- //~^ error: attempt to negate with overflow
+#[rustc_error]
+fn main() { //~ ERROR: compilation successful
+ let x2: i8 = --128; //~ warn: literal out of range for i8
+ //~^ warn: attempt to negate with overflow
- let x = -3.40282357e+38_f32; //~ error: literal out of range for f32
- let x = 3.40282357e+38_f32; //~ error: literal out of range for f32
- let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
- let x = 1.7976931348623159e+308_f64; //~ error: literal out of range for f64
+ let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32
+ let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32
+ let x = -1.7976931348623159e+308_f64; //~ warn: literal out of range for f64
+ let x = 1.7976931348623159e+308_f64; //~ warn: literal out of range for f64
}
let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable
fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable
+ let mut a = &mut 5; //~ ERROR: variable does not need to be mutable
+ *a = 4;
+
+ let mut a = 5;
+ let mut b = (&mut a,);
+ *b.0 = 4; //~^ ERROR: variable does not need to be mutable
+
+ let mut x = &mut 1; //~ ERROR: variable does not need to be mutable
+ let mut f = || {
+ *x += 1;
+ };
+ f();
+
+ fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
+ &mut arg[..] //~^ ERROR: variable does not need to be mutable
+ }
+
+ let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable
+ v.push(());
+
// positive cases
let mut a = 2;
a = 3;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused)]
#![allow(dead_code)]
#![deny(non_snake_case)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused)]
#![deny(unused_variables)]
#![deny(unused_assignments)]
#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)]
// Test that an assignment of type ! makes the rest of the block dead code.
-#![feature(never_type)]
-#![deny(unused, unreachable_code)]
+#![feature(never_type, rustc_attrs)]
+#![warn(unused)]
-fn main() {
- let x: ! = panic!("aah"); //~ ERROR unused
- drop(x); //~ ERROR unreachable
- //~^ ERROR unreachable
+#[rustc_error]
+fn main() { //~ ERROR: compilation successful
+ let x: ! = panic!("aah"); //~ WARN unused
+ drop(x); //~ WARN unreachable
+ //~^ WARN unreachable
}
-
#![feature(associated_consts)]
#![feature(conservative_impl_trait)]
#![feature(decl_macro)]
+#![allow(warnings)]
mod m {
fn priv_fn() {}
// aux-build:private-inferred-type.rs
#![feature(conservative_impl_trait)]
+#![allow(warnings)]
extern crate private_inferred_type as ext;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ println!("{}", __rust_unstable_column!());
+ //~^ERROR the __rust_unstable_column macro is unstable
+}
static mut a: Box<isize> = box 3;
//~^ ERROR allocations are not allowed in statics
-//~^^ ERROR destructors in statics are an unstable feature
+//~| ERROR destructors in statics are an unstable feature
+//~| WARN: constant evaluation error
fn main() {}
}
impl<T> Foo<T> {
- fn new<U>(u: U) -> Foo<U> {
+ fn new<U>(u: U) -> Foo<U> { //~ NOTE expected `Foo<U>` because of return type
Self {
//~^ ERROR mismatched types
- //~| expected type parameter, found a different type parameter
- //~| expected type `Foo<U>`
- //~| found type `Foo<T>`
+ //~| NOTE expected type parameter, found a different type parameter
+ //~| NOTE expected type `Foo<U>`
inner: u
//~^ ERROR mismatched types
- //~| expected type parameter, found a different type parameter
- //~| expected type `T`
- //~| found type `U`
+ //~| NOTE expected type parameter, found a different type parameter
+ //~| NOTE expected type `T`
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(never_type)]
-#![deny(unreachable_code)]
-#![deny(unreachable_patterns)]
+#![feature(never_type, rustc_attrs)]
+#![warn(unreachable_code)]
+#![warn(unreachable_patterns)]
enum Void {}
fn foo(x: Result<!, i32>) -> Result<u32, i32> {
let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?;
- //~^ ERROR unreachable pattern
- //~| ERROR unreachable expression
+ //~^ WARN unreachable pattern
+ //~| WARN unreachable expression
Ok(y)
}
fn vom(x: Result<u32, Void>) -> Result<u32, i32> {
let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?;
- //~^ ERROR unreachable pattern
+ //~^ WARN unreachable pattern
Ok(y)
}
-fn main() {
+#[rustc_error]
+fn main() { //~ ERROR: compilation successful
let _ = bar(Err(123));
let _ = foo(Err(123));
let _ = qux(Ok(123));
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Z verbose -Z mir-emit-validate=1
+// compile-flags: -Z verbose -Z mir-emit-validate=1 -Z span_free_formats
struct Test(i32);
fn main() {
let mut x = 0;
- Test(0).foo(&mut x);
+ Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor
// Also test closures
let c = |x: &mut i32| { let y = &*x; *y };
c(&mut x);
}
-// FIXME: Also test code generated inside the closure, make sure it has validation. Unfortunately,
-// the interesting lines of code also contain name of the source file, so we cannot test for it.
-
// END RUST SOURCE
// START rustc.node12.EraseRegions.after.mir
// bb0: {
// }
// }
// END rustc.node23.EraseRegions.after.mir
+// START rustc.node50.EraseRegions.after.mir
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_1/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_1/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// StorageLive(_3);
+// _3 = _2;
+// StorageLive(_4);
+// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 }))), [(*_3): i32]);
+// _4 = &ReErased (*_3);
+// Validate(Acquire, [(*_4): i32/ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 })) (imm)]);
+// StorageLive(_5);
+// _5 = (*_4);
+// _0 = _5;
+// StorageDead(_5);
+// StorageDead(_4);
+// EndRegion(ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 })));
+// StorageDead(_3);
+// return;
+// }
+// }
+// END rustc.node50.EraseRegions.after.mir
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Z verbose -Z mir-emit-validate=1
+// compile-flags: -Z verbose -Z mir-emit-validate=1 -Z span_free_formats
// Make sure unsafe fns and fns with an unsafe block only get restricted validation.
// }
// }
// END rustc.node4.EraseRegions.after.mir
+// START rustc.node22.EraseRegions.after.mir
+// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483659) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483659) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+// StorageLive(_3);
+// _3 = _2;
+// (*_3) = const 23i32;
+// StorageDead(_3);
+// return;
+// }
+// }
+// END rustc.node22.EraseRegions.after.mir
// START rustc.node31.EraseRegions.after.mir
// fn test(_1: &ReErased mut i32) -> () {
// bb0: {
// }
// }
// END rustc.node31.EraseRegions.after.mir
+// START rustc.node60.EraseRegions.after.mir
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// StorageLive(_3);
+// _0 = const write_42(_4) -> bb1;
+// }
+// }
+// END rustc.node60.EraseRegions.after.mir
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Z verbose -Z mir-emit-validate=2
+// compile-flags: -Z verbose -Z mir-emit-validate=2 -Z span_free_formats
-// Make sure unsafe fns and fns with an unsafe block only get full validation.
+// Make sure unsafe fns and fns with an unsafe block still get full validation.
unsafe fn write_42(x: *mut i32) -> bool {
*x = 42;
test(&mut 0);
let test_closure = unsafe { |x: &mut i32| write_42(x) };
+ // Note that validation will fail if this is executed: The closure keeps the lock on
+ // x, so the write in write_42 fails. This test just checks code generation,
+ // so the UB doesn't matter.
test_closure(&mut 0);
}
-// FIXME: Also test code generated inside the closure, make sure it has validation. Unfortunately,
-// the interesting lines of code also contain name of the source file, so we cannot test for it.
-
// END RUST SOURCE
// START rustc.node17.EraseRegions.after.mir
// fn test(_1: &ReErased mut i32) -> () {
// }
// }
// END rustc.node17.EraseRegions.after.mir
+// START rustc.node46.EraseRegions.after.mir
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
+// bb0: {
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483660) => validate_5/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483660) => validate_5/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// StorageLive(_3);
+// _3 = _2;
+// StorageLive(_4);
+// StorageLive(_5);
+// Validate(Suspend(ReScope(Misc(NodeId(44)))), [(*_3): i32]);
+// _5 = &ReErased mut (*_3);
+// Validate(Acquire, [(*_5): i32/ReScope(Misc(NodeId(44)))]);
+// _4 = _5 as *mut i32 (Misc);
+// StorageDead(_5);
+// EndRegion(ReScope(Misc(NodeId(44))));
+// Validate(Release, [_0: bool, _4: *mut i32]);
+// _0 = const write_42(_4) -> bb1;
+// }
+// }
+// END rustc.node46.EraseRegions.after.mir
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) a.rs && $(RUSTC) b.rs
$(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \
--out-dir=$(TMPDIR)
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) foo.rs; $(RUSTC) bar.rs
$(RUSTDOC) baz.rs -L $(TMPDIR) -o $(TMPDIR)
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
# Windows doesn't correctly handle include statements with escaping paths,
# so this test will not get run on Windows.
ifdef IS_WINDOWS
$(TMPDIR)/libllvm-module-pass.o:
$(CXX) $(CFLAGS) $(LLVM_CXXFLAGS) -c llvm-module-pass.so.cc -o $(TMPDIR)/libllvm-module-pass.o
endif
+
+endif
-include ../tools.mk
+ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
+# ignore stage1
+all:
+
+else
all:
$(RUSTC) foo.rs
$(RUSTC) bar.rs --emit dep-info
grep "proc-macro source" $(TMPDIR)/bar.d && exit 1 || exit 0
+endif
// except according to those terms.
// aux-build:custom_derive_plugin.rs
+// ignore-stage1
#![feature(plugin, custom_derive)]
#![plugin(custom_derive_plugin)]
// except according to those terms.
// aux-build:add-impl.rs
+// ignore-stage1
#[macro_use]
extern crate add_impl;
// except according to those terms.
// aux-build:append-impl.rs
+// ignore-stage1
#![allow(warnings)]
// except according to those terms.
// aux-build:attr-args.rs
+// ignore-stage1
#![allow(warnings)]
#![feature(proc_macro)]
// except according to those terms.
// aux-build:bang-macro.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:count_compound_ops.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:double.rs
+// ignore-stage1
#![allow(unused)]
// except according to those terms.
// aux-build:derive-same-struct.rs
+// ignore-stage1
#[macro_use]
extern crate derive_same_struct;
// aux-build:hygiene_example_codegen.rs
// aux-build:hygiene_example.rs
+// ignore-stage1
#![feature(proc_macro)]
// except according to those terms.
// aux-build:issue-39889.rs
+// ignore-stage1
#![feature(proc_macro)]
#![allow(unused)]
// except according to those terms.
// aux-build:issue-40001-plugin.rs
+// ignore-stage1
#![feature(proc_macro, plugin)]
#![plugin(issue_40001_plugin)]
// aux-build:derive-atob.rs
// aux-build:derive-ctod.rs
+// ignore-stage1
#[macro_use]
extern crate derive_atob;
// aux-build:derive-a.rs
// aux-build:derive-reexport.rs
+// ignore-stage1
#[macro_use]
extern crate derive_reexport;
--- /dev/null
+// Copyright 2017 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.
+
+#![allow(unused)]
+
+macro_rules! column {
+ ($i:ident) => {
+ $i
+ };
+}
+
+fn foo() -> ! {
+ panic!();
+}
+
+fn main() {}
panic!("from outer");
};
assert_eq!(break_from_while_to_outer, 567);
+
+ let rust = true;
+ let value = loop {
+ break rust;
+ };
+ assert!(value);
}
assert!(g != h);
assert!(g != i);
assert!(h != i);
+
+ // Make sure lifetime anonymization handles nesting correctly
+ let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>();
+ let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>();
+ assert_eq!(j, k);
}
// Boxed unboxed closures
{
String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
}
+fn union() {
+ union union<'union> { union: &'union union<'union>, }
+}
+
pub fn main() {
strange();
funny();
dots();
you_eight();
fishy();
+ union();
}
// compile-flags: -A test-lint
#![feature(plugin)]
+#![warn(unused)]
#![plugin(lint_plugin_test)]
fn lintme() { }
warning: function is never used: `lintme`
- --> $DIR/lint-plugin-cmdline-allow.rs:19:1
+ --> $DIR/lint-plugin-cmdline-allow.rs:20:1
|
-19 | fn lintme() { }
+20 | fn lintme() { }
| ^^^^^^^^^^^^^^^
|
- = note: #[warn(dead_code)] on by default
+note: lint level defined here
+ --> $DIR/lint-plugin-cmdline-allow.rs:17:9
+ |
+17 | #![warn(unused)]
+ | ^^^^^^
+ = note: #[warn(dead_code)] implied by #[warn(unused)]
error[E0308]: mismatched types
--> $DIR/block-must-not-have-result-res.rs:15:9
|
+14 | fn drop(&mut self) {
+ | - expected `()` because of default return type
15 | true //~ ERROR mismatched types
| ^^^^ expected (), found bool
|
error[E0308]: mismatched types
--> $DIR/issue-13624.rs:17:5
|
+16 | pub fn get_enum_struct_variant() -> () {
+ | -- expected `()` because of return type
17 | Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
|
error[E0308]: mismatched types
--> $DIR/issue-22645.rs:25:3
|
+23 | fn main() {
+ | - expected `()` because of default return type
+24 | let b = Bob + 3.5;
25 | b + 3 //~ ERROR E0277
| ^^^^^ expected (), found struct `Bob`
|
error[E0308]: mismatched types
--> $DIR/issue-5500.rs:12:5
|
+11 | fn main() {
+ | - expected `()` because of default return type
12 | &panic!()
| ^^^^^^^^^ expected (), found reference
|
// except according to those terms.
#![feature(exclusive_range_pattern)]
+#![warn(unreachable_patterns)]
fn main() {
// These cases should generate no warning.
9...9 => {},
_ => {},
}
-}
\ No newline at end of file
+}
warning: unreachable pattern
- --> $DIR/issue-43253.rs:36:9
+ --> $DIR/issue-43253.rs:37:9
|
-36 | 9 => {},
+37 | 9 => {},
| ^
|
- = note: #[warn(unreachable_patterns)] on by default
+note: lint level defined here
+ --> $DIR/issue-43253.rs:12:9
+ |
+12 | #![warn(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
warning: unreachable pattern
- --> $DIR/issue-43253.rs:42:9
+ --> $DIR/issue-43253.rs:43:9
|
-42 | 8...9 => {},
+43 | 8...9 => {},
| ^^^^^
warning: unreachable pattern
- --> $DIR/issue-43253.rs:48:9
+ --> $DIR/issue-43253.rs:49:9
|
-48 | 9...9 => {},
+49 | 9...9 => {},
| ^^^^^
-error[E0276]: impl has stricter requirements than trait
+error: impl has stricter requirements than trait
--> $DIR/proj-outlives-region.rs:19:5
|
14 | fn foo() where T: 'a;
-error[E0276]: impl has stricter requirements than trait
+error: impl has stricter requirements than trait
--> $DIR/region-unrelated.rs:19:5
|
14 | fn foo() where T: 'a;
--- /dev/null
+// Copyright 2017 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 continue-parse-after-error
+
+extern "C" {
+ const C: u8; //~ ERROR extern items cannot be `const`
+}
+
+fn main() {
+ let x = C;
+}
--- /dev/null
+error: extern items cannot be `const`
+ --> $DIR/extern-const.rs:14:5
+ |
+14 | const C: u8; //~ ERROR extern items cannot be `const`
+ | ^^^^^ help: instead try using: `static`
+
+error: aborting due to previous error
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused_must_use)]
struct MyStruct {
n: usize
warning: unused return value of `need_to_use_this_value` which must be used: it's important
- --> $DIR/fn_must_use.rs:29:5
+ --> $DIR/fn_must_use.rs:30:5
|
-29 | need_to_use_this_value();
+30 | need_to_use_this_value();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: #[warn(unused_must_use)] on by default
+note: lint level defined here
+ --> $DIR/fn_must_use.rs:11:9
+ |
+11 | #![warn(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used
- --> $DIR/fn_must_use.rs:32:5
+ --> $DIR/fn_must_use.rs:33:5
|
-32 | m.need_to_use_this_method_value();
+33 | m.need_to_use_this_method_value();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![forbid(unused, non_snake_case)]
-#[allow(unused, unused_variables, bad_style)]
+#[allow(unused_variables)]
+fn foo() {}
+
+#[allow(unused)]
+fn bar() {}
+
+#[allow(bad_style)]
fn main() {
println!("hello forbidden world")
}
-error[E0453]: allow(unused) overruled by outer forbid(unused)
+error[E0453]: allow(unused_variables) overruled by outer forbid(unused)
--> $DIR/outer-forbid.rs:19:9
|
17 | #![forbid(unused, non_snake_case)]
| ------ `forbid` level set here
18 |
-19 | #[allow(unused, unused_variables, bad_style)]
- | ^^^^^^ overruled by previous forbid
+19 | #[allow(unused_variables)]
+ | ^^^^^^^^^^^^^^^^ overruled by previous forbid
-error[E0453]: allow(unused_variables) overruled by outer forbid(unused)
- --> $DIR/outer-forbid.rs:19:17
+error[E0453]: allow(unused) overruled by outer forbid(unused)
+ --> $DIR/outer-forbid.rs:22:9
|
17 | #![forbid(unused, non_snake_case)]
| ------ `forbid` level set here
-18 |
-19 | #[allow(unused, unused_variables, bad_style)]
- | ^^^^^^^^^^^^^^^^ overruled by previous forbid
+...
+22 | #[allow(unused)]
+ | ^^^^^^ overruled by previous forbid
error[E0453]: allow(bad_style) overruled by outer forbid(non_snake_case)
- --> $DIR/outer-forbid.rs:19:35
+ --> $DIR/outer-forbid.rs:25:9
|
17 | #![forbid(unused, non_snake_case)]
| -------------- `forbid` level set here
-18 |
-19 | #[allow(unused, unused_variables, bad_style)]
- | ^^^^^^^^^ overruled by previous forbid
+...
+25 | #[allow(bad_style)]
+ | ^^^^^^^^^ overruled by previous forbid
error: aborting due to 3 previous errors
error[E0308]: mismatched types
--> $DIR/abridged.rs:26:5
|
+25 | fn a() -> Foo {
+ | --- expected `Foo` because of return type
26 | Some(Foo { bar: 1 })
| ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option`
|
error[E0308]: mismatched types
--> $DIR/abridged.rs:30:5
|
+29 | fn a2() -> Foo {
+ | --- expected `Foo` because of return type
30 | Ok(Foo { bar: 1})
| ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result`
|
error[E0308]: mismatched types
--> $DIR/abridged.rs:34:5
|
+33 | fn b() -> Option<Foo> {
+ | ----------- expected `std::option::Option<Foo>` because of return type
34 | Foo { bar: 1 }
| ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
|
error[E0308]: mismatched types
--> $DIR/abridged.rs:38:5
|
+37 | fn c() -> Result<Foo, Bar> {
+ | ---------------- expected `std::result::Result<Foo, Bar>` because of return type
38 | Foo { bar: 1 }
| ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
|
error[E0308]: mismatched types
--> $DIR/abridged.rs:49:5
|
+41 | fn d() -> X<X<String, String>, String> {
+ | ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
+...
49 | x
| ^ expected struct `std::string::String`, found integral variable
|
error[E0308]: mismatched types
--> $DIR/abridged.rs:60:5
|
+52 | fn e() -> X<X<String, String>, String> {
+ | ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
+...
60 | x
| ^ expected struct `std::string::String`, found integral variable
|
// run-pass
+#![warn(unused)]
+
// Parser test for #37765
fn with_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `with_parens`
warning: unnecessary parentheses around `return` value
- --> $DIR/path-lookahead.rs:16:10
+ --> $DIR/path-lookahead.rs:18:10
|
-16 | return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
+18 | return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_parens)] on by default
warning: function is never used: `with_parens`
- --> $DIR/path-lookahead.rs:15:1
+ --> $DIR/path-lookahead.rs:17:1
|
-15 | / fn with_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `with_parens`
-16 | | return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
-17 | | }
+17 | / fn with_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `with_parens`
+18 | | return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
+19 | | }
| |_^
|
- = note: #[warn(dead_code)] on by default
+note: lint level defined here
+ --> $DIR/path-lookahead.rs:13:9
+ |
+13 | #![warn(unused)]
+ | ^^^^^^
+ = note: #[warn(dead_code)] implied by #[warn(unused)]
warning: function is never used: `no_parens`
- --> $DIR/path-lookahead.rs:19:1
+ --> $DIR/path-lookahead.rs:21:1
|
-19 | / fn no_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `no_parens`
-20 | | return <T as ToString>::to_string(&arg);
-21 | | }
+21 | / fn no_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `no_parens`
+22 | | return <T as ToString>::to_string(&arg);
+23 | | }
| |_^
+error: unreachable expression
+ --> $DIR/expr_unary.rs:18:28
+ |
+18 | let x: ! = ! { return; 22 };
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/expr_unary.rs:14:9
+ |
+14 | #![deny(unreachable_code)]
+ | ^^^^^^^^^^^^^^^^
+
error[E0600]: cannot apply unary operator `!` to type `!`
--> $DIR/expr_unary.rs:18:16
|
18 | let x: ! = ! { return; 22 };
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
//! A test to ensure that helpful `note` messages aren't emitted more often
//! than necessary.
-// Although there are three errors, we should only get two "lint level defined
+#![feature(rustc_attrs)]
+
+// Although there are three warnings, we should only get two "lint level defined
// here" notes pointing at the `warnings` span, one for each error type.
-#![deny(warnings)]
+#![warn(unused)]
+#[rustc_error]
fn main() {
let theTwo = 2;
let theOtherTwo = 2;
-error: variable `theTwo` should have a snake case name such as `the_two`
- --> $DIR/issue-24690.rs:19:9
+warning: unused variable: `theOtherTwo`
+ --> $DIR/issue-24690.rs:23:9
|
-19 | let theTwo = 2;
- | ^^^^^^
+23 | let theOtherTwo = 2;
+ | ^^^^^^^^^^^
|
note: lint level defined here
- --> $DIR/issue-24690.rs:16:9
+ --> $DIR/issue-24690.rs:18:9
|
-16 | #![deny(warnings)]
- | ^^^^^^^^
- = note: #[deny(non_snake_case)] implied by #[deny(warnings)]
+18 | #![warn(unused)]
+ | ^^^^^^
+ = note: #[warn(unused_variables)] implied by #[warn(unused)]
-error: variable `theOtherTwo` should have a snake case name such as `the_other_two`
- --> $DIR/issue-24690.rs:20:9
+warning: variable `theTwo` should have a snake case name such as `the_two`
+ --> $DIR/issue-24690.rs:22:9
|
-20 | let theOtherTwo = 2;
- | ^^^^^^^^^^^
+22 | let theTwo = 2;
+ | ^^^^^^
+ |
+ = note: #[warn(non_snake_case)] on by default
-error: unused variable: `theOtherTwo`
- --> $DIR/issue-24690.rs:20:9
+warning: variable `theOtherTwo` should have a snake case name such as `the_other_two`
+ --> $DIR/issue-24690.rs:23:9
|
-20 | let theOtherTwo = 2;
+23 | let theOtherTwo = 2;
| ^^^^^^^^^^^
- |
-note: lint level defined here
- --> $DIR/issue-24690.rs:16:9
- |
-16 | #![deny(warnings)]
- | ^^^^^^^^
- = note: #[deny(unused_variables)] implied by #[deny(warnings)]
-error: aborting due to 3 previous errors
+error: compilation successful
+ --> $DIR/issue-24690.rs:21:1
+ |
+21 | / fn main() {
+22 | | let theTwo = 2;
+23 | | let theOtherTwo = 2;
+24 | | println!("{}", theTwo);
+25 | | }
+ | |_^
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused)]
+
macro_rules! m {
($a:tt $b:tt) => {
$b $a;
warning: struct is never used: `S`
- --> $DIR/macro-span-replacement.rs:13:9
+ --> $DIR/macro-span-replacement.rs:15:9
|
-13 | $b $a;
+15 | $b $a;
| ^^^^^^
...
-18 | m!(S struct);
+20 | m!(S struct);
| ------------- in this macro invocation
|
- = note: #[warn(dead_code)] on by default
+note: lint level defined here
+ --> $DIR/macro-span-replacement.rs:11:9
+ |
+11 | #![warn(unused)]
+ | ^^^^^^
+ = note: #[warn(dead_code)] implied by #[warn(unused)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![warn(unused)]
+
use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd};
fn main() {
warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd`
- --> $DIR/multispan-import-lint.rs:11:16
+ --> $DIR/multispan-import-lint.rs:13:16
|
-11 | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd};
+13 | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd};
| ^^ ^^^ ^^^^^^^^^ ^^^^^^^^^^
|
- = note: #[warn(unused_imports)] on by default
+note: lint level defined here
+ --> $DIR/multispan-import-lint.rs:11:9
+ |
+11 | #![warn(unused)]
+ | ^^^^^^
+ = note: #[warn(unused_imports)] implied by #[warn(unused)]
--- /dev/null
+// Copyright 2017 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.
+
+mod inner {
+ pub trait Bar {
+ fn method(&self);
+ }
+
+ pub struct Foo;
+
+ impl Foo {
+ fn method(&self) {}
+ }
+
+ impl Bar for Foo {
+ fn method(&self) {}
+ }
+}
+
+fn main() {
+ let foo = inner::Foo;
+ foo.method();
+}
--- /dev/null
+error[E0624]: method `method` is private
+ --> $DIR/trait-method-private.rs:29:9
+ |
+29 | foo.method();
+ | ^^^^^^
+ |
+ = help: items from traits can only be used if the trait is in scope
+ = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+ candidate #1: `use inner::Bar;`
+
+error: aborting due to previous error
+
-Subproject commit 305bc25d5e105e84ffe261655b46cf74570f6e5b
+Subproject commit 7704f7b1fd52607104cc7fdc435d636c9de1fe90
fn compile_test(&self) -> ProcRes {
let aux_dir = self.aux_output_dir_name();
// FIXME (#9639): This needs to handle non-utf8 paths
- let link_args = vec!["-L".to_owned(),
- aux_dir.to_str().unwrap().to_owned()];
- let args = self.make_compile_args(link_args,
+ let mut extra_args = vec!["-L".to_owned(),
+ aux_dir.to_str().unwrap().to_owned()];
+ match self.config.mode {
+ CompileFail | Ui => {
+ // compile-fail and ui tests tend to have tons of unused code as
+ // it's just testing various pieces of the compile, but we don't
+ // want to actually assert warnings about all this code. Instead
+ // let's just ignore unused code warnings by defaults and tests
+ // can turn it back on if needed.
+ extra_args.push("-A".to_owned());
+ extra_args.push("unused".to_owned());
+ }
+ _ => {}
+ }
+ let args = self.make_compile_args(extra_args,
&self.testpaths.file,
TargetLocation::ThisFile(self.make_exe_name()));
self.compose_and_run_compiler(args, None)
"src/libstd/path.rs",
"src/libstd/f32.rs",
"src/libstd/f64.rs",
+ "src/libstd/lib.rs", // Until next stage0 snapshot bump
"src/libstd/sys_common/mod.rs",
"src/libstd/sys_common/net.rs",
"src/libterm", // Not sure how to make this crate portable, but test needs it
=> state = EXP_END,
(EXP_URL, w)
- if w.starts_with("http://") || w.starts_with("https://")
+ if w.starts_with("http://") || w.starts_with("https://") || w.starts_with("../")
=> state = EXP_END,
(_, _) => return false,