# =============================================================================
[rust]
-# Indicates that the build should be optimized for debugging Rust. Note that
-# this is typically not what you want as it takes an incredibly large amount of
-# time to have a debug-mode rustc compile any code (notably libstd). If this
-# value is set to `true` it will affect a number of configuration options below
-# as well, if unconfigured.
-#debug = false
-
-# Whether or not to optimize the compiler and standard library
+# Whether or not to optimize the compiler and standard library.
+#
# Note: the slowness of the non optimized compiler compiling itself usually
# outweighs the time gains in not doing optimizations, therefore a
-# full bootstrap takes much more time with optimize set to false.
+# full bootstrap takes much more time with `optimize` set to false.
#optimize = true
+# Indicates that the build should be configured for debugging Rust. A
+# `debug`-enabled compiler and standard library will be somewhat
+# slower (due to e.g. checking of debug assertions) but should remain
+# usable.
+#
+# Note: If this value is set to `true`, it will affect a number of
+# configuration options below as well, if they have been left
+# unconfigured in this file.
+#
+# Note: changes to the `debug` setting do *not* affect `optimize`
+# above. In theory, a "maximally debuggable" environment would
+# set `optimize` to `false` above to assist the introspection
+# facilities of debuggers like lldb and gdb. To recreate such an
+# environment, explicitly set `optimize` to `false` and `debug`
+# to `true`. In practice, everyone leaves `optimize` set to
+# `true`, because an unoptimized rustc with debugging
+# enabled becomes *unusably slow* (e.g. rust-lang/rust#24840
+# reported a 25x slowdown) and bootstrapping the supposed
+# "maximally debuggable" environment (notably libstd) takes
+# hours to build.
+#
+#debug = false
+
# Number of codegen units to use for each compiler invocation. A value of 0
# means "the number of cores on this machine", and 1+ is passed through to the
# compiler.
[[package]]
name = "chalk-engine"
-version = "0.7.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "minifier"
-version = "0.0.19"
+version = "0.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fmt_macros 0.0.0",
"graphviz 0.0.0",
version = "0.0.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
name = "rustdoc"
version = "0.0.0"
dependencies = [
- "minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
-"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0"
+"checksum chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6749eb72e7d4355d944a99f15fbaea701b978c18c5e184a025fcde942b0c9779"
"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
-"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11"
+"checksum minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "96c269bb45c39b333392b2b18ad71760b34ac65666591386b0e959ed58b3f474"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
let default = false;
config.llvm_assertions = llvm_assertions.unwrap_or(default);
+ let default = true;
+ config.rust_optimize = optimize.unwrap_or(default);
+
let default = match &config.channel[..] {
"stable" | "beta" | "nightly" => true,
_ => false,
config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
config.rust_debuginfo = debuginfo.unwrap_or(default);
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
- config.rust_optimize = optimize.unwrap_or(!default);
let default = config.channel == "dev";
config.ignore_git = ignore_git.unwrap_or(default);
output.status.success()
}
-pub fn gnu_target(target: &str) -> String {
+pub fn gnu_target(target: &str) -> &str {
match target {
- "i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
- "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
- "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
- "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
- s => s.to_string(),
+ "i686-pc-windows-msvc" => "i686-pc-win32",
+ "x86_64-pc-windows-msvc" => "x86_64-pc-win32",
+ "i686-pc-windows-gnu" => "i686-w64-mingw32",
+ "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
+ s => s,
}
}
--- /dev/null
+# `cfg_attr_multi`
+
+The tracking issue for this feature is: [#54881]
+The RFC for this feature is: [#2539]
+
+[#54881]: https://github.com/rust-lang/rust/issues/54881
+[#2539]: https://github.com/rust-lang/rfcs/pull/2539
+
+------------------------
+
+This feature flag lets you put multiple attributes into a `cfg_attr` attribute.
+
+Example:
+
+```rust,ignore
+#[cfg_attr(all(), must_use, optimize)]
+```
+
+Because `cfg_attr` resolves before procedural macros, this does not affect
+macro resolution at all.
\ No newline at end of file
+++ /dev/null
-# `tool_lints`
-
-The tracking issue for this feature is: [#44690]
-
-[#44690]: https://github.com/rust-lang/rust/issues/44690
-
-------------------------
-
-Tool lints let you use scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of
-certain tools.
-
-Currently `clippy` is the only available lint tool.
-
-It is recommended for lint tools to implement the scoped lints like this:
-
-- `#[_(TOOL_NAME::lintname)]`: for lint names
-- `#[_(TOOL_NAME::lintgroup)]`: for groups of lints
-- `#[_(TOOL_NAME::all)]`: for (almost[^1]) all lints
-
-## An example
-
-```rust
-#![feature(tool_lints)]
-
-#![warn(clippy::pedantic)]
-
-#[allow(clippy::filter_map)]
-fn main() {
- let v = vec![0; 10];
- let _ = v.into_iter().filter(|&x| x < 1).map(|x| x + 1).collect::<Vec<_>>();
- println!("No filter_map()!");
-}
-```
-
-[^1]: Some defined lint groups can be excluded here.
def children(self):
(length, data_ptr) = \
rustpp.extract_length_and_ptr_from_std_btreeset(self.__val)
- val = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
- gdb_ptr = val.get_wrapped_value()
+ leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
+ maybe_uninit_keys = leaf_node.get_child_at_index(3)
+ manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
+ keys = manually_drop_keys.get_child_at_index(0)
+ gdb_ptr = keys.get_wrapped_value()
for index in xrange(length):
yield (str(index), gdb_ptr[index])
def children(self):
(length, data_ptr) = \
rustpp.extract_length_and_ptr_from_std_btreemap(self.__val)
- keys = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
+ leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
+ maybe_uninit_keys = leaf_node.get_child_at_index(3)
+ manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
+ keys = manually_drop_keys.get_child_at_index(0)
keys_ptr = keys.get_wrapped_value()
- vals = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(4)
+ maybe_uninit_vals = leaf_node.get_child_at_index(4)
+ manually_drop_vals = maybe_uninit_vals.get_child_at_index(1)
+ vals = manually_drop_vals.get_child_at_index(0)
vals_ptr = vals.get_wrapped_value()
for index in xrange(length):
yield (str(index), keys_ptr[index])
// This implies that even an empty internal node has at least one edge.
use core::marker::PhantomData;
-use core::mem;
+use core::mem::{self, MaybeUninit};
use core::ptr::{self, Unique, NonNull};
use core::slice;
/// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned
/// case.
///
-/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
-/// avoiding accidentally dropping unused and uninitialized keys and values.
-///
/// We put the metadata first so that its position is the same for every `K` and `V`, in order
/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
/// prevent them from being reordered.
/// This node's index into the parent node's `edges` array.
/// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
/// This is only guaranteed to be initialized when `parent` is nonnull.
- parent_idx: u16,
+ parent_idx: MaybeUninit<u16>,
/// The number of keys and values this node stores.
///
/// The arrays storing the actual data of the node. Only the first `len` elements of each
/// array are initialized and valid.
- keys: [K; CAPACITY],
- vals: [V; CAPACITY],
+ keys: MaybeUninit<[K; CAPACITY]>,
+ vals: MaybeUninit<[V; CAPACITY]>,
}
impl<K, V> LeafNode<K, V> {
LeafNode {
// As a general policy, we leave fields uninitialized if they can be, as this should
// be both slightly faster and easier to track in Valgrind.
- keys: mem::uninitialized(),
- vals: mem::uninitialized(),
+ keys: MaybeUninit::uninitialized(),
+ vals: MaybeUninit::uninitialized(),
parent: ptr::null(),
- parent_idx: mem::uninitialized(),
+ parent_idx: MaybeUninit::uninitialized(),
len: 0
}
}
// ever take a pointer past the first key.
static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
parent: ptr::null(),
- parent_idx: 0,
+ parent_idx: MaybeUninit::uninitialized(),
len: 0,
- keys: [(); CAPACITY],
- vals: [(); CAPACITY],
+ keys: MaybeUninit::uninitialized(),
+ vals: MaybeUninit::uninitialized(),
};
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
root: self.root,
_marker: PhantomData
},
- idx: self.as_leaf().parent_idx as usize,
+ idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) },
_marker: PhantomData
})
} else {
// the node, which is allowed by LLVM.
unsafe {
slice::from_raw_parts(
- self.as_leaf().keys.as_ptr(),
+ self.as_leaf().keys.as_ptr() as *const K,
self.len()
)
}
debug_assert!(!self.is_shared_root());
unsafe {
slice::from_raw_parts(
- self.as_leaf().vals.as_ptr(),
+ self.as_leaf().vals.as_ptr() as *const V,
self.len()
)
}
} else {
unsafe {
slice::from_raw_parts_mut(
- &mut self.as_leaf_mut().keys as *mut [K] as *mut K,
+ self.as_leaf_mut().keys.get_mut() as *mut [K] as *mut K,
self.len()
)
}
debug_assert!(!self.is_shared_root());
unsafe {
slice::from_raw_parts_mut(
- &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+ self.as_leaf_mut().vals.get_mut() as *mut [V] as *mut V,
self.len()
)
}
let ptr = self.node.as_internal_mut() as *mut _;
let mut child = self.descend();
child.as_leaf_mut().parent = ptr;
- child.as_leaf_mut().parent_idx = idx;
+ child.as_leaf_mut().parent_idx.set(idx);
}
/// Unsafely asserts to the compiler some static information about whether the underlying
ptr::copy_nonoverlapping(
self.node.keys().as_ptr().add(self.idx + 1),
- new_node.keys.as_mut_ptr(),
+ new_node.keys.as_mut_ptr() as *mut K,
new_len
);
ptr::copy_nonoverlapping(
self.node.vals().as_ptr().add(self.idx + 1),
- new_node.vals.as_mut_ptr(),
+ new_node.vals.as_mut_ptr() as *mut V,
new_len
);
ptr::copy_nonoverlapping(
self.node.keys().as_ptr().add(self.idx + 1),
- new_node.data.keys.as_mut_ptr(),
+ new_node.data.keys.as_mut_ptr() as *mut K,
new_len
);
ptr::copy_nonoverlapping(
self.node.vals().as_ptr().add(self.idx + 1),
- new_node.data.vals.as_mut_ptr(),
+ new_node.data.vals.as_mut_ptr() as *mut V,
new_len
);
ptr::copy_nonoverlapping(
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
+#![feature(maybe_uninit)]
// Allow testing this library
/// assert_eq!(vec, [1, 2, 3, 4]);
/// ```
///
-/// It can also initialize each element of a `Vec<T>` with a given value:
+/// It can also initialize each element of a `Vec<T>` with a given value.
+/// This may be more efficient than performing allocation and initialization
+/// in separate steps, especially when initializing a vector of zeros:
///
/// ```
/// let vec = vec![0; 5];
/// assert_eq!(vec, [0, 0, 0, 0, 0]);
+///
+/// // The following is equivalent, but potentially slower:
+/// let mut vec1 = Vec::with_capacity(5);
+/// vec1.resize(5, 0);
/// ```
///
/// Use a `Vec<T>` as an efficient stack:
#![feature(nll)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
+#![cfg_attr(
+ all(target_arch = "wasm32", not(target_os = "emscripten")),
+ feature(integer_atomics, stdsimd)
+)]
#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
#![rustc_alloc_kind = "lib"]
use core::alloc::{GlobalAlloc, Layout};
use System;
- // No need for synchronization here as wasm is currently single-threaded
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ let _lock = lock::lock();
DLMALLOC.malloc(layout.size(), layout.align())
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ let _lock = lock::lock();
DLMALLOC.calloc(layout.size(), layout.align())
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ let _lock = lock::lock();
DLMALLOC.free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ let _lock = lock::lock();
DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
}
}
+
+ #[cfg(target_feature = "atomics")]
+ mod lock {
+ use core::arch::wasm32;
+ use core::sync::atomic::{AtomicI32, Ordering::SeqCst};
+
+ static LOCKED: AtomicI32 = AtomicI32::new(0);
+
+ pub struct DropLock;
+
+ pub fn lock() -> DropLock {
+ loop {
+ if LOCKED.swap(1, SeqCst) == 0 {
+ return DropLock
+ }
+ unsafe {
+ let r = wasm32::atomic::wait_i32(
+ &LOCKED as *const AtomicI32 as *mut i32,
+ 1, // expected value
+ -1, // timeout
+ );
+ debug_assert!(r == 0 || r == 1);
+ }
+ }
+ }
+
+ impl Drop for DropLock {
+ fn drop(&mut self) {
+ let r = LOCKED.swap(0, SeqCst);
+ debug_assert_eq!(r, 1);
+ unsafe {
+ wasm32::atomic::wake(
+ &LOCKED as *const AtomicI32 as *mut i32,
+ 1, // only one thread
+ );
+ }
+ }
+ }
+ }
+
+ #[cfg(not(target_feature = "atomics"))]
+ mod lock {
+ pub fn lock() {} // no atomics, no threads, that's easy!
+ }
}
/// # Examples
///
/// ```
- /// #![feature(option_replace)]
- ///
/// let mut x = Some(2);
/// let old = x.replace(5);
/// assert_eq!(x, Some(5));
/// assert_eq!(old, None);
/// ```
#[inline]
- #[unstable(feature = "option_replace", issue = "51998")]
+ #[stable(feature = "option_replace", since = "1.31.0")]
pub fn replace(&mut self, value: T) -> Option<T> {
mem::replace(self, Some(value))
}
///
/// Note, that this table does not contain values where inverse does not exist (i.e. for
/// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.)
- const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
+ const INV_TABLE_MOD_16: [u8; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
/// Modulo for which the `INV_TABLE_MOD_16` is intended.
const INV_TABLE_MOD: usize = 16;
/// INV_TABLE_MOD²
const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD;
- let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1];
+ let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1] as usize;
if m <= INV_TABLE_MOD {
table_inverse & (m - 1)
} else {
let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a));
let gcd = 1usize << gcdpow;
- if gcd == 1 {
- // This branch solves for the variable $o$ in following linear congruence equation:
- //
- // ⎰ p + o ≡ 0 (mod a) # $p + o$ must be aligned to specified alignment $a$
- // ⎱ o ≡ 0 (mod s) # offset $o$ must be a multiple of stride $s$
- //
- // where
+ if p as usize & (gcd - 1) == 0 {
+ // This branch solves for the following linear congruence equation:
//
- // * a, s are co-prime
+ // $$ p + so ≡ 0 mod a $$
//
- // This gives us the formula below:
+ // $p$ here is the pointer value, $s$ – stride of `T`, $o$ offset in `T`s, and $a$ – the
+ // requested alignment.
//
- // o = (a - (p mod a)) * (s⁻¹ mod a) * s
+ // g = gcd(a, s)
+ // o = (a - (p mod a))/g * ((s/g)⁻¹ mod a)
//
// The first term is “the relative alignment of p to a”, the second term is “how does
- // incrementing p by one s change the relative alignment of p”, the third term is
- // translating change in units of s to a byte count.
+ // incrementing p by s bytes change the relative alignment of p”. Division by `g` is
+ // necessary to make this equation well formed if $a$ and $s$ are not co-prime.
//
// Furthermore, the result produced by this solution is not “minimal”, so it is necessary
- // to take the result $o mod lcm(s, a)$. Since $s$ and $a$ are co-prime (i.e. $gcd(s, a) =
- // 1$) and $lcm(s, a) = s * a / gcd(s, a)$, we can replace $lcm(s, a)$ with just a $s * a$.
- //
- // (Author note: we decided later on to express the offset in "elements" rather than bytes,
- // which drops the multiplication by `s` on both sides of the modulo.)
- return intrinsics::unchecked_rem(a.wrapping_sub(pmoda).wrapping_mul(mod_inv(smoda, a)), a);
- }
-
- if p as usize & (gcd - 1) == 0 {
- // This can be aligned, but `a` and `stride` are not co-prime, so a somewhat adapted
- // formula is used.
+ // to take the result $o mod lcm(s, a)$. We can replace $lcm(s, a)$ with just a $a / g$.
let j = a.wrapping_sub(pmoda) >> gcdpow;
let k = smoda >> gcdpow;
return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow);
fn gcd(a: usize, b: usize) -> usize {
// iterative stein’s algorithm
// We should still make this `const fn` (and revert to recursive algorithm if we do)
- // because relying on llvm to consteval all this is… well, it makes me
+ // because relying on llvm to consteval all this is… well, it makes me uncomfortable.
let (ctz_a, mut ctz_b) = unsafe {
if a == 0 { return b; }
if b == 0 { return a; }
reason = "futures in libcore are unstable",
issue = "50547")]
-use {fmt, mem};
+use fmt;
use marker::Unpin;
use ptr::NonNull;
pub fn will_wake(&self, other: &Waker) -> bool {
self.inner == other.inner
}
+
+ /// Returns whether or not this `Waker` and `other` `LocalWaker` awaken
+ /// the same task.
+ ///
+ /// This function works on a best-effort basis, and may return false even
+ /// when the `Waker`s would awaken the same task. However, if this function
+ /// returns true, it is guaranteed that the `Waker`s will awaken the same
+ /// task.
+ ///
+ /// This function is primarily used for optimization purposes.
+ #[inline]
+ pub fn will_wake_local(&self, other: &LocalWaker) -> bool {
+ self.will_wake(&other.0)
+ }
}
impl Clone for Waker {
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// behavior.
#[repr(transparent)]
-pub struct LocalWaker {
- inner: NonNull<dyn UnsafeWake>,
-}
+#[derive(Clone)]
+pub struct LocalWaker(Waker);
impl Unpin for LocalWaker {}
impl !Send for LocalWaker {}
/// on the current thread.
#[inline]
pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
- LocalWaker { inner }
+ LocalWaker(Waker::new(inner))
+ }
+
+ /// Borrows this `LocalWaker` as a `Waker`.
+ ///
+ /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
+ /// (implements `Send` and `Sync`).
+ #[inline]
+ pub fn as_waker(&self) -> &Waker {
+ &self.0
}
/// Converts this `LocalWaker` into a `Waker`.
/// (implements `Send` and `Sync`).
#[inline]
pub fn into_waker(self) -> Waker {
- self.into()
+ self.0
}
/// Wake up the task associated with this `LocalWaker`.
#[inline]
pub fn wake(&self) {
- unsafe { self.inner.as_ref().wake_local() }
+ unsafe { self.0.inner.as_ref().wake_local() }
}
/// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
/// This function is primarily used for optimization purposes.
#[inline]
pub fn will_wake(&self, other: &LocalWaker) -> bool {
- self.inner == other.inner
+ self.0.will_wake(&other.0)
}
/// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
/// This function is primarily used for optimization purposes.
#[inline]
pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
- self.inner == other.inner
+ self.0.will_wake(other)
}
}
impl From<LocalWaker> for Waker {
#[inline]
fn from(local_waker: LocalWaker) -> Self {
- let inner = local_waker.inner;
- mem::forget(local_waker);
- Waker { inner }
- }
-}
-
-impl Clone for LocalWaker {
- #[inline]
- fn clone(&self) -> Self {
- let waker = unsafe { self.inner.as_ref().clone_raw() };
- let inner = waker.inner;
- mem::forget(waker);
- LocalWaker { inner }
+ local_waker.0
}
}
impl fmt::Debug for LocalWaker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("Waker")
+ f.debug_struct("LocalWaker")
.finish()
}
}
-impl Drop for LocalWaker {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- self.inner.as_ref().drop_raw()
- }
- }
-}
-
/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
///
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
#![feature(reverse_bits)]
#![feature(inner_deref)]
#![feature(slice_internals)]
-#![feature(option_replace)]
#![feature(slice_partition_dedup)]
#![feature(copy_within)]
backtrace = "0.3.3"
parking_lot = "0.6"
byteorder = { version = "1.1", features = ["i128"]}
-chalk-engine = { version = "0.7.0", default-features=false }
+chalk-engine = { version = "0.8.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
smallvec = { version = "0.6.5", features = ["union"] }
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
- use traits::Goal::*;
+ use traits::GoalKind::*;
mem::discriminant(self).hash_stable(hcx, hasher);
match self {
use lint::{self, Lint, LintId, Level, LintSource};
use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
StableHasher, StableHasherResult};
-use session::{config::nightly_options, Session};
+use session::Session;
use syntax::ast;
use syntax::attr;
use syntax::source_map::MultiSpan;
-use syntax::feature_gate;
use syntax::symbol::Symbol;
use util::nodemap::FxHashMap;
}
};
let tool_name = if let Some(lint_tool) = word.is_scoped() {
- let gate_feature = !self.sess.features_untracked().tool_lints;
- let known_tool = attr::is_known_lint_tool(lint_tool);
- if gate_feature {
- feature_gate::emit_feature_err(
- &sess.parse_sess,
- "tool_lints",
- word.span,
- feature_gate::GateIssue::Language,
- &format!("scoped lint `{}` is experimental", word.ident),
- );
- }
- if !known_tool {
+ if !attr::is_known_lint_tool(lint_tool) {
span_err!(
sess,
lint_tool.span,
"an unknown tool name found in scoped lint: `{}`",
word.ident
);
- }
-
- if gate_feature || !known_tool {
continue;
}
"change it to",
new_lint_name.to_string(),
Applicability::MachineApplicable,
- );
-
- if nightly_options::is_nightly_build() {
- err.emit();
- } else {
- err.cancel();
- }
+ ).emit();
let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span);
for id in ids {
})
}
+#[macro_export]
+macro_rules! static_assert {
+ ($name:ident: $test:expr) => {
+ // Use the bool to access an array such that if the bool is false, the access
+ // is out-of-bounds.
+ #[allow(dead_code)]
+ static $name: () = [()][!$test as usize];
+ }
+}
+
#[macro_export]
macro_rules! __impl_stable_hash_field {
($field:ident, $ctx:expr, $hasher:expr) => ($field.hash_stable($ctx, $hasher));
impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { private });
// compilation error if size of `ScopeData` is not the same as a `u32`
-#[allow(dead_code)]
-static ASSERT: () = [()][!(mem::size_of::<ScopeData>() == 4) as usize];
+static_assert!(ASSERT_SCOPE_DATA: mem::size_of::<ScopeData>() == 4);
impl Scope {
/// Returns a item-local id associated with this scope.
"output a json file with profiler results"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emits a section containing stack size metadata"),
+ plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "whether to use the PLT when calling into shared libraries;
+ only has effect for PIC code on systems with ELF binaries
+ (default: PLT is disabled if full relro is enabled)"),
}
pub fn default_lib_output() -> CrateType {
use syntax_pos::{MultiSpan, Span};
use util::profiling::SelfProfiler;
-use rustc_target::spec::PanicStrategy;
-use rustc_target::spec::{Target, TargetTriple};
+use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
use rustc_data_structures::flock;
use jobserver::Client;
pub fn edition(&self) -> Edition {
self.opts.edition
}
+
+ /// True if we cannot skip the PLT for shared library calls.
+ pub fn needs_plt(&self) -> bool {
+ // Check if the current target usually needs PLT to be enabled.
+ // The user can use the command line flag to override it.
+ let needs_plt = self.target.target.options.needs_plt;
+
+ let dbg_opts = &self.opts.debugging_opts;
+
+ let relro_level = dbg_opts.relro_level
+ .unwrap_or(self.target.target.options.relro_level);
+
+ // Only enable this optimization by default if full relro is also enabled.
+ // In this case, lazy binding was already unavailable, so nothing is lost.
+ // This also ensures `-Wl,-z,now` is supported by the linker.
+ let full_relro = RelroLevel::Full == relro_level;
+
+ // If user didn't explicitly forced us to use / skip the PLT,
+ // then try to skip it where possible.
+ dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
+ }
}
pub fn build_session(
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum Goal<'tcx> {
- Implies(Clauses<'tcx>, &'tcx Goal<'tcx>),
- And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>),
- Not(&'tcx Goal<'tcx>),
+pub enum GoalKind<'tcx> {
+ Implies(Clauses<'tcx>, Goal<'tcx>),
+ And(Goal<'tcx>, Goal<'tcx>),
+ Not(Goal<'tcx>),
DomainGoal(DomainGoal<'tcx>),
- Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>),
+ Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
CannotProve,
}
+pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
+
pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
impl<'tcx> DomainGoal<'tcx> {
- pub fn into_goal(self) -> Goal<'tcx> {
- Goal::DomainGoal(self)
+ pub fn into_goal(self) -> GoalKind<'tcx> {
+ GoalKind::DomainGoal(self)
}
}
-impl<'tcx> Goal<'tcx> {
+impl<'tcx> GoalKind<'tcx> {
pub fn from_poly_domain_goal<'a>(
domain_goal: PolyDomainGoal<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ) -> Goal<'tcx> {
+ ) -> GoalKind<'tcx> {
match domain_goal.no_late_bound_regions() {
Some(p) => p.into_goal(),
- None => Goal::Quantified(
+ None => GoalKind::Quantified(
QuantifierKind::Universal,
domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal()))
),
impl<'tcx> fmt::Display for traits::Goal<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- use traits::Goal::*;
+ use traits::GoalKind::*;
match self {
Implies(hypotheses, goal) => {
}
EnumTypeFoldableImpl! {
- impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
- (traits::Goal::Implies)(hypotheses, goal),
- (traits::Goal::And)(goal1, goal2),
- (traits::Goal::Not)(goal),
- (traits::Goal::DomainGoal)(domain_goal),
- (traits::Goal::Quantified)(qkind, goal),
- (traits::Goal::CannotProve),
+ impl<'tcx> TypeFoldable<'tcx> for traits::GoalKind<'tcx> {
+ (traits::GoalKind::Implies)(hypotheses, goal),
+ (traits::GoalKind::And)(goal1, goal2),
+ (traits::GoalKind::Not)(goal),
+ (traits::GoalKind::DomainGoal)(domain_goal),
+ (traits::GoalKind::Quantified)(qkind, goal),
+ (traits::GoalKind::CannotProve),
}
}
EnumLiftImpl! {
- impl<'a, 'tcx> Lift<'tcx> for traits::Goal<'a> {
- type Lifted = traits::Goal<'tcx>;
- (traits::Goal::Implies)(hypotheses, goal),
- (traits::Goal::And)(goal1, goal2),
- (traits::Goal::Not)(goal),
- (traits::Goal::DomainGoal)(domain_goal),
- (traits::Goal::Quantified)(kind, goal),
- (traits::Goal::CannotProve),
+ impl<'a, 'tcx> Lift<'tcx> for traits::GoalKind<'a> {
+ type Lifted = traits::GoalKind<'tcx>;
+ (traits::GoalKind::Implies)(hypotheses, goal),
+ (traits::GoalKind::And)(goal1, goal2),
+ (traits::GoalKind::Not)(goal),
+ (traits::GoalKind::DomainGoal)(domain_goal),
+ (traits::GoalKind::Quantified)(kind, goal),
+ (traits::GoalKind::CannotProve),
}
}
}
}
-impl<'tcx> TypeFoldable<'tcx> for &'tcx traits::Goal<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let v = (**self).fold_with(folder);
folder.tcx().mk_goal(v)
use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
use ty::ReprOptions;
use traits;
-use traits::{Clause, Clauses, Goal, Goals};
+use traits::{Clause, Clauses, GoalKind, Goal, Goals};
use ty::{self, Ty, TypeAndMut};
use ty::{TyS, TyKind, List};
use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const};
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
const_: InternedSet<'tcx, Const<'tcx>>,
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
- goals: InternedSet<'tcx, List<Goal<'tcx>>>,
+ goal: InternedSet<'tcx, GoalKind<'tcx>>,
+ goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
}
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
predicates: Default::default(),
const_: Default::default(),
clauses: Default::default(),
- goals: Default::default(),
+ goal: Default::default(),
+ goal_list: Default::default(),
}
}
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
// Ensure our type representation does not grow
#[cfg(target_pointer_width = "64")]
- #[allow(dead_code)]
- static ASSERT_TY_KIND: () =
- [()][!(::std::mem::size_of::<ty::TyKind<'_>>() <= 24) as usize];
+ static_assert!(ASSERT_TY_KIND: ::std::mem::size_of::<ty::TyKind<'_>>() <= 24);
#[cfg(target_pointer_width = "64")]
- #[allow(dead_code)]
- static ASSERT_TYS: () = [()][!(::std::mem::size_of::<ty::TyS<'_>>() <= 32) as usize];
+ static_assert!(ASSERT_TYS: ::std::mem::size_of::<ty::TyS<'_>>() <= 32);
let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
let mk_region = |r| {
}
}
-impl<'a, 'tcx> Lift<'tcx> for &'a Goal<'a> {
- type Lifted = &'tcx Goal<'tcx>;
- fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Goal<'tcx>> {
+impl<'a, 'tcx> Lift<'tcx> for Goal<'a> {
+ type Lifted = Goal<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Goal<'tcx>> {
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
}
}
+impl<'tcx: 'lcx, 'lcx> Borrow<GoalKind<'lcx>> for Interned<'tcx, GoalKind<'tcx>> {
+ fn borrow<'a>(&'a self) -> &'a GoalKind<'lcx> {
+ &self.0
+ }
+}
+
impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]>
for Interned<'tcx, List<ExistentialPredicate<'tcx>>> {
fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] {
direct_interners!('tcx,
region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind,
- const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>
+ const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>,
+ goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx>
);
macro_rules! slice_interners {
type_list: _intern_type_list(Ty),
substs: _intern_substs(Kind),
clauses: _intern_clauses(Clause),
- goals: _intern_goals(Goal)
+ goal_list: _intern_goals(Goal)
);
// This isn't a perfect fit: CanonicalVarInfo slices are always
iter.intern_with(|xs| self.intern_goals(xs))
}
- pub fn mk_goal(self, goal: Goal<'tcx>) -> &'tcx Goal<'_> {
- &self.intern_goals(&[goal])[0]
- }
-
pub fn lint_hir<S: Into<MultiSpan>>(self,
lint: &'static Lint,
hir_id: HirId,
self.add_projection_ty(data);
}
- &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+ &ty::UnnormalizedProjection(ref data) => {
+ self.add_flags(TypeFlags::HAS_PROJECTION);
+ self.add_projection_ty(data);
+ },
&ty::Opaque(_, substs) => {
self.add_flags(TypeFlags::HAS_PROJECTION);
// Create list of fields in the main structure
let mut args: Vec<_> =
self.prefix.iter().flat_map(|option_kind| option_kind.map(
- |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
+ |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();
}
pub trait FnTypeExt<'tcx> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>)
- -> Self;
+ fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
fn new(cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> Self;
}
impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>)
- -> Self {
+ fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
let fn_ty = instance.ty(cx.tcx);
let sig = ty_fn_sig(cx, fn_ty);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
}
fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>]) -> Self {
FnType::new_internal(cx, sig, extra_args, |ty, _| {
ArgType::new(cx.layout_of(ty))
})
}
fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>]) -> Self {
FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
let mut layout = cx.layout_of(ty);
// Don't pass the vtable, it's not an argument of the virtual fn.
RustIntrinsic | PlatformIntrinsic |
Rust | RustCall => Conv::C,
- // It's the ABI's job to select this, not us.
+ // It's the ABI's job to select this, not ours.
System => bug!("system abi should be selected elsewhere"),
Stdcall => Conv::X86Stdcall,
// If the value is a boolean, the range is 0..2 and that ultimately
// become 0..0 when the type becomes i1, which would be rejected
// by the LLVM verifier.
- match scalar.value {
- layout::Int(..) if !scalar.is_bool() => {
+ if let layout::Int(..) = scalar.value {
+ if !scalar.is_bool() {
let range = scalar.valid_range_exclusive(bx.cx);
if range.start != range.end {
bx.range_metadata(callsite, range);
}
}
- _ => {}
}
}
for arg in &self.args {
let void = llvm::LLVMVoidTypeInContext(llcx);
for method in ALLOCATOR_METHODS {
- let mut args = Vec::new();
+ let mut args = Vec::with_capacity(method.inputs.len());
for ty in method.inputs.iter() {
match *ty {
AllocatorTy::Layout => {
// Currently stack probes seem somewhat incompatible with the address
// sanitizer. With asan we're already protected from stack overflow anyway
// so we don't really need stack probes regardless.
- match cx.sess().opts.debugging_opts.sanitizer {
- Some(Sanitizer::Address) => return,
- _ => {}
+ if let Some(Sanitizer::Address) = cx.sess().opts.debugging_opts.sanitizer {
+ return
}
// probestack doesn't play nice either with pgo-gen.
target_cpu.as_c_str());
}
+/// Sets the `NonLazyBind` LLVM attribute on a given function,
+/// assuming the codegen options allow skipping the PLT.
+pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
+ // Don't generate calls through PLT if it's not necessary
+ if !sess.needs_plt() {
+ Attribute::NonLazyBind.apply_llfn(Function, llfn);
+ }
+}
+
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
pub fn from_fn_attrs(
// `NativeLibrary` internally contains information about
// `#[link(wasm_import_module = "...")]` for example.
let native_libs = tcx.native_libraries(cnum);
- let mut def_id_to_native_lib = FxHashMap();
- for lib in native_libs.iter() {
+
+ let def_id_to_native_lib = native_libs.iter().filter_map(|lib|
if let Some(id) = lib.foreign_module {
- def_id_to_native_lib.insert(id, lib);
+ Some((id, lib))
+ } else {
+ None
}
- }
+ ).collect::<FxHashMap<_, _>>();
let mut ret = FxHashMap();
for lib in tcx.foreign_modules(cnum).iter() {
Some(s) => s,
None => continue,
};
- for id in lib.foreign_items.iter() {
+ ret.extend(lib.foreign_items.iter().map(|id| {
assert_eq!(id.krate, cnum);
- ret.insert(*id, module.to_string());
- }
+ (*id, module.to_string())
+ }));
}
Lrc::new(ret)
vtable_ptr.llvm_type(cx))
}
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
- source,
- target),
+ source,
+ target),
}
}
}
fn cast_shift_rhs<'ll, F, G>(op: hir::BinOpKind,
- lhs: &'ll Value,
- rhs: &'ll Value,
- trunc: F,
- zext: G)
- -> &'ll Value
+ lhs: &'ll Value,
+ rhs: &'ll Value,
+ trunc: F,
+ zext: G)
+ -> &'ll Value
where F: FnOnce(&'ll Value, &'ll Type) -> &'ll Value,
G: FnOnce(&'ll Value, &'ll Type) -> &'ll Value
{
if lhs_sz < rhs_sz {
trunc(rhs, lhs_llty)
} else if lhs_sz > rhs_sz {
- // FIXME (#1877: If shifting by negative
- // values becomes not undefined then this is wrong.
+ // FIXME (#1877: If in the future shifting by negative
+ // values is no longer undefined then this is wrong.
zext(rhs, lhs_llty)
} else {
rhs
let sig = common::ty_fn_sig(cx, fn_ty);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- let lldecl = match cx.instances.borrow().get(&instance) {
- Some(&val) => val,
- None => bug!("Instance `{:?}` not already declared", instance)
- };
+ let lldecl = cx.instances.borrow().get(&instance).cloned().unwrap_or_else(||
+ bug!("Instance `{:?}` not already declared", instance));
cx.stats.borrow_mut().n_closures += 1;
if declare::get_defined_value(cx, "main").is_some() {
// FIXME: We should be smart and show a better diagnostic here.
cx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times")
- .help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
- .emit();
+ .help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
+ .emit();
cx.sess().abort_if_errors();
bug!();
}
}
pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- rx: mpsc::Receiver<Box<dyn Any + Send>>)
- -> OngoingCodegen {
-
+ rx: mpsc::Receiver<Box<dyn Any + Send>>)
+ -> OngoingCodegen
+{
check_for_rustc_errors_attr(tcx);
if let Some(true) = tcx.sess.opts.debugging_opts.thinlto {
// Run the monomorphization collector and partition the collected items into
// codegen units.
- let codegen_units =
- tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
+ let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
let codegen_units = (*codegen_units).clone();
// Force all codegen_unit queries so they are already either red or green
.iter()
.any(|(_, list)| {
use rustc::middle::dependency_format::Linkage;
- list.iter().any(|linkage| {
- match linkage {
- Linkage::Dynamic => true,
- _ => false,
- }
- })
+ list.iter().any(|&linkage| linkage == Linkage::Dynamic)
});
let allocator_module = if any_dynamic_crate {
None
if mode_string != "lazy" {
let message = format!("Unknown codegen-item collection mode '{}'. \
Falling back to 'lazy' mode.",
- mode_string);
+ mode_string);
tcx.sess.warn(&message);
}
info.load_wasm_imports(tcx, LOCAL_CRATE);
}
- for &cnum in tcx.crates().iter() {
+ let crates = tcx.crates();
+
+ let n_crates = crates.len();
+ info.native_libraries.reserve(n_crates);
+ info.crate_name.reserve(n_crates);
+ info.used_crate_source.reserve(n_crates);
+ info.missing_lang_items.reserve(n_crates);
+
+ for &cnum in crates.iter() {
info.native_libraries.insert(cnum, tcx.native_libraries(cnum));
info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
}
fn load_wasm_imports(&mut self, tcx: TyCtxt, cnum: CrateNum) {
- for (&id, module) in tcx.wasm_import_module_map(cnum).iter() {
+ self.wasm_imports.extend(tcx.wasm_import_module_map(cnum).iter().map(|(&id, module)| {
let instance = Instance::mono(tcx, id);
let import_name = tcx.symbol_name(instance);
- self.wasm_imports.insert(import_name.to_string(), module.clone());
- }
+
+ (import_name.to_string(), module.clone())
+ }));
}
}
}
if self.cx.sess().count_llvm_insns() {
*self.cx.stats
- .borrow_mut()
- .llvm_insns
- .entry(category.to_string())
- .or_insert(0) += 1;
+ .borrow_mut()
+ .llvm_insns
+ .entry(category.to_string())
+ .or_insert(0) += 1;
}
}
}
pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
- inputs: &[&'ll Value], output: &'ll Type,
- volatile: bool, alignstack: bool,
- dia: AsmDialect) -> Option<&'ll Value> {
+ inputs: &[&'ll Value], output: &'ll Type,
+ volatile: bool, alignstack: bool,
+ dia: AsmDialect) -> Option<&'ll Value> {
self.count_insn("inlineasm");
let volatile = if volatile { llvm::True }
) -> &'ll Value {
unsafe {
llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src,
- order, failure_order, weak)
+ order, failure_order, weak)
}
}
pub fn atomic_rmw(
})
.collect();
- return Cow::Owned(casted_args);
+ Cow::Owned(casted_args)
}
pub fn lifetime_start(&self, ptr: &'ll Value, size: Size) {
msg: &str,
li: LangItem)
-> DefId {
- match tcx.lang_items().require(li) {
- Ok(id) => id,
- Err(s) => {
- let msg = format!("{} {}", msg, s);
- match span {
- Some(span) => tcx.sess.span_fatal(span, &msg[..]),
- None => tcx.sess.fatal(&msg[..]),
- }
+ tcx.lang_items().require(li).unwrap_or_else(|s| {
+ let msg = format!("{} {}", msg, s);
+ match span {
+ Some(span) => tcx.sess.span_fatal(span, &msg[..]),
+ None => tcx.sess.fatal(&msg[..]),
}
- }
+ })
}
// To avoid UB from LLVM, these two functions mask RHS with an
assert!(!defined_in_current_codegen_unit,
"consts::get_static() should always hit the cache for \
statics defined in the same CGU, but did not for `{:?}`",
- def_id);
+ def_id);
let ty = instance.ty(cx.tcx);
let sym = cx.tcx.symbol_name(instance).as_str();
// extern "C" fn() from being non-null, so we can't just declare a
// static and call it a day. Some linkages (like weak) will make it such
// that the static actually has a null value.
- let llty2 = match ty.sty {
- ty::RawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
- _ => {
- if span.is_some() {
- cx.sess().span_fatal(span.unwrap(), "must have type `*const T` or `*mut T`")
- } else {
- bug!("must have type `*const T` or `*mut T`")
- }
+ let llty2 = if let ty::RawPtr(ref mt) = ty.sty {
+ cx.layout_of(mt.ty).llvm_type(cx)
+ } else {
+ if let Some(span) = span {
+ cx.sess().span_fatal(span, "must have type `*const T` or `*mut T`")
+ } else {
+ bug!("must have type `*const T` or `*mut T`")
}
};
unsafe {
let mut real_name = "_rust_extern_with_linkage_".to_string();
real_name.push_str(&sym);
let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{
- if span.is_some() {
+ if let Some(span) = span {
cx.sess().span_fatal(
- span.unwrap(),
+ span,
&format!("symbol `{}` is already defined", &sym)
)
} else {
/// Cache instances of monomorphic and polymorphic items
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'a Value>>,
/// Cache generated vtables
- pub vtables: RefCell<FxHashMap<(Ty<'tcx>,
- Option<ty::PolyExistentialTraitRef<'tcx>>), &'a Value>>,
+ pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
+ &'a Value>>,
/// Cache of constant strings,
pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, &'a Value>>,
llvm::LLVMRustSetModulePIELevel(llmod);
}
+ // If skipping the PLT is enabled, we need to add some module metadata
+ // to ensure intrinsic calls don't use it.
+ if !sess.needs_plt() {
+ let avoid_plt = "RtLibUseGOT\0".as_ptr() as *const _;
+ llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
+ }
+
llmod
}
impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
crate fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- codegen_unit: Arc<CodegenUnit<'tcx>>,
- llvm_module: &'a ::ModuleLlvm)
- -> CodegenCx<'a, 'tcx> {
+ codegen_unit: Arc<CodegenUnit<'tcx>>,
+ llvm_module: &'a ::ModuleLlvm)
+ -> CodegenCx<'a, 'tcx> {
// An interesting part of Windows which MSVC forces our hand on (and
// apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
// attributes in LLVM IR as well as native dependencies (in C these
let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None {
let dctx = debuginfo::CrateDebugContext::new(llmod);
debuginfo::metadata::compile_unit_metadata(tcx,
- &codegen_unit.name().as_str(),
- &dctx);
+ &codegen_unit.name().as_str(),
+ &dctx);
Some(dctx)
} else {
None
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
return v;
}
- match declare_intrinsic(self, key) {
- Some(v) => return v,
- None => bug!("unknown intrinsic '{}'", key)
- }
+
+ declare_intrinsic(self, key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key))
}
/// Generate a new symbol name with the given prefix. This symbol name must
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty))
- .unwrap_or_else(|e| match e {
- LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
- _ => bug!("failed to get layout for `{}`: {}", ty, e)
+ .unwrap_or_else(|e| if let LayoutError::SizeOverflow(_) = e {
+ self.sess().fatal(&e.to_string())
+ } else {
+ bug!("failed to get layout for `{}`: {}", ty, e)
})
}
}
ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void);
ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void);
}
- return None;
+
+ None
}
attributes::unwind(llfn, false);
}
+ attributes::non_lazy_bind(cx.sess(), llfn);
+
llfn
}
```
"##,
+E0669: r##"
+Cannot convert inline assembly operand to a single LLVM value.
+
+This error usually happens when trying to pass in a value to an input inline
+assembly operand that is actually a pair of values. In particular, this can
+happen when trying to pass in a slice, for instance a `&str`. In Rust, these
+values are represented internally as a pair of values, the pointer and its
+length. When passed as an input operand, this pair of values can not be
+coerced into a register and thus we must fail with an error.
+"##,
+
}
C_usize(cx, std::cmp::max(sized_align, unsized_align) as u64)
}
_ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align),
- sized_align,
- unsized_align)
+ sized_align,
+ unsized_align)
};
// Issue #27023: must add any necessary padding to `size`
let llval = match name {
_ if simple.is_some() => {
bx.call(simple.unwrap(),
- &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
- None)
+ &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
+ None)
}
"unreachable" => {
return;
return;
}
}
-
},
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
let sty = &arg_tys[0].sty;
}
_ => {
- let intr = match Intrinsic::find(&name) {
- Some(intr) => intr,
- None => bug!("unknown intrinsic '{}'", name),
- };
+ let intr = Intrinsic::find(&name).unwrap_or_else(||
+ bug!("unknown intrinsic '{}'", name));
+
fn one<T>(x: Vec<T>) -> T {
assert_eq!(x.len(), 1);
x.into_iter().next().unwrap()
let i64p = Type::i64(cx).ptr_to();
let ptr_align = bx.tcx().data_layout.pointer_align;
let slot = bx.alloca(i64p, "slot", ptr_align);
- bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(),
- None);
+ bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
normal.ret(C_i32(cx, 0));
// being thrown. The second value is a "selector" indicating which of
// the landing pad clauses the exception's type had been matched to.
// rust_try ignores the selector.
- let lpad_ty = Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)],
- false);
+ let lpad_ty = Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], false);
let vals = catch.landing_pad(lpad_ty, bx.cx.eh_personality(), 1);
catch.add_clause(vals, C_null(Type::i8p(cx)));
let ptr = catch.extract_value(vals, 0);
let output = tcx.types.i32;
let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen);
cx.rust_try_fn.set(Some(rust_try));
- return rust_try
+ rust_try
}
fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
($msg: tt, $($fmt: tt)*) => {
span_invalid_monomorphization_error(
bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ",
- $msg),
+ &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
name, $($fmt)*));
}
}
+
macro_rules! return_error {
($($fmt: tt)*) => {
{
}
};
}
+
macro_rules! require_simd {
($ty: expr, $position: expr) => {
require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
}
}
-
-
let tcx = bx.tcx();
let sig = tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
}
if name.starts_with("simd_shuffle") {
- let n: usize = match name["simd_shuffle".len()..].parse() {
- Ok(n) => n,
- Err(_) => span_bug!(span,
- "bad `simd_shuffle` instruction only caught in codegen?")
- };
+ let n: usize = name["simd_shuffle".len()..].parse().unwrap_or_else(|_|
+ span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?"));
require_simd!(ret_ty, "return");
};
return Ok(bx.shuffle_vector(args[0].immediate(),
- args[1].immediate(),
- C_vector(&indices)))
+ args[1].immediate(),
+ C_vector(&indices)))
}
if name == "simd_insert" {
"expected inserted type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, arg_tys[2]);
return Ok(bx.insert_element(args[0].immediate(),
- args[2].immediate(),
- args[1].immediate()))
+ args[2].immediate(),
+ args[1].immediate()))
}
if name == "simd_extract" {
require!(ret_ty == in_elem,
);
match m_elem_ty.sty {
ty::Int(_) => {},
- _ => {
- return_error!("mask element type is `{}`, expected `i_`", m_elem_ty);
- }
+ _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty)
}
// truncate the mask to a vector of i1s
let i1 = Type::i1(bx.cx);
($msg: tt, $($fmt: tt)*) => {
span_invalid_monomorphization_error(
bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ",
- $msg),
+ &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
name, $($fmt)*));
}
}
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
None);
unsafe { llvm::LLVMRustSetHasUnsafeAlgebra(c) };
- return Ok(c);
- }
-
- if name == "simd_fsqrt" {
- return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fsin" {
- return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fcos" {
- return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fabs" {
- return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_floor" {
- return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_ceil" {
- return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fexp" {
- return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fexp2" {
- return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_flog10" {
- return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_flog2" {
- return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_flog" {
- return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
+ Ok(c)
}
- if name == "simd_fpowi" {
- return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fpow" {
- return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
- }
-
- if name == "simd_fma" {
- return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
+ match name {
+ "simd_fsqrt" => {
+ return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fsin" => {
+ return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fcos" => {
+ return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fabs" => {
+ return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_floor" => {
+ return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_ceil" => {
+ return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fexp" => {
+ return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fexp2" => {
+ return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_flog10" => {
+ return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_flog2" => {
+ return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_flog" => {
+ return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fpowi" => {
+ return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fpow" => {
+ return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
+ }
+ "simd_fma" => {
+ return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
+ }
+ _ => { /* fallthrough */ }
}
// FIXME: use:
}
- if name == "simd_gather" {
+ if name == "simd_gather" {
// simd_gather(values: <N x T>, pointers: <N x *_ T>,
// mask: <N x i{M}>) -> <N x T>
// * N: number of elements in the input vectors
// to the element type of the first argument
let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty {
ty::RawPtr(p) if p.ty == in_elem => (ptr_count(arg_tys[1].simd_type(tcx)),
- non_ptr(arg_tys[1].simd_type(tcx))),
+ non_ptr(arg_tys[1].simd_type(tcx))),
_ => {
require!(false, "expected element type `{}` of second argument `{}` \
to be a pointer to the element type `{}` of the first \
}
};
assert!(pointer_count > 0);
- assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx)));
+ assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
// The element type of the third argument must be a signed integer type of any width:
return Ok(v);
}
- if name == "simd_scatter" {
+ if name == "simd_scatter" {
// simd_scatter(values: <N x T>, pointers: <N x *mut T>,
// mask: <N x i{M}>) -> ()
// * N: number of elements in the input vectors
}
};
assert!(pointer_count > 0);
- assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx)));
+ assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
// The element type of the third argument must be a signed integer type of any width:
)
}
}
-
};
Ok(bx.$float_reduce(acc, args[0].immediate()))
}
_ => {},
}
require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ "unsupported operation on `{}` with element `{}`",
+ in_ty,
+ in_elem)
})*
}
}
};
let bytecode_compressed = if emit_bc_compressed {
Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
- .with_extension(RLIB_BYTECODE_EXTENSION))
+ .with_extension(RLIB_BYTECODE_EXTENSION))
} else {
None
};
SanitizeThread = 20,
SanitizeAddress = 21,
SanitizeMemory = 22,
+ NonLazyBind = 23,
}
/// LLVMIntPredicate
}
unsafe fn configure_llvm(sess: &Session) {
- let mut llvm_c_strs = Vec::new();
- let mut llvm_args = Vec::new();
+ let n_args = sess.opts.cg.llvm_args.len();
+ let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
+ let mut llvm_args = Vec::with_capacity(n_args + 1);
{
let mut add = |arg: &str| {
let of = ObjectFile::new(mb)
.map(|of| OwningRef::new(box of))
.ok_or_else(|| format!("provided path not an object file: '{}'",
- filename.display()))?;
+ filename.display()))?;
let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
Ok(rustc_erase_owner!(buf))
}
}
fn visit_place(&mut self,
- place: &mir::Place<'tcx>,
- context: PlaceContext<'tcx>,
- location: Location) {
+ place: &mir::Place<'tcx>,
+ context: PlaceContext<'tcx>,
+ location: Location) {
debug!("visit_place(place={:?}, context={:?})", place, context);
let cx = self.fx.cx;
}
fn codegen_terminator(&mut self,
- mut bx: Builder<'a, 'll, 'tcx>,
- bb: mir::BasicBlock,
- terminator: &mir::Terminator<'tcx>)
+ mut bx: Builder<'a, 'll, 'tcx>,
+ bb: mir::BasicBlock,
+ terminator: &mir::Terminator<'tcx>)
{
debug!("codegen_terminator: {:?}", terminator);
use super::FunctionCx;
use super::LocalRef;
+use super::OperandValue;
impl FunctionCx<'a, 'll, 'tcx> {
pub fn codegen_statement(&mut self,
self.codegen_place(&bx, output)
}).collect();
- let input_vals = inputs.iter().map(|input| {
- self.codegen_operand(&bx, input).immediate()
- }).collect();
+ let input_vals = inputs.iter()
+ .try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| {
+ let op = self.codegen_operand(&bx, input);
+ if let OperandValue::Immediate(_) = op.val {
+ acc.push(op.immediate());
+ Ok(acc)
+ } else {
+ Err(op)
+ }
+ });
- let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
- if !res {
- span_err!(bx.sess(), statement.source_info.span, E0668,
- "malformed inline assembly");
+ if input_vals.is_err() {
+ span_err!(bx.sess(), statement.source_info.span, E0669,
+ "invalid value for constraint in inline assembly");
+ } else {
+ let input_vals = input_vals.unwrap();
+ let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
+ if !res {
+ span_err!(bx.sess(), statement.source_info.span, E0668,
+ "malformed inline assembly");
+ }
}
bx
}
match *self.as_mono_item() {
MonoItem::Fn(instance) => {
format!("Fn({:?}, {})",
- instance.def,
- instance.substs.as_ptr() as usize)
+ instance.def,
+ instance.substs.as_ptr() as usize)
}
MonoItem::Static(id) => {
format!("Static({:?})", id)
let mut name = String::with_capacity(32);
let printer = DefPathBasedNames::new(cx.tcx, true, true);
printer.push_type_name(layout.ty, &mut name);
- match (&layout.ty.sty, &layout.variants) {
- (&ty::Adt(def, _), &layout::Variants::Single { index }) => {
- if def.is_enum() && !def.variants.is_empty() {
- write!(&mut name, "::{}", def.variants[index].name).unwrap();
- }
+ if let (&ty::Adt(def, _), &layout::Variants::Single { index })
+ = (&layout.ty.sty, &layout.variants)
+ {
+ if def.is_enum() && !def.variants.is_empty() {
+ write!(&mut name, "::{}", def.variants[index].name).unwrap();
}
- _ => {}
}
Some(name)
}
debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \
effective_field_align: {}",
- i, field, offset, target_offset, effective_field_align.abi());
+ i, field, offset, target_offset, effective_field_align.abi());
assert!(target_offset >= offset);
let padding = target_offset - offset;
let padding_align = prev_effective_align.min(effective_field_align);
debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
padding, offset, layout.size);
result.push(Type::padding_filler(cx, padding, padding_align));
- assert!(result.len() == 1 + field_count * 2);
+ assert_eq!(result.len(), 1 + field_count * 2);
} else {
debug!("struct_llfields: offset: {:?} stride: {:?}",
offset, layout.size);
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&llvm::build_string(|s| unsafe {
llvm::LLVMRustWriteValueToString(self, s);
- }).expect("nun-UTF8 value description from LLVM"))
+ }).expect("non-UTF8 value description from LLVM"))
}
}
#![feature(box_syntax)]
#![cfg_attr(unix, feature(libc))]
#![feature(nll)]
-#![feature(option_replace)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
}
impl StringPart {
- pub fn content(&self) -> String {
+ pub fn content(&self) -> &str {
match self {
- &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
+ &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s
}
}
}
}
pub fn message(&self) -> String {
- self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
+ self.message.iter().map(|i| i.0.as_str()).collect::<String>()
}
pub fn styled_message(&self) -> &Vec<(String, Style)> {
impl SubDiagnostic {
pub fn message(&self) -> String {
- self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
+ self.message.iter().map(|i| i.0.as_str()).collect::<String>()
}
pub fn styled_message(&self) -> &Vec<(String, Style)> {
}
let t = cx.tables.expr_ty(&expr);
- let ty_warned = match t.sty {
- ty::Tuple(ref tys) if tys.is_empty() => return,
- ty::Never => return,
+ // FIXME(varkor): replace with `t.is_unit() || t.conservative_is_uninhabited()`.
+ let type_permits_no_use = match t.sty {
+ ty::Tuple(ref tys) if tys.is_empty() => true,
+ ty::Never => true,
ty::Adt(def, _) => {
if def.variants.is_empty() {
- return;
+ true
+ } else {
+ check_must_use(cx, def.did, s.span, "")
}
- check_must_use(cx, def.did, s.span, "")
- },
+ }
_ => false,
};
if let Some(def) = maybe_def {
let def_id = def.def_id();
fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
+ } else if type_permits_no_use {
+ // We don't warn about unused unit or uninhabited types.
+ // (See https://github.com/rust-lang/rust/issues/43806 for details.)
+ return;
}
+
let must_use_op = match expr.node {
// Hardcoding operators here seemed more expedient than the
// refactoring that would be needed to look up the `#[must_use]`
op_warned = true;
}
- if !(ty_warned || fn_warned || op_warned) {
+ if !(type_permits_no_use || fn_warned || op_warned) {
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
}
.find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
.is_some();
- // Has a plugin registered this attribute as one which must be used at
+ // Has a plugin registered this attribute as one that must be used at
// the crate level?
let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
enum BorrowedContentSource {
Arc,
Rc,
+ DerefRawPointer,
Other,
}
match *self {
BorrowedContentSource::Arc => write!(f, "an `Arc`"),
BorrowedContentSource::Rc => write!(f, "an `Rc`"),
+ BorrowedContentSource::DerefRawPointer => write!(f, "dereference of raw pointer"),
BorrowedContentSource::Other => write!(f, "borrowed content"),
}
}
self.prefixes(&original_path, PrefixSet::All)
.any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx)
.is_some());
+ debug!("report: ty={:?}", ty);
match ty.sty {
ty::Array(..) | ty::Slice(..) =>
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
}
}
+ // If we didn't find an `Arc` or an `Rc`, then check specifically for
+ // a dereference of a place that has the type of a raw pointer.
+ // We can't use `place.ty(..).to_ty(..)` here as that strips away the raw pointer.
+ if let Place::Projection(box Projection {
+ base,
+ elem: ProjectionElem::Deref,
+ }) = place {
+ if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() {
+ return BorrowedContentSource::DerefRawPointer;
+ }
+ }
+
BorrowedContentSource::Other
}
}
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
use rustc::ty::{self, Region, TyCtxt};
-use rustc::mir::{FakeReadCause, Local, Location, Mir, Operand};
-use rustc::mir::{Place, StatementKind, TerminatorKind};
+use rustc::mir::{
+ CastKind, FakeReadCause, Local, Location, Mir, Operand, Place, Projection, ProjectionElem,
+ Rvalue, Statement, StatementKind, TerminatorKind
+};
use rustc_errors::DiagnosticBuilder;
use syntax_pos::Span;
#[derive(Clone, Copy)]
pub(in borrow_check) enum LaterUseKind {
+ TraitCapture,
ClosureCapture,
Call,
FakeLetRead,
match *self {
BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
let message = match later_use_kind {
+ LaterUseKind::TraitCapture => "borrow later captured here by trait object",
LaterUseKind::ClosureCapture => "borrow later captured here by closure",
LaterUseKind::Call => "borrow later used by call",
LaterUseKind::FakeLetRead => "borrow later stored here",
},
BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
let message = match later_use_kind {
- LaterUseKind::ClosureCapture => {
- "borrow captured here by closure, in later iteration of loop"
- },
+ LaterUseKind::TraitCapture =>
+ "borrow captured here by trait object, in later iteration of loop",
+ LaterUseKind::ClosureCapture =>
+ "borrow captured here by closure, in later iteration of loop",
LaterUseKind::Call => "borrow used by call, in later iteration of loop",
LaterUseKind::FakeLetRead => "borrow later stored here",
LaterUseKind::Other => "borrow used here, in later iteration of loop",
.or_else(|| self.borrow_spans(span, location));
if self.is_borrow_location_in_loop(context.loc) {
- let later_use = self.later_use_kind(spans, location);
+ let later_use = self.later_use_kind(borrow, spans, location);
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
} else {
// Check if the location represents a `FakeRead`, and adapt the error
// message to the `FakeReadCause` it is from: in particular,
// the ones inserted in optimized `let var = <expr>` patterns.
- let later_use = self.later_use_kind(spans, location);
+ let later_use = self.later_use_kind(borrow, spans, location);
BorrowExplanation::UsedLater(later_use.0, later_use.1)
}
}
false
}
- fn later_use_kind(&self, use_spans: UseSpans, location: Location) -> (LaterUseKind, Span) {
- use self::LaterUseKind::*;
-
- let block = &self.mir.basic_blocks()[location.block];
+ /// Determine how the borrow was later used.
+ fn later_use_kind(
+ &self,
+ borrow: &BorrowData<'tcx>,
+ use_spans: UseSpans,
+ location: Location
+ ) -> (LaterUseKind, Span) {
match use_spans {
- UseSpans::ClosureUse { var_span, .. } => (LaterUseKind::ClosureCapture, var_span),
+ UseSpans::ClosureUse { var_span, .. } => {
+ // Used in a closure.
+ (LaterUseKind::ClosureCapture, var_span)
+ },
UseSpans::OtherUse(span) => {
- (if let Some(stmt) = block.statements.get(location.statement_index) {
- match stmt.kind {
- StatementKind::FakeRead(FakeReadCause::ForLet, _) => FakeLetRead,
- _ => Other,
+ let block = &self.mir.basic_blocks()[location.block];
+
+ let kind = if let Some(&Statement {
+ kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
+ ..
+ }) = block.statements.get(location.statement_index) {
+ LaterUseKind::FakeLetRead
+ } else if self.was_captured_by_trait_object(borrow) {
+ LaterUseKind::TraitCapture
+ } else if location.statement_index == block.statements.len() {
+ if let TerminatorKind::Call {
+ ref func, from_hir_call: true, ..
+ } = block.terminator().kind {
+ // Just point to the function, to reduce the chance of overlapping spans.
+ let function_span = match func {
+ Operand::Constant(c) => c.span,
+ Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => {
+ let local_decl = &self.mir.local_decls[*l];
+ if local_decl.name.is_none() {
+ local_decl.source_info.span
+ } else {
+ span
+ }
+ },
+ _ => span,
+ };
+ return (LaterUseKind::Call, function_span);
+ } else {
+ LaterUseKind::Other
}
} else {
- assert_eq!(location.statement_index, block.statements.len());
- match block.terminator().kind {
- TerminatorKind::Call { ref func, from_hir_call: true, .. } => {
- // Just point to the function, to reduce the chance
- // of overlapping spans.
- let function_span = match func {
- Operand::Constant(c) => c.span,
- Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => {
- let local_decl = &self.mir.local_decls[*l];
- if local_decl.name.is_none() {
- local_decl.source_info.span
- } else {
- span
- }
- },
- _ => span,
- };
- return (Call, function_span);
+ LaterUseKind::Other
+ };
+
+ (kind, span)
+ }
+ }
+ }
+
+ /// Check if a borrowed value was captured by a trait object. We do this by
+ /// looking forward in the MIR from the reserve location and checking if we see
+ /// a unsized cast to a trait object on our data.
+ fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
+ // Start at the reserve location, find the place that we want to see cast to a trait object.
+ let location = borrow.reserve_location;
+ let block = &self.mir[location.block];
+ let stmt = block.statements.get(location.statement_index);
+ debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt);
+
+ // We make a `queue` vector that has the locations we want to visit. As of writing, this
+ // will only ever have one item at any given time, but by using a vector, we can pop from
+ // it which simplifies the termination logic.
+ let mut queue = vec![location];
+ let mut target = if let Some(&Statement {
+ kind: StatementKind::Assign(Place::Local(local), _),
+ ..
+ }) = stmt {
+ local
+ } else {
+ return false;
+ };
+
+ debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
+ while let Some(current_location) = queue.pop() {
+ debug!("was_captured_by_trait: target={:?}", target);
+ let block = &self.mir[current_location.block];
+ // We need to check the current location to find out if it is a terminator.
+ let is_terminator = current_location.statement_index == block.statements.len();
+ if !is_terminator {
+ let stmt = &block.statements[current_location.statement_index];
+ debug!("was_captured_by_trait_object: stmt={:?}", stmt);
+
+ // The only kind of statement that we care about is assignments...
+ if let StatementKind::Assign(
+ place,
+ box rvalue,
+ ) = &stmt.kind {
+ let into = match place {
+ Place::Local(into) => into,
+ Place::Projection(box Projection {
+ base: Place::Local(into),
+ elem: ProjectionElem::Deref,
+ }) => into,
+ _ => {
+ // Continue at the next location.
+ queue.push(current_location.successor_within_block());
+ continue;
},
- _ => Other,
+ };
+
+ match rvalue {
+ // If we see a use, we should check whether it is our data, and if so
+ // update the place that we're looking for to that new place.
+ Rvalue::Use(operand) => match operand {
+ Operand::Copy(Place::Local(from)) |
+ Operand::Move(Place::Local(from)) if *from == target => {
+ target = *into;
+ },
+ _ => {},
+ },
+ // If we see a unsized cast, then if it is our data we should check
+ // whether it is being cast to a trait object.
+ Rvalue::Cast(CastKind::Unsize, operand, ty) => match operand {
+ Operand::Copy(Place::Local(from)) |
+ Operand::Move(Place::Local(from)) if *from == target => {
+ debug!("was_captured_by_trait_object: ty={:?}", ty);
+ // Check the type for a trait object.
+ match ty.sty {
+ // `&dyn Trait`
+ ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true,
+ // `Box<dyn Trait>`
+ _ if ty.is_box() && ty.boxed_ty().is_trait() =>
+ return true,
+ // `dyn Trait`
+ _ if ty.is_trait() => return true,
+ // Anything else.
+ _ => return false,
+ }
+ },
+ _ => return false,
+ },
+ _ => {},
}
- }, span)
+ }
+
+ // Continue at the next location.
+ queue.push(current_location.successor_within_block());
+ } else {
+ // The only thing we need to do for terminators is progress to the next block.
+ let terminator = block.terminator();
+ debug!("was_captured_by_trait_object: terminator={:?}", terminator);
+
+ match &terminator.kind {
+ TerminatorKind::Call {
+ destination: Some((Place::Local(dest), block)),
+ args,
+ ..
+ } => {
+ debug!(
+ "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
+ target, dest, args
+ );
+ // Check if one of the arguments to this function is the target place.
+ let found_target = args.iter().any(|arg| {
+ if let Operand::Move(Place::Local(potential)) = arg {
+ *potential == target
+ } else {
+ false
+ }
+ });
+
+ // If it is, follow this to the next block and update the target.
+ if found_target {
+ target = *dest;
+ queue.push(block.start_location());
+ }
+ },
+ _ => {},
+ }
}
+
+ debug!("was_captured_by_trait: queue={:?}", queue);
}
+
+ // We didn't find anything and ran out of locations to check.
+ false
}
}
//! Functions concerning immediate values and operands, and reading from operands.
//! All high-level functions to read from memory work on operands as sources.
-use std::hash::{Hash, Hasher};
use std::convert::TryInto;
use rustc::{mir, ty};
}
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct OpTy<'tcx, Tag=()> {
crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
pub layout: TyLayout<'tcx>,
}
}
-// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type
-impl<'tcx, Tag> Hash for OpTy<'tcx, Tag>
- where Tag: Hash
-{
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.op.hash(state);
- self.layout.ty.hash(state);
- }
-}
-impl<'tcx, Tag> PartialEq for OpTy<'tcx, Tag>
- where Tag: PartialEq
-{
- fn eq(&self, other: &Self) -> bool {
- self.op == other.op && self.layout.ty == other.layout.ty
- }
-}
-impl<'tcx, Tag> Eq for OpTy<'tcx, Tag>
- where Tag: Eq
-{}
-
impl<'tcx, Tag> OpTy<'tcx, Tag>
{
#[inline]
/// to those obtained from `layout_of(ty)`, as we need to produce
/// layouts for which Rust types do not exist, such as enum variants
/// or synthetic fields of enums (i.e. discriminants) and fat pointers.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct TyLayout<'a, Ty> {
pub ty: Ty,
pub details: &'a LayoutDetails
/// the functions in the executable are not randomized and can be used
/// during an exploit of a vulnerability in any code.
pub position_independent_executables: bool,
+ /// Determines if the target always requires using the PLT for indirect
+ /// library calls or not. This controls the default value of the `-Z plt` flag.
+ pub needs_plt: bool,
/// Either partial, full, or off. Full RELRO makes the dynamic linker
/// resolve all symbols at startup and marks the GOT read-only before
/// starting the program, preventing overwriting the GOT.
has_rpath: false,
no_default_libraries: true,
position_independent_executables: false,
+ needs_plt: false,
relro_level: RelroLevel::None,
pre_link_objects_exe: Vec::new(),
pre_link_objects_exe_crt: Vec::new(),
key!(has_rpath, bool);
key!(no_default_libraries, bool);
key!(position_independent_executables, bool);
+ key!(needs_plt, bool);
try!(key!(relro_level, RelroLevel));
key!(archive_format);
key!(allow_asm, bool);
target_option_val!(has_rpath);
target_option_val!(no_default_libraries);
target_option_val!(position_independent_executables);
+ target_option_val!(needs_plt);
target_option_val!(relro_level);
target_option_val!(archive_format);
target_option_val!(allow_asm);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
base.stack_probes = true;
base.has_elf_tls = false;
+ // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
+ // breaks code gen. See LLVM bug 36743
+ base.needs_plt = true;
Ok(Target {
llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
rustc_data_structures = { path = "../librustc_data_structures" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
-chalk-engine = { version = "0.7.0", default-features=false }
+chalk-engine = { version = "0.8.0", default-features=false }
smallvec = { version = "0.6.5", features = ["union"] }
ExClauseFold,
ExClauseLift,
Goal,
+ GoalKind,
ProgramClause,
QuantifierKind
};
type DomainGoal = DomainGoal<'tcx>;
- type BindersGoal = ty::Binder<&'tcx Goal<'tcx>>;
+ type BindersGoal = ty::Binder<Goal<'tcx>>;
type Parameter = Kind<'tcx>;
type UnificationResult = InferOk<'tcx, ()>;
- fn into_goal(domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> {
- Goal::DomainGoal(domain_goal)
- }
-
- fn cannot_prove() -> Goal<'tcx> {
- Goal::CannotProve
- }
-
fn goal_in_environment(
env: &ty::ParamEnv<'tcx>,
goal: Goal<'tcx>,
impl context::InferenceTable<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
for ChalkInferenceContext<'cx, 'gcx, 'tcx>
{
+ fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> {
+ self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal))
+ }
+
+ fn cannot_prove(&self) -> Goal<'tcx> {
+ self.infcx.tcx.mk_goal(GoalKind::CannotProve)
+ }
+
fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> {
- match goal {
- Goal::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"),
- Goal::And(left, right) => HhGoal::And(*left, *right),
- Goal::Not(subgoal) => HhGoal::Not(*subgoal),
- Goal::DomainGoal(d) => HhGoal::DomainGoal(d),
- Goal::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
- Goal::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
- Goal::CannotProve => HhGoal::CannotProve,
+ match *goal {
+ GoalKind::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"),
+ GoalKind::And(left, right) => HhGoal::And(left, right),
+ GoalKind::Not(subgoal) => HhGoal::Not(subgoal),
+ GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d),
+ GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
+ GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
+ GoalKind::CannotProve => HhGoal::CannotProve,
}
}
fn instantiate_binders_universally(
&mut self,
- _arg: &ty::Binder<&'tcx Goal<'tcx>>,
+ _arg: &ty::Binder<Goal<'tcx>>,
) -> Goal<'tcx> {
panic!("FIXME -- universal instantiation needs sgrif's branch")
}
fn instantiate_binders_existentially(
&mut self,
- arg: &ty::Binder<&'tcx Goal<'tcx>>,
+ arg: &ty::Binder<Goal<'tcx>>,
) -> Goal<'tcx> {
let (value, _map) = self.infcx.replace_late_bound_regions_with_fresh_var(
DUMMY_SP,
LateBoundRegionConversionTime::HigherRankedType,
arg,
);
- *value
+ value
}
fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box<dyn Debug + 'v> {
use rustc::hir::map::definitions::DefPathData;
use rustc::hir::{self, ImplPolarity};
use rustc::traits::{
- Clause, Clauses, DomainGoal, FromEnv, Goal, PolyDomainGoal, ProgramClause, WellFormed,
+ Clause,
+ Clauses,
+ DomainGoal,
+ FromEnv,
+ GoalKind,
+ PolyDomainGoal,
+ ProgramClause,
+ WellFormed,
WhereClause,
};
use rustc::ty::query::Providers;
let impl_trait: DomainGoal = trait_pred.lower();
// `FromEnv(Self: Trait<P1..Pn>)`
- let from_env_goal = impl_trait.into_from_env_goal().into_goal();
+ let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
let hypotheses = tcx.intern_goals(&[from_env_goal]);
// `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
let wf_clause = ProgramClause {
goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
hypotheses: tcx.mk_goals(
- wf_conditions.map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+ wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
};
let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause)));
hypotheses: tcx.mk_goals(
where_clauses
.into_iter()
- .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+ .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
};
- tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))])
+ tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
pub fn program_clauses_for_type_def<'a, 'tcx>(
where_clauses
.iter()
.cloned()
- .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+ .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
};
// ```
// `FromEnv(Ty<...>)`
- let from_env_goal = DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal();
+ let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
let hypotheses = tcx.intern_goals(&[from_env_goal]);
// For each where clause `WC`:
}
pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
- _tcx: TyCtxt<'a, 'tcx, 'tcx>,
- _item_id: DefId,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item_id: DefId,
) -> Clauses<'tcx> {
- unimplemented!()
+ // Rule ProjectionEq-Skolemize
+ //
+ // ```
+ // trait Trait<P1..Pn> {
+ // type AssocType<Pn+1..Pm>;
+ // }
+ // ```
+ //
+ // `ProjectionEq` can succeed by skolemizing, see "associated type"
+ // chapter for more:
+ // ```
+ // forall<Self, P1..Pn, Pn+1..Pm> {
+ // ProjectionEq(
+ // <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
+ // (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
+ // )
+ // }
+ // ```
+
+ let item = tcx.associated_item(item_id);
+ debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
+ let trait_id = match item.container {
+ ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id,
+ _ => bug!("not an trait container"),
+ };
+ let trait_ref = ty::TraitRef::identity(tcx, trait_id);
+
+ let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
+ let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
+ let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate {
+ projection_ty,
+ ty: placeholder_ty,
+ });
+
+ let projection_eq_clause = ProgramClause {
+ goal: DomainGoal::Holds(projection_eq),
+ hypotheses: &ty::List::empty(),
+ };
+
+ // Rule WellFormed-AssocTy
+ // ```
+ // forall<Self, P1..Pn, Pn+1..Pm> {
+ // WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
+ // :- Implemented(Self: Trait<P1..Pn>)
+ // }
+ // ```
+
+ let trait_predicate = ty::TraitPredicate { trait_ref };
+ let hypothesis = tcx.mk_goal(
+ DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal()
+ );
+ let wf_clause = ProgramClause {
+ goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
+ hypotheses: tcx.mk_goals(iter::once(hypothesis)),
+ };
+
+ // Rule Implied-Trait-From-AssocTy
+ // ```
+ // forall<Self, P1..Pn, Pn+1..Pm> {
+ // FromEnv(Self: Trait<P1..Pn>)
+ // :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
+ // }
+ // ```
+
+ let hypothesis = tcx.mk_goal(
+ DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal()
+ );
+ let from_env_clause = ProgramClause {
+ goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
+ hypotheses: tcx.mk_goals(iter::once(hypothesis)),
+ };
+
+ let clauses = iter::once(projection_eq_clause)
+ .chain(iter::once(wf_clause))
+ .chain(iter::once(from_env_clause));
+ let clauses = clauses.map(|clause| Clause::ForAll(ty::Binder::dummy(clause)));
+ tcx.mk_clauses(clauses)
}
pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
) -> Clauses<'tcx> {
// Rule Normalize-From-Impl (see rustc guide)
//
- // ```impl<P0..Pn> Trait<A1..An> for A0
- // {
+ // ```
+ // impl<P0..Pn> Trait<A1..An> for A0 {
// type AssocType<Pn+1..Pm> = T;
- // }```
+ // }
+ // ```
//
// FIXME: For the moment, we don't account for where clauses written on the associated
// ty definition (i.e. in the trait def, as in `type AssocType<T> where T: Sized`).
hypotheses: tcx.mk_goals(
hypotheses
.into_iter()
- .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+ .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
),
};
- tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))])
+ tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
[dependencies]
pulldown-cmark = { version = "0.1.2", default-features = false }
-minifier = "0.0.19"
+minifier = "0.0.20"
tempfile = "3"
parking_lot = "0.6.4"
}
write_header(class, &mut out).unwrap();
- let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm, None),
- sess.source_map());
+ let lexer = match lexer::StringReader::new_without_err(&sess, fm, None, "Output from rustc:") {
+ Ok(l) => l,
+ Err(_) => {
+ let first_line = src.lines().next().unwrap_or_else(|| "");
+ let mut err = sess.span_diagnostic
+ .struct_warn(&format!("Invalid doc comment starting with: `{}`\n\
+ (Ignoring this codeblock)",
+ first_line));
+ err.emit();
+ return String::new();
+ }
+ };
+ let mut classifier = Classifier::new(lexer, sess.source_map());
if classifier.write_source(&mut out).is_err() {
+ classifier.lexer.emit_fatal_errors();
return format!("<pre>{}</pre>", src);
}
match self.lexer.try_next_token() {
Ok(tas) => Ok(tas),
Err(_) => {
- self.lexer.emit_fatal_errors();
- self.lexer.sess.span_diagnostic
- .struct_warn("Backing out of syntax highlighting")
- .note("You probably did not intend to render this as a rust code-block")
- .emit();
+ let mut err = self.lexer.sess.span_diagnostic
+ .struct_warn("Backing out of syntax highlighting");
+ err.note("You probably did not intend to render this as a rust code-block");
+ err.emit();
Err(io::Error::new(io::ErrorKind::Other, ""))
}
}
</div>",
version)?;
}
+ }
+ write!(fmt, "<div class=\"sidebar-elems\">")?;
+ if it.is_crate() {
write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
it.name.as_ref().expect("crates always have a name"))?;
}
-
- write!(fmt, "<div class=\"sidebar-elems\">")?;
match it.inner {
clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?,
clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?,
padding-top: 0px;
}
- .sidebar {
+ body > .sidebar {
height: 45px;
min-height: 40px;
- width: calc(100% + 30px);
margin: 0;
margin-left: -15px;
padding: 0 15px;
.anchor {
display: none !important;
}
+
+ h1.fqn {
+ overflow: initial;
+ }
}
@media print {
top: 2px;
}
+#all-types {
+ text-align: center;
+ border: 1px solid;
+ margin: 0 10px;
+ margin-bottom: 10px;
+ display: block;
+ border-radius: 7px;
+}
+#all-types > p {
+ margin: 5px 0;
+}
+
@media (max-width: 700px) {
h4 > .important-traits {
position: absolute;
background-color: rgba(0,0,0,0);
height: 100%;
}
+ .sidebar {
+ width: calc(100% + 30px);
+ }
.show-it {
display: block;
.impl > .collapse-toggle {
left: -10px;
}
+
+ #all-types {
+ margin: 10px;
+ }
}
#main > ul > li {
list-style: none;
}
-#all-types {
- text-align: center;
- border: 1px solid;
- margin: 0 10px;
- margin-bottom: 10px;
- display: block;
- border-radius: 7px;
-}
-#all-types > p {
- margin: 5px 0;
-}
.non-exhaustive {
margin-bottom: 1em;
/// If a file is opened with both read and append access, beware that after
/// opening, and after every write, the position for reading may be set at the
/// end of the file. So, before writing, save the current position (using
- /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+ /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
///
/// ## Note
///
///
/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
/// witnessing a broken invariant through the use of `catch_unwind` (catching a
-/// panic). This trait is a marker trait, so it is automatically implemented for
+/// panic). This trait is an auto trait, so it is automatically implemented for
/// many types, and it is also structurally composed (e.g. a struct is unwind
/// safe if all of its components are unwind safe).
///
/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
/// references with longer lifetimes can be freely coerced into references with shorter ones.
///
+/// Reference equality by address, instead of comparing the values pointed to, is accomplished via
+/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while
+/// [`PartialEq`] compares values.
+///
+/// [`ptr::eq`]: ptr/fn.eq.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+///
+/// ```
+/// use std::ptr;
+///
+/// let five = 5;
+/// let other_five = 5;
+/// let five_ref = &five;
+/// let same_five_ref = &five;
+/// let other_five_ref = &other_five;
+///
+/// assert!(five_ref == same_five_ref);
+/// assert!(five_ref == other_five_ref);
+///
+/// assert!(ptr::eq(five_ref, same_five_ref));
+/// assert!(!ptr::eq(five_ref, other_five_ref));
+/// ```
+///
/// For more information on how to use references, see [the book's section on "References and
/// Borrowing"][book-refs].
///
/// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html
///
+/// # Trait implementations
+///
/// The following traits are implemented for all `&T`, regardless of the type of its referent:
///
/// * [`Copy`]
/// assert!(handle.join().is_err());
/// assert_eq!(INIT.is_completed(), false);
/// ```
- #[unstable(feature = "once_is_completed", issue = "42")]
+ #[unstable(feature = "once_is_completed", issue = "54890")]
#[inline]
pub fn is_completed(&self) -> bool {
// An `Acquire` load is enough because that makes all the initialization
// except according to those terms.
use attr::HasAttrs;
-use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
+use feature_gate::{
+ feature_err,
+ EXPLAIN_STMT_ATTR_SYNTAX,
+ Features,
+ get_features,
+ GateIssue,
+ emit_feature_err,
+};
use {fold, attr};
use ast;
use source_map::Spanned;
if self.in_cfg(node.attrs()) { Some(node) } else { None }
}
+ /// Parse and expand all `cfg_attr` attributes into a list of attributes
+ /// that are within each `cfg_attr` that has a true configuration predicate.
+ ///
+ /// Gives compiler warnigns if any `cfg_attr` does not contain any
+ /// attributes and is in the original source code. Gives compiler errors if
+ /// the syntax of any `cfg_attr` is incorrect.
pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
node.map_attrs(|attrs| {
- attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
+ attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect()
})
}
- fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
+ /// Parse and expand a single `cfg_attr` attribute into a list of attributes
+ /// when the configuration predicate is true, or otherwise expand into an
+ /// empty list of attributes.
+ ///
+ /// Gives a compiler warning when the `cfg_attr` contains no attribtes and
+ /// is in the original source file. Gives a compiler error if the syntax of
+ /// the attribute is incorrect
+ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
if !attr.check_name("cfg_attr") {
- return Some(attr);
+ return vec![attr];
}
- let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| {
+ let gate_cfg_attr_multi = if let Some(ref features) = self.features {
+ !features.cfg_attr_multi
+ } else {
+ false
+ };
+ let cfg_attr_span = attr.span;
+
+ let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
parser.expect(&token::OpenDelim(token::Paren))?;
- let cfg = parser.parse_meta_item()?;
+
+ let cfg_predicate = parser.parse_meta_item()?;
parser.expect(&token::Comma)?;
- let lo = parser.span.lo();
- let (path, tokens) = parser.parse_meta_item_unrestricted()?;
- parser.eat(&token::Comma); // Optional trailing comma
+
+ // Presumably, the majority of the time there will only be one attr.
+ let mut expanded_attrs = Vec::with_capacity(1);
+
+ while !parser.check(&token::CloseDelim(token::Paren)) {
+ let lo = parser.span.lo();
+ let (path, tokens) = parser.parse_meta_item_unrestricted()?;
+ expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
+ parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
+ }
+
parser.expect(&token::CloseDelim(token::Paren))?;
- Ok((cfg, path, tokens, parser.prev_span.with_lo(lo)))
+ Ok((cfg_predicate, expanded_attrs))
}) {
Ok(result) => result,
Err(mut e) => {
e.emit();
- return None;
+ return Vec::new();
}
};
- if attr::cfg_matches(&cfg, self.sess, self.features) {
- self.process_cfg_attr(ast::Attribute {
+ // Check feature gate and lint on zero attributes in source. Even if the feature is gated,
+ // we still compute as if it wasn't, since the emitted error will stop compilation futher
+ // along the compilation.
+ match (expanded_attrs.len(), gate_cfg_attr_multi) {
+ (0, false) => {
+ // FIXME: Emit unused attribute lint here.
+ },
+ (1, _) => {},
+ (_, true) => {
+ emit_feature_err(
+ self.sess,
+ "cfg_attr_multi",
+ cfg_attr_span,
+ GateIssue::Language,
+ "cfg_attr with zero or more than one attributes is experimental",
+ );
+ },
+ (_, false) => {}
+ }
+
+ if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+ // We call `process_cfg_attr` recursively in case there's a
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+ expanded_attrs.into_iter()
+ .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
id: attr::mk_attr_id(),
style: attr.style,
path,
tokens,
is_sugared_doc: false,
span,
- })
+ }))
+ .collect()
} else {
- None
+ Vec::new()
}
}
- // Determine if a node with the given attributes should be included in this configuration.
+ /// Determine if a node with the given attributes should be included in this configuration.
pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
attrs.iter().all(|attr| {
if !is_cfg(attr) {
})
}
- // Visit attributes on expression and statements (but not attributes on items in blocks).
+ /// Visit attributes on expression and statements (but not attributes on items in blocks).
fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
// flag the offending attributes
for attr in attrs.iter() {
// #[doc(alias = "...")]
(active, doc_alias, "1.27.0", Some(50146), None),
- // Scoped lints
- (active, tool_lints, "1.28.0", Some(44690), None),
-
// Allows irrefutable patterns in if-let and while-let statements (RFC 2086)
(active, irrefutable_let_patterns, "1.27.0", Some(44495), None),
// Allows `impl Trait` in bindings (`let`, `const`, `static`)
(active, impl_trait_in_bindings, "1.30.0", Some(34511), None),
+
+ // #[cfg_attr(predicate, multiple, attributes, here)]
+ (active, cfg_attr_multi, "1.31.0", Some(54881), None),
);
declare_features! (
(accepted, pattern_parentheses, "1.31.0", Some(51087), None),
// Allows the definition of `const fn` functions.
(accepted, min_const_fn, "1.31.0", Some(53555), None),
+ // Scoped lints
+ (accepted, tool_lints, "1.31.0", Some(44690), None),
);
// If you change this, please modify src/doc/unstable-book as well. You must
sr
}
+ pub fn new_without_err(sess: &'a ParseSess,
+ source_file: Lrc<syntax_pos::SourceFile>,
+ override_span: Option<Span>,
+ prepend_error_text: &str) -> Result<Self, ()> {
+ let mut sr = StringReader::new_raw(sess, source_file, override_span);
+ if sr.advance_token().is_err() {
+ eprintln!("{}", prepend_error_text);
+ sr.emit_fatal_errors();
+ return Err(());
+ }
+ Ok(sr)
+ }
+
pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
let begin = sess.source_map().lookup_byte_offset(span.lo());
let end = sess.source_map().lookup_byte_offset(span.hi());
/// Expect next token to be edible or inedible token. If edible,
/// then consume it; if inedible, then return without consuming
/// anything. Signal a fatal error if next token is unexpected.
- fn expect_one_of(&mut self,
+ pub fn expect_one_of(&mut self,
edible: &[token::Token],
inedible: &[token::Token]) -> PResult<'a, ()>{
fn tokens_to_string(tokens: &[TokenType]) -> String {
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
+ token::Interpolated(ref nt) => {
+ match &nt.0 {
+ token::NtBlock(..) => {
+ *at_end = true;
+ let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+ attrs.extend(inner_attrs.iter().cloned());
+ Some(body)
+ }
+ _ => {
+ let token_str = self.this_token_to_string();
+ let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
+ token_str));
+ err.span_label(self.span, "expected `;` or `{`");
+ return Err(err);
+ }
+ }
+ }
_ => {
let token_str = self.this_token_to_string();
let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
// check that a comma comes after every field
if !ate_comma {
let err = self.struct_span_err(self.prev_span, "expected `,`");
+ if let Some(mut delayed) = delayed_err {
+ delayed.emit();
+ }
return Err(err);
}
ate_comma = false;
return Attribute::SanitizeAddress;
case SanitizeMemory:
return Attribute::SanitizeMemory;
+ case NonLazyBind:
+ return Attribute::NonLazyBind;
}
report_fatal_error("bad AttributeKind");
}
SanitizeThread = 20,
SanitizeAddress = 21,
SanitizeMemory = 22,
+ NonLazyBind = 23,
};
typedef struct OpaqueRustString *RustStringRef;
#![crate_type = "lib"]
#![feature(naked_functions)]
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define void @naked_empty()
#[no_mangle]
#[naked]
// CHECK-NEXT: ret void
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
#[no_mangle]
#[naked]
// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}})
// CHECK: ret void
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_return()
#[no_mangle]
#[naked]
0
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
#[no_mangle]
#[naked]
a
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define void @naked_recursive()
#[no_mangle]
#[naked]
--- /dev/null
+// Copyright 2018 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: -C relocation-model=pic -Z plt=no
+
+#![crate_type = "lib"]
+
+// We need a function which is normally called through the PLT.
+extern "C" {
+ // CHECK: Function Attrs: nounwind nonlazybind
+ fn getenv(name: *const u8) -> *mut u8;
+}
+
+// Ensure the function gets referenced.
+pub unsafe fn call_through_plt() -> *mut u8 {
+ getenv(b"\0".as_ptr())
+}
+
+// Ensure intrinsics also skip the PLT
+// CHECK: !"RtLibUseGOT"
--- /dev/null
+// Copyright 2012 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.
+//
+// run-pass
+//
+// Description - ensure Interpolated blocks can act as valid function bodies
+// Covered cases: free functions, struct methods, and default trait functions
+
+macro_rules! def_fn {
+ ($body:block) => {
+ fn bar() $body
+ }
+}
+
+trait Foo {
+ def_fn!({ println!("foo"); });
+}
+
+struct Baz {}
+
+impl Foo for Baz {}
+
+struct Qux {}
+
+impl Qux {
+ def_fn!({ println!("qux"); });
+}
+
+def_fn!({ println!("quux"); });
+
+pub fn main() {
+ Baz::bar();
+ Qux::bar();
+ bar();
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(tool_lints)]
+
#![deny(unknown_lints)]
#[allow(clippy::almost_swapped)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(tool_lints)]
+
#![feature(rust_2018_preview)]
#![deny(unknown_lints)]
--- /dev/null
+// Copyright 2018 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-pass
+// compile-flags: --error-format=human
+
+/// ```
+/// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/
+/// ```
+pub fn foo() {}
--- /dev/null
+Output from rustc:
+error: unknown start of token: /
+ --> <stdin>:1:1
+ |
+1 | /__________pkt->size___________/ /_result->size_/ /__pkt->size__/
+ | ^
+
+warning: Invalid doc comment starting with: `/__________pkt->size___________/ /_result->size_/ /__pkt->size__/`
+(Ignoring this codeblock)
+
// aux-build:lint_tool_test.rs
// ignore-stage1
// compile-flags: --cfg foo
+
#![feature(plugin)]
-#![feature(tool_lints)]
#![plugin(lint_tool_test)]
#![allow(dead_code)]
#![cfg_attr(foo, warn(test_lint))]
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub enum Foo {
- A,
- B(isize),
- C { a: isize },
-}
-
-impl Foo {
- pub fn foo() {}
- pub fn bar(&self) {}
-}
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
--> $DIR/borrowck-move-from-unsafe-ptr.rs:13:13
|
LL | let y = *x; //~ ERROR cannot move out of dereference of raw pointer
| ^^
| |
- | cannot move out of borrowed content
+ | cannot move out of dereference of raw pointer
| help: consider removing the `*`: `x`
error: aborting due to previous error
+++ /dev/null
-// compile-flags: --cfg a(b=c)
-// error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`)
-fn main() {}
+++ /dev/null
-// compile-flags: --cfg a{b}
-// error-pattern: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`)
-fn main() {}
+++ /dev/null
-// compile-flags: --cfg a::b
-// error-pattern: invalid `--cfg` argument: `a::b` (argument key must be an identifier)
-fn main() {}
+++ /dev/null
-// compile-flags: --cfg a(b)
-// error-pattern: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`)
-fn main() {}
+++ /dev/null
-// compile-flags: --cfg a=10
-// error-pattern: invalid `--cfg` argument: `a=10` (argument value must be a string)
-fn main() {}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-//
-// error-pattern: `main` function not found
-// compile-flags: --cfg foo
-
-// main is conditionally compiled, but the conditional compilation
-// is conditional too!
-
-#[cfg_attr(foo, cfg(bar))]
-fn main() { }
+++ /dev/null
-error[E0601]: `main` function not found in crate `cfg_attr_cfg_2`
- |
- = note: consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-//
-// compile-flags: --cfg broken
-
-// https://github.com/rust-lang/rust/issues/21833#issuecomment-72353044
-
-#![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental
-
-fn main() { }
+++ /dev/null
-error[E0658]: no_core is experimental (see issue #29639)
- --> $DIR/cfg-attr-crate-2.rs:15:21
- |
-LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental
- | ^^^^^^^^
- |
- = help: add #![feature(no_core)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[cfg(foo(bar))] //~ ERROR invalid predicate `foo`
-fn main() {}
+++ /dev/null
-error[E0537]: invalid predicate `foo`
- --> $DIR/cfg-attr-invalid-predicate.rs:11:7
- |
-LL | #[cfg(foo(bar))] //~ ERROR invalid predicate `foo`
- | ^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0537`.
+++ /dev/null
-#[cfg] //~ ERROR `cfg` is not followed by parentheses
-struct S1;
-
-#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
-struct S2;
-
-#[cfg()] //~ ERROR `cfg` predicate is not specified
-struct S3;
-
-#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
-struct S4;
-
-#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
-struct S5;
-
-#[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
-struct S6;
-
-#[cfg(a())] //~ ERROR invalid predicate `a`
-struct S7;
-
-#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
-struct S8;
-
-macro_rules! generate_s9 {
- ($expr: expr) => {
- #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item
- struct S9;
- }
-}
-
-generate_s9!(concat!("nonexistent"));
+++ /dev/null
-error: `cfg` is not followed by parentheses
- --> $DIR/cfg-attr-syntax-validation.rs:1:1
- |
-LL | #[cfg] //~ ERROR `cfg` is not followed by parentheses
- | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
-
-error: `cfg` is not followed by parentheses
- --> $DIR/cfg-attr-syntax-validation.rs:4:1
- |
-LL | #[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
- | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
-
-error: `cfg` predicate is not specified
- --> $DIR/cfg-attr-syntax-validation.rs:7:1
- |
-LL | #[cfg()] //~ ERROR `cfg` predicate is not specified
- | ^^^^^^^^
-
-error: multiple `cfg` predicates are specified
- --> $DIR/cfg-attr-syntax-validation.rs:10:10
- |
-LL | #[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
- | ^
-
-error: `cfg` predicate key cannot be a literal
- --> $DIR/cfg-attr-syntax-validation.rs:13:7
- |
-LL | #[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
- | ^^^^^
-
-error: `cfg` predicate key must be an identifier
- --> $DIR/cfg-attr-syntax-validation.rs:16:7
- |
-LL | #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
- | ^^^^
-
-error[E0537]: invalid predicate `a`
- --> $DIR/cfg-attr-syntax-validation.rs:19:7
- |
-LL | #[cfg(a())] //~ ERROR invalid predicate `a`
- | ^^^
-
-error: literal in `cfg` predicate value must be a string
- --> $DIR/cfg-attr-syntax-validation.rs:22:11
- |
-LL | #[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
- | ^^
-
-error: `cfg` is not a well-formed meta-item
- --> $DIR/cfg-attr-syntax-validation.rs:27:9
- |
-LL | #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: expected syntax is: `#[cfg(/* predicate */)]`
-...
-LL | generate_s9!(concat!("nonexistent"));
- | ------------------------------------- in this macro invocation
-
-error: aborting due to 9 previous errors
-
-For more information about this error, try `rustc --explain E0537`.
+++ /dev/null
-// compile-flags: --cfg TRUE
-
-#[cfg_attr(TRUE, inline,)] // OK
-fn f() {}
-
-#[cfg_attr(FALSE, inline,)] // OK
-fn g() {}
-
-#[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,`
-fn h() {}
-
-#[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,`
-fn i() {}
+++ /dev/null
-error: expected `)`, found `,`
- --> $DIR/cfg-attr-trailing-comma.rs:9:25
- |
-LL | #[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,`
- | ^ expected `)`
-
-error: expected `)`, found `,`
- --> $DIR/cfg-attr-trailing-comma.rs:12:26
- |
-LL | #[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,`
- | ^ expected `)`
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-macro_rules! foo {
- () => {
- #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown
- fn foo() {}
- }
-}
-
-foo!();
-
-fn main() {}
+++ /dev/null
-error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
- --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:13:27
- |
-LL | #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown
- | ^^^^^^^
-...
-LL | foo!();
- | ------- in this macro invocation
- |
- = help: add #![feature(custom_attribute)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Tests that empty source_maps don't ICE (#23301)
-
-// compile-flags: --cfg ""
-
-// error-pattern: invalid `--cfg` argument: `""` (expected `key` or `key="value"`)
-
-pub fn main() {
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// error-pattern: `main` function not found
-
-#![cfg(bar)]
+++ /dev/null
-error[E0601]: `main` function not found in crate `cfg_in_crate_1`
- |
- = note: consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(stmt_expr_attributes)]
-#![feature(custom_test_frameworks)]
-
-fn main() {
- let _ = #[cfg(unset)] ();
- //~^ ERROR removing an expression is not supported in this position
- let _ = 1 + 2 + #[cfg(unset)] 3;
- //~^ ERROR removing an expression is not supported in this position
- let _ = [1, 2, 3][#[cfg(unset)] 1];
- //~^ ERROR removing an expression is not supported in this position
-}
+++ /dev/null
-error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:15:13
- |
-LL | let _ = #[cfg(unset)] ();
- | ^^^^^^^^^^^^^
-
-error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:17:21
- |
-LL | let _ = 1 + 2 + #[cfg(unset)] 3;
- | ^^^^^^^^^^^^^
-
-error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:19:23
- |
-LL | let _ = [1, 2, 3][#[cfg(unset)] 1];
- | ^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
+++ /dev/null
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-#![deny(unused_attributes)] // c.f #35584
-
-mod auxiliary {
- #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums;
- #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file;
-}
-
-#[rustc_error]
-fn main() { //~ ERROR compilation successful
- let _ = auxiliary::namespaced_enums::Foo::A;
- let _ = auxiliary::nonexistent_file::Foo::A;
-}
+++ /dev/null
-error: compilation successful
- --> $DIR/cfg_attr_path.rs:21:1
- |
-LL | / fn main() { //~ ERROR compilation successful
-LL | | let _ = auxiliary::namespaced_enums::Foo::A;
-LL | | let _ = auxiliary::nonexistent_file::Foo::A;
-LL | | }
- | |_^
-
-error: aborting due to previous error
-
#![feature(rustc_attrs)]
+trait Bar { }
+
#[rustc_dump_program_clauses] //~ ERROR program clause dump
-trait Foo<S, T, U> {
- fn s(_: S) -> S;
- fn t(_: T) -> T;
- fn u(_: U) -> U;
+trait Foo<S, T: ?Sized> {
+ #[rustc_dump_program_clauses] //~ ERROR program clause dump
+ type Assoc: Bar + ?Sized;
}
fn main() {
error: program clause dump
- --> $DIR/lower_trait.rs:13:1
+ --> $DIR/lower_trait.rs:15:1
|
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
- = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
- = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
- = note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
- = note: WellFormed(Self: Foo<S, T, U>) :- Implemented(Self: Foo<S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(U: std::marker::Sized).
+ = note: FromEnv(<Self as Foo<S, T>>::Assoc: Bar) :- FromEnv(Self: Foo<S, T>).
+ = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T>).
+ = note: Implemented(Self: Foo<S, T>) :- FromEnv(Self: Foo<S, T>).
+ = note: WellFormed(Self: Foo<S, T>) :- Implemented(Self: Foo<S, T>), WellFormed(S: std::marker::Sized), WellFormed(<Self as Foo<S, T>>::Assoc: Bar).
-error: aborting due to previous error
+error: program clause dump
+ --> $DIR/lower_trait.rs:17:5
+ |
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: FromEnv(Self: Foo<S, T>) :- FromEnv(Unnormalized(<Self as Foo<S, T>>::Assoc)).
+ = note: ProjectionEq(<Self as Foo<S, T>>::Assoc == Unnormalized(<Self as Foo<S, T>>::Assoc)).
+ = note: WellFormed(Unnormalized(<Self as Foo<S, T>>::Assoc)) :- Implemented(Self: Foo<S, T>).
+
+error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub enum Foo {
+ A,
+ B(isize),
+ C { a: isize },
+}
+
+impl Foo {
+ pub fn foo() {}
+ pub fn bar(&self) {}
+}
--- /dev/null
+// compile-flags: --cfg a(b=c)
+// error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`)
+fn main() {}
--- /dev/null
+// compile-flags: --cfg a{b}
+// error-pattern: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`)
+fn main() {}
--- /dev/null
+// compile-flags: --cfg a::b
+// error-pattern: invalid `--cfg` argument: `a::b` (argument key must be an identifier)
+fn main() {}
--- /dev/null
+// compile-flags: --cfg a(b)
+// error-pattern: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`)
+fn main() {}
--- /dev/null
+// compile-flags: --cfg a=10
+// error-pattern: invalid `--cfg` argument: `a=10` (argument value must be a string)
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// error-pattern: `main` function not found
+// compile-flags: --cfg foo
+
+// main is conditionally compiled, but the conditional compilation
+// is conditional too!
+
+#[cfg_attr(foo, cfg(bar))]
+fn main() { }
--- /dev/null
+error[E0601]: `main` function not found in crate `cfg_attr_cfg_2`
+ |
+ = note: consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// compile-flags: --cfg broken
+
+// https://github.com/rust-lang/rust/issues/21833#issuecomment-72353044
+
+#![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental
+
+fn main() { }
--- /dev/null
+error[E0658]: no_core is experimental (see issue #29639)
+ --> $DIR/cfg-attr-crate-2.rs:15:21
+ |
+LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental
+ | ^^^^^^^
+ |
+ = help: add #![feature(no_core)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(foo(bar))] //~ ERROR invalid predicate `foo`
+fn main() {}
--- /dev/null
+error[E0537]: invalid predicate `foo`
+ --> $DIR/cfg-attr-invalid-predicate.rs:11:7
+ |
+LL | #[cfg(foo(bar))] //~ ERROR invalid predicate `foo`
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0537`.
--- /dev/null
+// Test that cfg_attr doesn't emit any attributes when the
+// configuation variable is false. This mirrors `cfg-attr-multi-true.rs`
+
+// compile-pass
+
+#![warn(unused_must_use)]
+#![feature(cfg_attr_multi)]
+
+#[cfg_attr(any(), deprecated, must_use)]
+struct Struct {}
+
+impl Struct {
+ fn new() -> Struct {
+ Struct {}
+ }
+}
+
+fn main() {
+ Struct::new();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// compile-flags: --cfg broken
+
+#![feature(cfg_attr_multi)]
+#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
+
+fn main() { }
--- /dev/null
+error[E0658]: no_core is experimental (see issue #29639)
+ --> $DIR/cfg-attr-multi-invalid-1.rs:14:21
+ |
+LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
+ | ^^^^^^^
+ |
+ = help: add #![feature(no_core)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// compile-flags: --cfg broken
+
+#![feature(cfg_attr_multi)]
+#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
+
+fn main() { }
--- /dev/null
+error[E0658]: no_core is experimental (see issue #29639)
+ --> $DIR/cfg-attr-multi-invalid-2.rs:14:29
+ |
+LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
+ | ^^^^^^^
+ |
+ = help: add #![feature(no_core)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Test that cfg_attr with multiple attributes actually emits both attributes.
+// This is done by emitting two attributes that cause new warnings, and then
+// triggering those warnings.
+
+// compile-pass
+
+#![warn(unused_must_use)]
+#![feature(cfg_attr_multi)]
+
+#[cfg_attr(all(), deprecated, must_use)]
+struct MustUseDeprecated {}
+
+impl MustUseDeprecated { //~ warning: use of deprecated item
+ fn new() -> MustUseDeprecated { //~ warning: use of deprecated item
+ MustUseDeprecated {} //~ warning: use of deprecated item
+ }
+}
+
+fn main() {
+ MustUseDeprecated::new(); //~ warning: use of deprecated item
+ //| warning: unused `MustUseDeprecated` which must be used
+}
--- /dev/null
+warning: use of deprecated item 'MustUseDeprecated'
+ --> $DIR/cfg-attr-multi-true.rs:13:6
+ |
+LL | impl MustUseDeprecated { //~ warning: use of deprecated item
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(deprecated)] on by default
+
+warning: use of deprecated item 'MustUseDeprecated'
+ --> $DIR/cfg-attr-multi-true.rs:20:5
+ |
+LL | MustUseDeprecated::new(); //~ warning: use of deprecated item
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+warning: use of deprecated item 'MustUseDeprecated'
+ --> $DIR/cfg-attr-multi-true.rs:14:17
+ |
+LL | fn new() -> MustUseDeprecated { //~ warning: use of deprecated item
+ | ^^^^^^^^^^^^^^^^^
+
+warning: use of deprecated item 'MustUseDeprecated'
+ --> $DIR/cfg-attr-multi-true.rs:15:9
+ |
+LL | MustUseDeprecated {} //~ warning: use of deprecated item
+ | ^^^^^^^^^^^^^^^^^
+
+warning: unused `MustUseDeprecated` which must be used
+ --> $DIR/cfg-attr-multi-true.rs:20:5
+ |
+LL | MustUseDeprecated::new(); //~ warning: use of deprecated item
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/cfg-attr-multi-true.rs:7:9
+ |
+LL | #![warn(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
+
--- /dev/null
+// Parse `cfg_attr` with varying numbers of attributes and trailing commas
+
+#![feature(cfg_attr_multi)]
+
+// Completely empty `cfg_attr` input
+#[cfg_attr()] //~ error: expected identifier, found `)`
+struct NoConfigurationPredicate;
+
+// Zero attributes, zero trailing comma (comma manatory here)
+#[cfg_attr(all())] //~ error: expected `,`, found `)`
+struct A0C0;
+
+// Zero attributes, one trailing comma
+#[cfg_attr(all(),)] // Ok
+struct A0C1;
+
+// Zero attributes, two trailing commas
+#[cfg_attr(all(),,)] //~ ERROR expected identifier
+struct A0C2;
+
+// One attribute, no trailing comma
+#[cfg_attr(all(), must_use)] // Ok
+struct A1C0;
+
+// One attribute, one trailing comma
+#[cfg_attr(all(), must_use,)] // Ok
+struct A1C1;
+
+// One attribute, two trailing commas
+#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier
+struct A1C2;
+
+// Two attributes, no trailing comma
+#[cfg_attr(all(), must_use, deprecated)] // Ok
+struct A2C0;
+
+// Two attributes, one trailing comma
+#[cfg_attr(all(), must_use, deprecated,)] // Ok
+struct A2C1;
+
+// Two attributes, two trailing commas
+#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier
+struct A2C2;
+
+fn main() {}
--- /dev/null
+error: expected identifier, found `)`
+ --> $DIR/cfg-attr-parse.rs:6:12
+ |
+LL | #[cfg_attr()] //~ error: expected identifier, found `)`
+ | ^ expected identifier
+
+error: expected `,`, found `)`
+ --> $DIR/cfg-attr-parse.rs:10:17
+ |
+LL | #[cfg_attr(all())] //~ error: expected `,`, found `)`
+ | ^ expected `,`
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:18:18
+ |
+LL | #[cfg_attr(all(),,)] //~ ERROR expected identifier
+ | ^ expected identifier
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:30:28
+ |
+LL | #[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier
+ | ^ expected identifier
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:42:40
+ |
+LL | #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier
+ | ^ expected identifier
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+#[cfg] //~ ERROR `cfg` is not followed by parentheses
+struct S1;
+
+#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
+struct S2;
+
+#[cfg()] //~ ERROR `cfg` predicate is not specified
+struct S3;
+
+#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
+struct S4;
+
+#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
+struct S5;
+
+#[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
+struct S6;
+
+#[cfg(a())] //~ ERROR invalid predicate `a`
+struct S7;
+
+#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
+struct S8;
+
+macro_rules! generate_s9 {
+ ($expr: expr) => {
+ #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item
+ struct S9;
+ }
+}
+
+generate_s9!(concat!("nonexistent"));
--- /dev/null
+error: `cfg` is not followed by parentheses
+ --> $DIR/cfg-attr-syntax-validation.rs:1:1
+ |
+LL | #[cfg] //~ ERROR `cfg` is not followed by parentheses
+ | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+
+error: `cfg` is not followed by parentheses
+ --> $DIR/cfg-attr-syntax-validation.rs:4:1
+ |
+LL | #[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
+ | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+
+error: `cfg` predicate is not specified
+ --> $DIR/cfg-attr-syntax-validation.rs:7:1
+ |
+LL | #[cfg()] //~ ERROR `cfg` predicate is not specified
+ | ^^^^^^^^
+
+error: multiple `cfg` predicates are specified
+ --> $DIR/cfg-attr-syntax-validation.rs:10:10
+ |
+LL | #[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
+ | ^
+
+error: `cfg` predicate key cannot be a literal
+ --> $DIR/cfg-attr-syntax-validation.rs:13:7
+ |
+LL | #[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
+ | ^^^^^
+
+error: `cfg` predicate key must be an identifier
+ --> $DIR/cfg-attr-syntax-validation.rs:16:7
+ |
+LL | #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
+ | ^^^^
+
+error[E0537]: invalid predicate `a`
+ --> $DIR/cfg-attr-syntax-validation.rs:19:7
+ |
+LL | #[cfg(a())] //~ ERROR invalid predicate `a`
+ | ^^^
+
+error: literal in `cfg` predicate value must be a string
+ --> $DIR/cfg-attr-syntax-validation.rs:22:11
+ |
+LL | #[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
+ | ^^
+
+error: `cfg` is not a well-formed meta-item
+ --> $DIR/cfg-attr-syntax-validation.rs:27:9
+ |
+LL | #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: expected syntax is: `#[cfg(/* predicate */)]`
+...
+LL | generate_s9!(concat!("nonexistent"));
+ | ------------------------------------- in this macro invocation
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0537`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! foo {
+ () => {
+ #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown
+ fn foo() {}
+ }
+}
+
+foo!();
+
+fn main() {}
--- /dev/null
+error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+ --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:13:27
+ |
+LL | #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown
+ | ^^^^^^^
+...
+LL | foo!();
+ | ------- in this macro invocation
+ |
+ = help: add #![feature(custom_attribute)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that empty source_maps don't ICE (#23301)
+
+// compile-flags: --cfg ""
+
+// error-pattern: invalid `--cfg` argument: `""` (expected `key` or `key="value"`)
+
+pub fn main() {
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: `main` function not found
+
+#![cfg(bar)]
--- /dev/null
+error[E0601]: `main` function not found in crate `cfg_in_crate_1`
+ |
+ = note: consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(stmt_expr_attributes)]
+#![feature(custom_test_frameworks)]
+
+fn main() {
+ let _ = #[cfg(unset)] ();
+ //~^ ERROR removing an expression is not supported in this position
+ let _ = 1 + 2 + #[cfg(unset)] 3;
+ //~^ ERROR removing an expression is not supported in this position
+ let _ = [1, 2, 3][#[cfg(unset)] 1];
+ //~^ ERROR removing an expression is not supported in this position
+}
--- /dev/null
+error: removing an expression is not supported in this position
+ --> $DIR/cfg-non-opt-expr.rs:15:13
+ |
+LL | let _ = #[cfg(unset)] ();
+ | ^^^^^^^^^^^^^
+
+error: removing an expression is not supported in this position
+ --> $DIR/cfg-non-opt-expr.rs:17:21
+ |
+LL | let _ = 1 + 2 + #[cfg(unset)] 3;
+ | ^^^^^^^^^^^^^
+
+error: removing an expression is not supported in this position
+ --> $DIR/cfg-non-opt-expr.rs:19:23
+ |
+LL | let _ = [1, 2, 3][#[cfg(unset)] 1];
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+#![deny(unused_attributes)] // c.f #35584
+
+mod auxiliary {
+ #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums;
+ #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file;
+}
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+ let _ = auxiliary::namespaced_enums::Foo::A;
+ let _ = auxiliary::nonexistent_file::Foo::A;
+}
--- /dev/null
+error: compilation successful
+ --> $DIR/cfg_attr_path.rs:21:1
+ |
+LL | / fn main() { //~ ERROR compilation successful
+LL | | let _ = auxiliary::namespaced_enums::Foo::A;
+LL | | let _ = auxiliary::nonexistent_file::Foo::A;
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+// gate-test-cfg_attr_multi
+
+#![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))]
+//~^ ERROR cfg_attr with zero or more than one attributes is experimental
+fn main() {}
--- /dev/null
+error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881)
+ --> $DIR/feature-gate-cfg-attr-multi-1.rs:3:1
+ |
+LL | #![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(cfg_attr_multi)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+#![cfg_attr(all(),)]
+//~^ ERROR cfg_attr with zero or more than one attributes is experimental
+fn main() {}
--- /dev/null
+error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881)
+ --> $DIR/feature-gate-cfg-attr-multi-2.rs:1:1
+ |
+LL | #![cfg_attr(all(),)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(cfg_attr_multi)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Test that settingt the featute gate while using its functionality doesn't error.
+
+// compile-pass
+
+#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")]
+
+fn main() {}
--- /dev/null
+// Test that settingt the featute gate while using its functionality doesn't error.
+// Specifically, if there's a cfg-attr *before* the feature gate.
+
+// compile-pass
+
+#![cfg_attr(all(),)]
+#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")]
+
+fn main() {}
+++ /dev/null
-// Copyright 2018 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.
-
-#[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental
-fn main() {}
+++ /dev/null
-error[E0658]: scoped lint `clippy::assign_ops` is experimental (see issue #44690)
- --> $DIR/feature-gate-tool_lints-fail.rs:11:8
- |
-LL | #[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental
- | ^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(tool_lints)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// Copyright 2018 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.
-
-#[warn(clippy::decimal_literal_representation)]
-//~^ ERROR scoped lint `clippy::decimal_literal_representation` is experimental
-fn main() {
- let a = 65_535;
-}
+++ /dev/null
-error[E0658]: scoped lint `clippy::decimal_literal_representation` is experimental (see issue #44690)
- --> $DIR/feature-gate-tool_lints.rs:11:8
- |
-LL | #[warn(clippy::decimal_literal_representation)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(tool_lints)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2018 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.
+
+// Test that the compiler will catch passing invalid values to inline assembly
+// operands.
+
+#![feature(asm)]
+
+#[repr(C)]
+struct MyPtr(usize);
+
+fn main() {
+ issue_37433();
+ issue_37437();
+ issue_40187();
+ issue_54067();
+}
+
+fn issue_37433() {
+ unsafe {
+ asm!("" :: "r"("")); //~ ERROR E0669
+ }
+
+ unsafe {
+ let target = MyPtr(0);
+ asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
+ }
+}
+
+fn issue_37437() {
+ let hello: &str = "hello";
+ // this should fail...
+ unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
+ // but this should succeed.
+ unsafe { asm!("" :: "r"(hello.as_ptr())) };
+}
+
+fn issue_40187() {
+ let arr: [u8; 1] = [0; 1];
+ unsafe {
+ asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
+ }
+}
+
+fn issue_54067() {
+ let addr: Option<u32> = Some(123);
+ unsafe {
+ asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
+ }
+}
--- /dev/null
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/inline-asm-bad-operand.rs:28:9
+ |
+LL | asm!("" :: "r"("")); //~ ERROR E0669
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/inline-asm-bad-operand.rs:33:9
+ |
+LL | asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/inline-asm-bad-operand.rs:40:14
+ |
+LL | unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/inline-asm-bad-operand.rs:48:9
+ |
+LL | asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/inline-asm-bad-operand.rs:55:9
+ |
+LL | asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0669`.
| cannot move out of borrowed content
| help: consider removing the `*`: `imm_ref()`
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
--> $DIR/issue-20801.rs:42:22
|
LL | let c = unsafe { *mut_ptr() };
| ^^^^^^^^^^
| |
- | cannot move out of borrowed content
+ | cannot move out of dereference of raw pointer
| help: consider removing the `*`: `mut_ptr()`
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
--> $DIR/issue-20801.rs:45:22
|
LL | let d = unsafe { *const_ptr() };
| ^^^^^^^^^^^^
| |
- | cannot move out of borrowed content
+ | cannot move out of dereference of raw pointer
| help: consider removing the `*`: `const_ptr()`
error: aborting due to 4 previous errors
--- /dev/null
+#![feature(never_type)]
+
+#![deny(unused_must_use)]
+
+#[must_use]
+fn foo() {}
+
+#[must_use]
+fn bar() -> ! {
+ unimplemented!()
+}
+
+fn main() {
+ foo(); //~ unused return value of `foo`
+
+ bar(); //~ unused return value of `bar`
+}
--- /dev/null
+error: unused return value of `foo` which must be used
+ --> $DIR/must_use-unit.rs:14:5
+ |
+LL | foo(); //~ unused return value of `foo`
+ | ^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/must_use-unit.rs:3:9
+ |
+LL | #![deny(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
+
+error: unused return value of `bar` which must be used
+ --> $DIR/must_use-unit.rs:16:5
+ |
+LL | bar(); //~ unused return value of `bar`
+ | ^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax)]
+#![feature(nll)]
+
+trait Foo { fn get(&self); }
+
+impl<A> Foo for A {
+ fn get(&self) { }
+}
+
+fn main() {
+ let _ = {
+ let tmp0 = 3;
+ let tmp1 = &tmp0;
+ box tmp1 as Box<Foo + '_>
+ };
+ //~^^^ ERROR `tmp0` does not live long enough
+}
--- /dev/null
+error[E0597]: `tmp0` does not live long enough
+ --> $DIR/issue-52663-trait-object.rs:23:20
+ |
+LL | let tmp1 = &tmp0;
+ | ^^^^^ borrowed value does not live long enough
+LL | box tmp1 as Box<Foo + '_>
+ | ------------------------- borrow later captured here by trait object
+LL | };
+ | - `tmp0` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 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.
+struct MyStruct {
+ pub s1: Option<String>,
+}
+
+fn main() {
+ let thing = MyStruct { s1: None };
+
+ match thing {
+ MyStruct { .., Some(_) } => {},
+ _ => {}
+ }
+}
--- /dev/null
+error: expected `}`, found `,`
+ --> $DIR/issue-54379.rs:18:22
+ |
+LL | MyStruct { .., Some(_) } => {},
+ | --^
+ | | |
+ | | expected `}`
+ | `..` must be at the end and cannot have a trailing comma
+
+error: expected `,`
+ --> $DIR/issue-54379.rs:18:24
+ |
+LL | MyStruct { .., Some(_) } => {},
+ | ^^^^
+
+error[E0027]: pattern does not mention field `s1`
+ --> $DIR/issue-54379.rs:18:9
+ |
+LL | MyStruct { .., Some(_) } => {},
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
LL | let tmp1 = &tmp0;
| ^^^^^ borrowed value does not live long enough
LL | repeater3(tmp1)
- | --------------- borrow later used here
+ | --------------- borrow later captured here by trait object
LL | };
| - `tmp0` dropped here while still borrowed
// Don't allow tool_lints, which aren't scoped
-#![feature(tool_lints)]
+
#![deny(unknown_lints)]
#![deny(clippy)] //~ ERROR: unknown lint: `clippy`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(tool_lints)]
+
#[warn(foo::bar)]
//~^ ERROR an unknown tool name found in scoped lint: `foo::bar`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(tool_lints)]
+
#![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`