+Version 1.29.2 (2018-10-11)
+===========================
+
+- [Workaround for an aliasing-related LLVM bug, which caused miscompilation.][54639]
+- The `rls-preview` component on the windows-gnu targets has been restored.
+
+[54639]: https://github.com/rust-lang/rust/pull/54639
+
Version 1.29.1 (2018-09-25)
===========================
# =============================================================================
[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);
initial_rustc: PathBuf,
initial_cargo: PathBuf,
- // Probed tools at runtime
- lldb_version: Option<String>,
- lldb_python_dir: Option<String>,
-
// Runtime state filled in later on
// C/C++ compilers and archiver for all targets
cc: HashMap<Interned<String>, cc::Tool>,
ar: HashMap::new(),
ranlib: HashMap::new(),
crates: HashMap::new(),
- lldb_version: None,
- lldb_python_dir: None,
is_sudo,
ci_env: CiEnv::current(),
delayed_failures: RefCell::new(Vec::new()),
}
}
- let run = |cmd: &mut Command| {
- cmd.output().map(|output| {
- String::from_utf8_lossy(&output.stdout)
- .lines().next().unwrap_or_else(|| {
- panic!("{:?} failed {:?}", cmd, output)
- }).to_string()
- })
- };
- build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
- if build.lldb_version.is_some() {
- build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
- }
-
if let Some(ref s) = build.config.ccache {
cmd_finder.must_have(s);
}
if let Some(ref gdb) = builder.config.gdb {
cmd.arg("--gdb").arg(gdb);
}
- if let Some(ref vers) = builder.lldb_version {
+
+ let run = |cmd: &mut Command| {
+ cmd.output().map(|output| {
+ String::from_utf8_lossy(&output.stdout)
+ .lines().next().unwrap_or_else(|| {
+ panic!("{:?} failed {:?}", cmd, output)
+ }).to_string()
+ })
+ };
+ let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
+ // Test against the lldb that was just built.
+ builder.llvm_out(target)
+ .join("bin")
+ .join("lldb")
+ } else {
+ PathBuf::from("lldb")
+ };
+ let lldb_version = Command::new(&lldb_exe)
+ .arg("--version")
+ .output()
+ .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() })
+ .ok();
+ if let Some(ref vers) = lldb_version {
cmd.arg("--lldb-version").arg(vers);
- }
- if let Some(ref dir) = builder.lldb_python_dir {
- cmd.arg("--lldb-python-dir").arg(dir);
+ let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
+ if let Some(ref dir) = lldb_python_dir {
+ cmd.arg("--lldb-python-dir").arg(dir);
+ }
}
// Get paths from cmd args
#TOC { display: none; }
.header-section-number { display: none; }
li {list-style-type: none; }
+#search-input {
+ width: calc(100% - 100px);
+}
+#search-but {
+ cursor: pointer;
+}
+#search-but, #search-input {
+ padding: 4px;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ outline: none;
+ font-size: 0.7em;
+ background-color: #fff;
+}
+#search-but:hover, #search-input:focus {
+ border-color: #55a9ff;
+}
+#search-from {
+ border: none;
+ padding: 0;
+ font-size: 0.7em;
+}
</style>
Looks like you've taken a wrong turn.
# Search
-<form action="https://duckduckgo.com/">
- <input type="text" id="site-search" name="q" size="80"></input>
- <input type="submit" value="Search DuckDuckGo"></form>
-
-Rust doc search: <span id="core-search"></span>
+<div>
+ <form id="search-form" action="https://duckduckgo.com/">
+ <input id="search-input" type="search" name="q"></input>
+ <input type="submit" value="Search" id="search-but">
+ <!--
+ Don't show the options by default,
+ since "From the Standary Library" doesn't work without JavaScript
+ -->
+ <fieldset id="search-from" style="display:none">
+ <label><input name="from" value="library" type="radio"> From the Standard Library</label>
+ <label><input name="from" value="duckduckgo" type="radio" checked> From DuckDuckGo</label>
+ </fieldset>
+ </form>
+</div>
# Reference
return op;
}
-function populate_site_search() {
- var op = get_url_fragments();
+function on_submit(event) {
+ var form = event.target;
+ var q = form['q'].value;
+
+ event.preventDefault();
- var search = document.getElementById('site-search');
- search.value = op.join(' ') + " site:doc.rust-lang.org";
+ if (form['from'].value === 'duckduckgo') {
+ document.location.href = form.action + '?q=' + encodeURIComponent(q + ' site:doc.rust-lang.org');
+ } else if (form['from'].value === 'library') {
+ document.location.href = 'std/index.html?search=' + encodeURIComponent(q);
+ }
}
-function populate_rust_search() {
- var op = get_url_fragments();
- var lt = op.pop();
+function populate_search() {
+ var form = document.getElementById('search-form');
+ form.addEventListener('submit', on_submit);
+ document.getElementById('search-from').style.display = '';
- // #18540, use a single token
+ form['from'].value = 'library';
- var a = document.createElement("a");
- a.href = "https://doc.rust-lang.org/core/?search=" + encodeURIComponent(lt);
- a.textContent = lt;
- var search = document.getElementById('core-search');
- search.innerHTML = "";
- search.appendChild(a);
+ var op = get_url_fragments();
+ document.getElementById('search-input').value = op.join(' ');
}
-populate_site_search();
-populate_rust_search();
+populate_search();
</script>
--- /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(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
-#![feature(min_const_fn)]
+#![cfg_attr(stage0, feature(min_const_fn))]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
+#![feature(maybe_uninit)]
// Allow testing this library
#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for str {
type Owned = String;
+ #[inline]
fn to_owned(&self) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for String {
+ #[inline]
fn from(s: &'a str) -> String {
s.to_owned()
}
#![feature(allocator_api)]
#![feature(alloc_system)]
#![feature(box_syntax)]
-#![feature(min_const_fn)]
+#![cfg_attr(stage0, feature(min_const_fn))]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(pattern)]
/// 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:
/// # 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);
/// Binary searches this sorted slice for a given element.
///
- /// If the value is found then `Ok` is returned, containing the
- /// index of the matching element; if the value is not found then
- /// `Err` is returned, containing the index where a matching
+ /// If the value is found then [`Result::Ok`] is returned, containing the
+ /// index of the matching element. If there are multiple matches, then any
+ /// one of the matches could be returned. If the value is not found then
+ /// [`Result::Err`] is returned, containing the index where a matching
/// element could be inserted while maintaining sorted order.
///
/// # Examples
/// order code that indicates whether its argument is `Less`,
/// `Equal` or `Greater` the desired target.
///
- /// If a matching value is found then returns `Ok`, containing
- /// the index for the matched element; if no match is found then
- /// `Err` is returned, containing the index where a matching
+ /// If the value is found then [`Result::Ok`] is returned, containing the
+ /// index of the matching element. If there are multiple matches, then any
+ /// one of the matches could be returned. If the value is not found then
+ /// [`Result::Err`] is returned, containing the index where a matching
/// element could be inserted while maintaining sorted order.
///
/// # Examples
/// Assumes that the slice is sorted by the key, for instance with
/// [`sort_by_key`] using the same key extraction function.
///
- /// If a matching value is found then returns `Ok`, containing the
- /// index for the matched element; if no match is found then `Err`
- /// is returned, containing the index where a matching element could
- /// be inserted while maintaining sorted order.
+ /// If the value is found then [`Result::Ok`] is returned, containing the
+ /// index of the matching element. If there are multiple matches, then any
+ /// one of the matches could be returned. If the value is not found then
+ /// [`Result::Err`] is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
///
/// [`sort_by_key`]: #method.sort_by_key
///
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)]
//! ```rust
//! #![feature(rustc_private)]
//!
-//! use graphviz::IntoCow;
//! use std::io::Write;
//! use graphviz as dot;
//!
//! }
//! nodes.sort();
//! nodes.dedup();
-//! nodes.into_cow()
+//! nodes.into()
//! }
//!
//! fn edges(&'a self) -> dot::Edges<'a,Ed> {
//! let &Edges(ref edges) = self;
-//! (&edges[..]).into_cow()
+//! (&edges[..]).into()
//! }
//!
//! fn source(&self, e: &Ed) -> Nd { let &(s,_) = e; s }
//! Since both the set of nodes and the set of edges are always
//! constructed from scratch via iterators, we use the `collect()` method
//! from the `Iterator` trait to collect the nodes and edges into freshly
-//! constructed growable `Vec` values (rather use the `into_cow`
-//! from the `IntoCow` trait as was used in the first example
-//! above).
+//! constructed growable `Vec` values (rather than using `Cow` as in the
+//! first example above).
//!
//! The output from this example renders four nodes that make up the
//! Hasse-diagram for the subsets of the set `{x, y}`. Each edge is
use self::LabelText::*;
-use std::borrow::{Cow, ToOwned};
+use std::borrow::Cow;
use std::io::prelude::*;
use std::io;
///
/// Passing an invalid string (containing spaces, brackets,
/// quotes, ...) will return an empty `Err` value.
- pub fn new<Name: IntoCow<'a, str>>(name: Name) -> Result<Id<'a>, ()> {
- let name = name.into_cow();
+ pub fn new<Name: Into<Cow<'a, str>>>(name: Name) -> Result<Id<'a>, ()> {
+ let name = name.into();
match name.chars().next() {
Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
_ => return Err(()),
/// The label need not be unique, and may be the empty string; the
/// default is in fact the empty string.
fn edge_label(&'a self, _e: &Self::Edge) -> LabelText<'a> {
- LabelStr("".into_cow())
+ LabelStr("".into())
}
/// Maps `n` to a style that will be used in the rendered output.
}
impl<'a> LabelText<'a> {
- pub fn label<S: IntoCow<'a, str>>(s: S) -> LabelText<'a> {
- LabelStr(s.into_cow())
+ pub fn label<S: Into<Cow<'a, str>>>(s: S) -> LabelText<'a> {
+ LabelStr(s.into())
}
- pub fn escaped<S: IntoCow<'a, str>>(s: S) -> LabelText<'a> {
- EscStr(s.into_cow())
+ pub fn escaped<S: Into<Cow<'a, str>>>(s: S) -> LabelText<'a> {
+ EscStr(s.into())
}
- pub fn html<S: IntoCow<'a, str>>(s: S) -> LabelText<'a> {
- HtmlStr(s.into_cow())
+ pub fn html<S: Into<Cow<'a, str>>>(s: S) -> LabelText<'a> {
+ HtmlStr(s.into())
}
fn escape_char<F>(c: char, mut f: F)
EscStr(s) => s,
LabelStr(s) => {
if s.contains('\\') {
- (&*s).escape_default().into_cow()
+ (&*s).escape_default().into()
} else {
s
}
let suffix = suffix.pre_escaped_content();
prefix.push_str(r"\n\n");
prefix.push_str(&suffix);
- EscStr(prefix.into_cow())
+ EscStr(prefix.into())
}
}
writeln!(w, "}}")
}
-pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
- fn into_cow(self) -> Cow<'a, B>;
-}
-
-impl<'a> IntoCow<'a, str> for String {
- fn into_cow(self) -> Cow<'a, str> {
- Cow::Owned(self)
- }
-}
-
-impl<'a> IntoCow<'a, str> for &'a str {
- fn into_cow(self) -> Cow<'a, str> {
- Cow::Borrowed(self)
- }
-}
-
-impl<'a> IntoCow<'a, str> for Cow<'a, str> {
- fn into_cow(self) -> Cow<'a, str> {
- self
- }
-}
-
-impl<'a, T: Clone> IntoCow<'a, [T]> for Vec<T> {
- fn into_cow(self) -> Cow<'a, [T]> {
- Cow::Owned(self)
- }
-}
-
-impl<'a, T: Clone> IntoCow<'a, [T]> for &'a [T] {
- fn into_cow(self) -> Cow<'a, [T]> {
- Cow::Borrowed(self)
- }
-}
-
#[cfg(test)]
mod tests {
use self::NodeLabels::*;
use super::LabelText::{self, LabelStr, EscStr, HtmlStr};
use std::io;
use std::io::prelude::*;
- use IntoCow;
/// each node is an index in a vector in the graph.
type Node = usize;
}
fn node_label(&'a self, n: &Node) -> LabelText<'a> {
match self.node_labels[*n] {
- Some(ref l) => LabelStr(l.into_cow()),
+ Some(l) => LabelStr(l.into()),
None => LabelStr(id_name(n).name()),
}
}
fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
- LabelStr(e.label.into_cow())
+ LabelStr(e.label.into())
}
fn node_style(&'a self, n: &Node) -> Style {
self.node_styles[*n]
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"] }
// For clarity, rename the graphviz crate locally to dot.
use graphviz as dot;
-use graphviz::IntoCow;
use cfg;
use hir;
fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {
if i == self.cfg.entry {
- dot::LabelText::LabelStr("entry".into_cow())
+ dot::LabelText::LabelStr("entry".into())
} else if i == self.cfg.exit {
- dot::LabelText::LabelStr("exit".into_cow())
+ dot::LabelText::LabelStr("exit".into())
} else if n.data.id() == hir::DUMMY_ITEM_LOCAL_ID {
- dot::LabelText::LabelStr("(dummy_node)".into_cow())
+ dot::LabelText::LabelStr("(dummy_node)".into())
} else {
let s = self.local_id_to_string(n.data.id());
- dot::LabelText::EscStr(s.into_cow())
+ dot::LabelText::EscStr(s.into())
}
}
fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> {
let mut label = String::new();
if !self.labelled_edges {
- return dot::LabelText::EscStr(label.into_cow());
+ return dot::LabelText::EscStr(label.into());
}
let mut put_one = false;
for (i, &id) in e.data.exiting_scopes.iter().enumerate() {
i,
&s[..]));
}
- dot::LabelText::EscStr(label.into_cow())
+ dot::LabelText::EscStr(label.into())
}
}
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> {
let mut v = Vec::new();
self.graph.each_node(|i, nd| { v.push((i, nd)); true });
- v.into_cow()
+ v.into()
}
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
self.graph.all_edges().iter().collect()
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
subject,
outlived_free_region,
- blame_span
+ blame_span,
+ category
+});
+
+impl_stable_hash_for!(enum mir::ConstraintCategory {
+ Return,
+ TypeAnnotation,
+ Cast,
+ ClosureBounds,
+ CallArgument,
+ CopyBound,
+ SizedBound,
+ Assignment,
+ OpaqueType,
+ Boring,
+ BoringNoLocation,
+ Internal,
});
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubject<'gcx> {
}
}
-impl_stable_hash_for!(struct mir::interpret::Pointer {
- alloc_id,
- offset
-});
+impl<'a, Tag> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Pointer<Tag>
+where Tag: HashStable<StableHashingContext<'a>>
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ let ::mir::interpret::Pointer { alloc_id, offset, tag } = self;
+ alloc_id.hash_stable(hcx, hasher);
+ offset.hash_stable(hcx, hasher);
+ tag.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, Tag> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Scalar<Tag>
+where Tag: HashStable<StableHashingContext<'a>>
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use mir::interpret::Scalar::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match self {
+ Bits { bits, size } => {
+ bits.hash_stable(hcx, hasher);
+ size.hash_stable(hcx, hasher);
+ },
+ Ptr(ptr) => ptr.hash_stable(hcx, hasher),
+ }
+ }
+}
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
fn hash_stable<W: StableHasherResult>(
Mutable
});
-
-impl<'a> HashStable<StableHashingContext<'a>>
-for ::mir::interpret::Scalar {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
- use mir::interpret::Scalar::*;
-
- mem::discriminant(self).hash_stable(hcx, hasher);
- match *self {
- Bits { bits, size } => {
- bits.hash_stable(hcx, hasher);
- size.hash_stable(hcx, hasher);
- },
- Ptr(ptr) => ptr.hash_stable(hcx, hasher),
- }
- }
-}
-
impl_stable_hash_for!(struct ty::Const<'tcx> {
ty,
val
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
+ FunctionRetMismatch(a, b) => {
+ a.hash_stable(hcx, hasher);
+ b.hash_stable(hcx, hasher)
+ },
NoMirFor(ref s) => s.hash_stable(hcx, hasher),
UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher),
PointerOutOfBounds {
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 {
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(min_const_fn)]
+#![cfg_attr(stage0, feature(min_const_fn))]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![cfg_attr(windows, feature(libc))]
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 {
krate: &hir::Crate)
-> Vec<ast::NodeId>
{
- let worklist = access_levels.map.iter().map(|(&id, _)| id).chain(
+ let worklist = access_levels.map.iter().filter_map(|(&id, level)| {
+ if level >= &privacy::AccessLevel::Reachable {
+ Some(id)
+ } else {
+ None
+ }
+ }).chain(
// Seed entry point
tcx.sess.entry_fn.borrow().map(|(id, _, _)| id)
).collect::<Vec<_>>();
use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use hir::map::Map;
use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, ParamName, Node};
-use ty::{self, TyCtxt, GenericParamDefKind};
+use ty::{self, TyCtxt, DefIdTree, GenericParamDefKind};
-use errors::DiagnosticBuilder;
+use errors::{Applicability, DiagnosticBuilder};
use rustc::lint;
use rustc_data_structures::sync::Lrc;
use session::Session;
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
}
+ /// helper method to determine the span to remove when suggesting the
+ /// deletion of a lifetime
+ fn lifetime_deletion_span(&self, name: ast::Ident, generics: &hir::Generics) -> Option<Span> {
+ if generics.params.len() == 1 {
+ // if sole lifetime, remove the `<>` brackets
+ Some(generics.span)
+ } else {
+ generics.params.iter().enumerate()
+ .find_map(|(i, param)| {
+ if param.name.ident() == name {
+ // We also want to delete a leading or trailing comma
+ // as appropriate
+ if i >= generics.params.len() - 1 {
+ Some(generics.params[i-1].span.shrink_to_hi().to(param.span))
+ } else {
+ Some(param.span.to(generics.params[i+1].span.shrink_to_lo()))
+ }
+ } else {
+ None
+ }
+ })
+ }
+ }
+
fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
let defined_by = match self.scope {
Scope::Binder { lifetimes, .. } => lifetimes,
_ => None,
} {
debug!("id ={:?} span = {:?} name = {:?}", node_id, span, name);
- self.tcx.struct_span_lint_node(
+ let mut err = self.tcx.struct_span_lint_node(
lint::builtin::UNUSED_LIFETIMES,
id,
span,
&format!("lifetime parameter `{}` never used", name)
- ).emit();
+ );
+ if let Some(parent_def_id) = self.tcx.parent(def_id) {
+ if let Some(generics) = self.tcx.hir.get_generics(parent_def_id) {
+ let unused_lt_span = self.lifetime_deletion_span(name, generics);
+ if let Some(span) = unused_lt_span {
+ err.span_suggestion_with_applicability(
+ span,
+ "remove it",
+ String::new(),
+ Applicability::MachineApplicable
+ );
+ }
+ }
+ }
+ err.emit();
}
}
}
FunctionAbiMismatch(Abi, Abi),
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
+ FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionArgCountMismatch,
NoMirFor(String),
UnterminatedCString(Pointer),
use self::EvalErrorKind::*;
match *self {
MachineError(ref inner) => inner,
- FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionArgCountMismatch =>
+ FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
+ | FunctionArgCountMismatch =>
"tried to call a function through a function pointer of incompatible type",
InvalidMemoryAccess =>
"tried to access memory through an invalid pointer",
write!(f, "tried to call a function with argument of type {:?} \
passing data of type {:?}",
callee_ty, caller_ty),
+ FunctionRetMismatch(caller_ty, callee_ty) =>
+ write!(f, "tried to call a function with return type {:?} \
+ passing return place of type {:?}",
+ callee_ty, caller_ty),
FunctionArgCountMismatch =>
write!(f, "tried to call a function with incorrect number of arguments"),
BoundsCheck { ref len, ref index } =>
/// each context.
///
/// Defaults to the index based and loosely coupled AllocId.
+///
+/// Pointer is also generic over the `Tag` associated with each pointer,
+/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub struct Pointer<Id=AllocId> {
+pub struct Pointer<Tag=(),Id=AllocId> {
pub alloc_id: Id,
pub offset: Size,
+ pub tag: Tag,
}
/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
+ #[inline(always)]
fn from(alloc_id: AllocId) -> Self {
Pointer::new(alloc_id, Size::ZERO)
}
}
-impl<'tcx> Pointer {
+impl<'tcx> Pointer<()> {
+ #[inline(always)]
pub fn new(alloc_id: AllocId, offset: Size) -> Self {
- Pointer { alloc_id, offset }
+ Pointer { alloc_id, offset, tag: () }
+ }
+
+ #[inline(always)]
+ pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
+ where Tag: Default
+ {
+ Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
+ }
+}
+
+impl<'tcx, Tag> Pointer<Tag> {
+ #[inline(always)]
+ pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
+ Pointer { alloc_id, offset, tag }
}
pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
- Pointer::new(
+ Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
+ self.tag,
)
}
pub fn overflowing_signed_offset<C: HasDataLayout>(self, i: i128, cx: C) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
- (Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
+ (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}
pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
- Ok(Pointer::new(
+ Ok(Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
+ self.tag,
))
}
pub fn overflowing_offset<C: HasDataLayout>(self, i: Size, cx: C) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
- (Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
+ (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}
pub fn offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
- Ok(Pointer::new(
+ Ok(Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
+ self.tag
))
}
+
+ #[inline]
+ pub fn erase_tag(self) -> Pointer {
+ Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
+ }
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct Allocation {
+pub struct Allocation<Tag=()> {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer
pub bytes: Vec<u8>,
- /// Maps from byte addresses to allocations.
+ /// Maps from byte addresses to extra data for each pointer.
/// Only the first byte of a pointer is inserted into the map; i.e.,
/// every entry in this map applies to `pointer_size` consecutive bytes starting
/// at the given offset.
- pub relocations: Relocations,
+ pub relocations: Relocations<Tag>,
/// Denotes undefined memory. Reading from undefined memory is forbidden in miri
pub undef_mask: UndefMask,
/// The alignment of the allocation to detect unaligned reads.
pub mutability: Mutability,
}
-impl Allocation {
+impl<Tag> Allocation<Tag> {
/// Creates a read-only allocation initialized by the given bytes
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
let mut undef_mask = UndefMask::new(Size::ZERO);
impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct Relocations<Id=AllocId>(SortedMap<Size, Id>);
+pub struct Relocations<Tag=(), Id=AllocId>(SortedMap<Size, (Tag, Id)>);
-impl<Id> Relocations<Id> {
+impl<Tag, Id> Relocations<Tag, Id> {
pub fn new() -> Self {
Relocations(SortedMap::new())
}
// The caller must guarantee that the given relocations are already sorted
// by address and contain no duplicates.
- pub fn from_presorted(r: Vec<(Size, Id)>) -> Self {
+ pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self {
Relocations(SortedMap::from_presorted_elements(r))
}
}
-impl Deref for Relocations {
- type Target = SortedMap<Size, AllocId>;
+impl<Tag> Deref for Relocations<Tag> {
+ type Target = SortedMap<Size, (Tag, AllocId)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
-impl DerefMut for Relocations {
+impl<Tag> DerefMut for Relocations<Tag> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
}
-impl<'tcx> Scalar {
+/// A `Scalar` represents an immediate, primitive value existing outside of a
+/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
+/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
+/// of a simple value or a pointer into another `Allocation`
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub enum Scalar<Tag=(), Id=AllocId> {
+ /// The raw bytes of a simple value.
+ Bits {
+ /// The first `size` bytes are the value.
+ /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
+ size: u8,
+ bits: u128,
+ },
+
+ /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
+ /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
+ /// relocation and its associated offset together as a `Pointer` here.
+ Ptr(Pointer<Tag, Id>),
+}
+
+impl<'tcx> Scalar<()> {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
+ where Tag: Default
+ {
+ match self {
+ Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
+ Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
+ }
+ }
+}
+
+impl<'tcx, Tag> Scalar<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> Scalar {
+ match self {
+ Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
+ Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
+ }
+ }
+
#[inline]
pub fn ptr_null(cx: impl HasDataLayout) -> Self {
Scalar::Bits {
}
#[inline]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
match self {
Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
Scalar::Bits { .. } => err!(ReadBytesAsPointer),
}
}
-impl From<Pointer> for Scalar {
+impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
#[inline(always)]
- fn from(ptr: Pointer) -> Self {
+ fn from(ptr: Pointer<Tag>) -> Self {
Scalar::Ptr(ptr)
}
}
-
-/// A `Scalar` represents an immediate, primitive value existing outside of a
-/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
-/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
-/// of a simple value or a pointer into another `Allocation`
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum Scalar<Id=AllocId> {
- /// The raw bytes of a simple value.
- Bits {
- /// The first `size` bytes are the value.
- /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
- size: u8,
- bits: u128,
- },
-
- /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
- /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
- /// relocation and its associated offset together as a `Pointer` here.
- Ptr(Pointer<Id>),
-}
// This region or type ...
pub subject: ClosureOutlivesSubject<'tcx>,
- // .. must outlive this one.
+ // ... must outlive this one.
pub outlived_free_region: ty::RegionVid,
- // If not, report an error here.
+ // If not, report an error here ...
pub blame_span: Span,
+
+ // ... due to this reason.
+ pub category: ConstraintCategory,
+}
+
+/// Outlives constraints can be categorized to determine whether and why they
+/// are interesting (for error reporting). Order of variants indicates sort
+/// order of the category, thereby influencing diagnostic output.
+///
+/// See also [rustc_mir::borrow_check::nll::constraints]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub enum ConstraintCategory {
+ Return,
+ TypeAnnotation,
+ Cast,
+
+ /// A constraint that came from checking the body of a closure.
+ ///
+ /// We try to get the category that the closure used when reporting this.
+ ClosureBounds,
+ CallArgument,
+ CopyBound,
+ SizedBound,
+ Assignment,
+ OpaqueType,
+
+ /// A "boring" constraint (caused by the given location) is one that
+ /// the user probably doesn't want to see described in diagnostics,
+ /// because it is kind of an artifact of the type system setup.
+ /// Example: `x = Foo { field: y }` technically creates
+ /// intermediate regions representing the "type of `Foo { field: y
+ /// }`", and data flows from `y` into those variables, but they
+ /// are not very interesting. The assignment into `x` on the other
+ /// hand might be.
+ Boring,
+ // Boring and applicable everywhere.
+ BoringNoLocation,
+
+ /// A constraint that doesn't correspond to anything the user sees.
+ Internal,
}
/// The subject of a ClosureOutlivesRequirement -- that is, the thing
self.super_ty(ty);
}
- fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
+ fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
self.super_canonical_ty(ty);
}
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);
- self.visit_canonical_ty(c_ty);
+ self.visit_user_ty(c_ty);
}
fn super_place(&mut self,
source_info: *source_info,
});
if let Some(user_ty) = user_ty {
- self.visit_canonical_ty(user_ty);
+ self.visit_user_ty(user_ty);
}
self.visit_source_info(source_info);
self.visit_source_scope(visibility_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)
_ => true,
}
} else {
- // users enabling the `const_fn` can do what they want
+ // users enabling the `const_fn` feature gate can do what they want
!self.sess.features_untracked().const_fn
}
}
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(),
}
}
}
}
-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);
tcx.lift(&a)?,
tcx.lift(&b)?,
),
+ FunctionRetMismatch(a, b) => FunctionRetMismatch(
+ tcx.lift(&a)?,
+ tcx.lift(&b)?,
+ ),
FunctionArgCountMismatch => FunctionArgCountMismatch,
NoMirFor(ref s) => NoMirFor(s.clone()),
UnterminatedCString(ptr) => UnterminatedCString(ptr),
use rustc::cfg::CFGIndex;
use dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit};
use std::rc::Rc;
-use dot::IntoCow;
#[derive(Debug, Copy, Clone)]
pub enum Variant {
let suffix = self.dataflow_for(EntryOrExit::Exit, n);
let inner_label = self.inner.node_label(n);
inner_label
- .prefix_line(dot::LabelText::LabelStr(prefix.into_cow()))
- .suffix_line(dot::LabelText::LabelStr(suffix.into_cow()))
+ .prefix_line(dot::LabelText::LabelStr(prefix.into()))
+ .suffix_line(dot::LabelText::LabelStr(suffix.into()))
}
fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) }
}
// 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);
let pointer_size = layout.pointer_size.bytes() as usize;
let mut next_offset = 0;
- for &(offset, alloc_id) in alloc.relocations.iter() {
+ for &(offset, ((), alloc_id)) in alloc.relocations.iter() {
let offset = offset.bytes();
assert_eq!(offset as usize as u64, offset);
let offset = offset as usize;
).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
llvals.push(scalar_to_llvm(
cx,
- Pointer { alloc_id, offset: Size::from_bytes(ptr_offset) }.into(),
+ Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
&layout::Scalar {
value: layout::Primitive::Pointer,
valid_range: 0..=!0
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)]
use rustc::hir;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::ich::{ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED};
-use graphviz::IntoCow;
use std::env;
use std::fs::{self, File};
use std::io::Write;
type Edge = (&'q DepNode, &'q DepNode);
fn nodes(&self) -> dot::Nodes<&'q DepNode> {
let nodes: Vec<_> = self.0.iter().cloned().collect();
- nodes.into_cow()
+ nodes.into()
}
fn edges(&self) -> dot::Edges<(&'q DepNode, &'q DepNode)> {
- self.1[..].into_cow()
+ self.1[..].into()
}
fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
edge.0
let ecx = ::rustc_mir::const_eval::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
let result = (|| {
let op = ecx.const_to_op(constant)?;
- let mut todo = vec![(op, Vec::new())];
- let mut seen = FxHashSet();
- seen.insert(op);
- while let Some((op, mut path)) = todo.pop() {
+ let mut ref_tracking = ::rustc_mir::interpret::RefTracking::new(op);
+ while let Some((op, mut path)) = ref_tracking.todo.pop() {
ecx.validate_operand(
op,
&mut path,
- &mut seen,
- &mut todo,
+ Some(&mut ref_tracking),
+ /* const_mode */ true,
)?;
}
Ok(())
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
}
}
debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
match the_place_err {
+ // Suggest making an existing shared borrow in a struct definition a mutable borrow.
+ //
+ // This is applicable when we have a deref of a field access to a deref of a local -
+ // something like `*((*_1).0`. The local that we get will be a reference to the
+ // struct we've got a field access of (it must be a reference since there's a deref
+ // after the field access).
+ Place::Projection(box Projection {
+ base: Place::Projection(box Projection {
+ base: Place::Projection(box Projection {
+ base,
+ elem: ProjectionElem::Deref,
+ }),
+ elem: ProjectionElem::Field(field, _),
+ }),
+ elem: ProjectionElem::Deref,
+ }) => {
+ err.span_label(span, format!("cannot {ACT}", ACT = act));
+
+ if let Some((span, message)) = annotate_struct_field(
+ self.infcx.tcx,
+ base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx),
+ field,
+ ) {
+ err.span_suggestion_with_applicability(
+ span,
+ "consider changing this to be mutable",
+ message,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ },
+
// Suggest removing a `&mut` from the use of a mutable reference.
Place::Local(local)
if {
fn is_closure_or_generator(ty: ty::Ty) -> bool {
ty.is_closure() || ty.is_generator()
}
+
+/// Add a suggestion to a struct definition given a field access to a local.
+/// This function expects the local to be a reference to a struct in order to produce a suggestion.
+///
+/// ```text
+/// LL | s: &'a String
+/// | ---------- use `&'a mut String` here to make mutable
+/// ```
+fn annotate_struct_field(
+ tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+ ty: ty::Ty<'tcx>,
+ field: &mir::Field,
+) -> Option<(Span, String)> {
+ // Expect our local to be a reference to a struct of some kind.
+ if let ty::TyKind::Ref(_, ty, _) = ty.sty {
+ if let ty::TyKind::Adt(def, _) = ty.sty {
+ let field = def.all_fields().nth(field.index())?;
+ // Use the HIR types to construct the diagnostic message.
+ let node_id = tcx.hir.as_local_node_id(field.did)?;
+ let node = tcx.hir.find(node_id)?;
+ // Now we're dealing with the actual struct that we're going to suggest a change to,
+ // we can expect a field that is an immutable reference to a type.
+ if let hir::Node::Field(field) = node {
+ if let hir::TyKind::Rptr(lifetime, hir::MutTy {
+ mutbl: hir::Mutability::MutImmutable,
+ ref ty
+ }) = field.ty.node {
+ // Get the snippets in two parts - the named lifetime (if there is one) and
+ // type being referenced, that way we can reconstruct the snippet without loss
+ // of detail.
+ let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
+ let lifetime_snippet = if !lifetime.is_elided() {
+ format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
+ } else {
+ String::new()
+ };
+
+ return Some((
+ field.ty.span,
+ format!(
+ "&{}mut {}",
+ lifetime_snippet, &*type_snippet,
+ ),
+ ));
+ }
+ }
+ }
+ }
+
+ None
+}
// except according to those terms.
use borrow_check::nll::type_check::Locations;
-use borrow_check::nll::constraints::{ConstraintCategory, ConstraintIndex};
+use borrow_check::nll::constraints::ConstraintIndex;
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
+use rustc::mir::ConstraintCategory;
use rustc::ty::RegionVid;
use rustc_data_structures::graph;
use rustc_data_structures::indexed_vec::IndexVec;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::mir::ConstraintCategory;
use rustc::ty::RegionVid;
use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
}
-/// Constraints can be categorized to determine whether and why they are
-/// interesting. Order of variants indicates sort order of the category,
-/// thereby influencing diagnostic output.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-pub enum ConstraintCategory {
- Return,
- TypeAnnotation,
- Cast,
- CallArgument,
-
- /// A constraint that came from checking the body of a closure.
- ///
- /// Ideally we would give an explanation that points to the relevant part
- /// of the closure's body.
- ClosureBounds,
- CopyBound,
- SizedBound,
- Assignment,
- OpaqueType,
-
- /// A "boring" constraint (caused by the given location) is one that
- /// the user probably doesn't want to see described in diagnostics,
- /// because it is kind of an artifact of the type system setup.
- /// Example: `x = Foo { field: y }` technically creates
- /// intermediate regions representing the "type of `Foo { field: y
- /// }`", and data flows from `y` into those variables, but they
- /// are not very interesting. The assignment into `x` on the other
- /// hand might be.
- Boring,
- // Boring and applicable everywhere.
- BoringNoLocation,
-
- /// A constraint that doesn't correspond to anything the user sees.
- Internal,
-}
-
impl ConstraintSet {
crate fn push(&mut self, constraint: OutlivesConstraint) {
debug!(
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
}
}
let MirTypeckRegionConstraints {
mut liveness_constraints,
outlives_constraints,
+ closure_bounds_mapping,
type_tests,
} = constraints;
universal_region_relations,
mir,
outlives_constraints,
+ closure_bounds_mapping,
type_tests,
liveness_constraints,
elements,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use borrow_check::nll::constraints::{OutlivesConstraint, ConstraintCategory};
+use borrow_check::nll::constraints::{OutlivesConstraint};
use borrow_check::nll::region_infer::RegionInferenceContext;
+use borrow_check::nll::region_infer::error_reporting::region_name::RegionNameSource;
+use borrow_check::nll::type_check::Locations;
+use borrow_check::nll::universal_regions::DefiningTy;
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
-use rustc::mir::{Location, Mir};
+use rustc::mir::{ConstraintCategory, Location, Mir};
use rustc::ty::{self, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::{Diagnostic, DiagnosticBuilder};
use std::collections::VecDeque;
-use std::fmt;
use syntax::symbol::keywords;
use syntax_pos::Span;
use syntax::errors::Applicability;
use self::region_name::RegionName;
-impl fmt::Display for ConstraintCategory {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+trait ConstraintDescription {
+ fn description(&self) -> &'static str;
+}
+
+impl ConstraintDescription for ConstraintCategory {
+ fn description(&self) -> &'static str {
// Must end with a space. Allows for empty names to be provided.
match self {
- ConstraintCategory::Assignment => write!(f, "assignment "),
- ConstraintCategory::Return => write!(f, "returning this value "),
- ConstraintCategory::Cast => write!(f, "cast "),
- ConstraintCategory::CallArgument => write!(f, "argument "),
- ConstraintCategory::TypeAnnotation => write!(f, "type annotation "),
- ConstraintCategory::ClosureBounds => write!(f, "closure body "),
- ConstraintCategory::SizedBound => write!(f, "proving this value is `Sized` "),
- ConstraintCategory::CopyBound => write!(f, "copying this value "),
- ConstraintCategory::OpaqueType => write!(f, "opaque type "),
+ ConstraintCategory::Assignment => "assignment ",
+ ConstraintCategory::Return => "returning this value ",
+ ConstraintCategory::Cast => "cast ",
+ ConstraintCategory::CallArgument => "argument ",
+ ConstraintCategory::TypeAnnotation => "type annotation ",
+ ConstraintCategory::ClosureBounds => "closure body ",
+ ConstraintCategory::SizedBound => "proving this value is `Sized` ",
+ ConstraintCategory::CopyBound => "copying this value ",
+ ConstraintCategory::OpaqueType => "opaque type ",
ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
- | ConstraintCategory::Internal => write!(f, ""),
+ | ConstraintCategory::Internal => "",
}
}
}
// Classify each of the constraints along the path.
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
.iter()
- .map(|constraint| (constraint.category, constraint.locations.span(mir)))
+ .map(|constraint| {
+ if constraint.category == ConstraintCategory::ClosureBounds {
+ self.retrieve_closure_constraint_info(mir, &constraint)
+ } else {
+ (constraint.category, constraint.locations.span(mir))
+ }
+ })
.collect();
debug!(
"best_blame_constraint: categorized_path={:#?}",
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
fr_is_local, outlived_fr_is_local, category);
match (category, fr_is_local, outlived_fr_is_local) {
+ (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) =>
+ self.report_fnmut_error(mir, infcx, mir_def_id, fr, outlived_fr, span,
+ errors_buffer),
(ConstraintCategory::Assignment, true, false) |
(ConstraintCategory::CallArgument, true, false) =>
self.report_escaping_data_error(mir, infcx, mir_def_id, fr, outlived_fr,
};
}
+ /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
+ /// This function expects `fr` to be local and `outlived_fr` to not be local.
+ ///
+ /// ```text
+ /// error: captured variable cannot escape `FnMut` closure body
+ /// --> $DIR/issue-53040.rs:15:8
+ /// |
+ /// LL | || &mut v;
+ /// | -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
+ /// | |
+ /// | inferred to be a `FnMut` closure
+ /// |
+ /// = note: `FnMut` closures only have access to their captured variables while they are
+ /// executing...
+ /// = note: ...therefore, returned references to captured variables will escape the closure
+ /// ```
+ fn report_fnmut_error(
+ &self,
+ mir: &Mir<'tcx>,
+ infcx: &InferCtxt<'_, '_, 'tcx>,
+ mir_def_id: DefId,
+ _fr: RegionVid,
+ outlived_fr: RegionVid,
+ span: Span,
+ errors_buffer: &mut Vec<Diagnostic>,
+ ) {
+ let mut diag = infcx.tcx.sess.struct_span_err(
+ span,
+ "captured variable cannot escape `FnMut` closure body",
+ );
+
+ // We should check if the return type of this closure is in fact a closure - in that
+ // case, we can special case the error further.
+ let return_type_is_closure = self.universal_regions.unnormalized_output_ty.is_closure();
+ let message = if return_type_is_closure {
+ "returns a closure that contains a reference to a captured variable, which then \
+ escapes the closure body"
+ } else {
+ "returns a reference to a captured variable which escapes the closure body"
+ };
+
+ diag.span_label(
+ span,
+ message,
+ );
+
+ match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).source {
+ RegionNameSource::NamedEarlyBoundRegion(fr_span) |
+ RegionNameSource::NamedFreeRegion(fr_span) |
+ RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) |
+ RegionNameSource::CannotMatchHirTy(fr_span, _) |
+ RegionNameSource::MatchedHirTy(fr_span) |
+ RegionNameSource::MatchedAdtAndSegment(fr_span) |
+ RegionNameSource::AnonRegionFromUpvar(fr_span, _) |
+ RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
+ diag.span_label(fr_span, "inferred to be a `FnMut` closure");
+ },
+ _ => {},
+ }
+
+ diag.note("`FnMut` closures only have access to their captured variables while they are \
+ executing...");
+ diag.note("...therefore, they cannot allow references to captured variables to escape");
+
+ diag.buffer(errors_buffer);
+ }
+
+ /// Reports a error specifically for when data is escaping a closure.
+ ///
+ /// ```text
+ /// error: borrowed data escapes outside of function
+ /// --> $DIR/lifetime-bound-will-change-warning.rs:44:5
+ /// |
+ /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
+ /// | - `x` is a reference that is only valid in the function body
+ /// LL | // but ref_obj will not, so warn.
+ /// LL | ref_obj(x)
+ /// | ^^^^^^^^^^ `x` escapes the function body here
+ /// ```
fn report_escaping_data_error(
&self,
mir: &Mir<'tcx>,
span, &format!("borrowed data escapes outside of {}", escapes_from),
);
- if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
- if let Some(name) = outlived_fr_name {
- diag.span_label(
- outlived_fr_span,
- format!("`{}` is declared here, outside of the {} body", name, escapes_from),
- );
- }
+ if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
+ diag.span_label(
+ outlived_fr_span,
+ format!(
+ "`{}` is declared here, outside of the {} body",
+ outlived_fr_name, escapes_from
+ ),
+ );
}
- if let Some((fr_name, fr_span)) = fr_name_and_span {
- if let Some(name) = fr_name {
- diag.span_label(
- fr_span,
- format!("`{}` is a reference that is only valid in the {} body",
- name, escapes_from),
- );
+ if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
+ diag.span_label(
+ fr_span,
+ format!(
+ "`{}` is a reference that is only valid in the {} body",
+ fr_name, escapes_from
+ ),
+ );
- diag.span_label(span, format!("`{}` escapes the {} body here",
- name, escapes_from));
- }
+ diag.span_label(span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
}
diag.buffer(errors_buffer);
}
+ /// Reports a region inference error for the general case with named/synthesized lifetimes to
+ /// explain what is happening.
+ ///
+ /// ```text
+ /// error: unsatisfied lifetime constraints
+ /// --> $DIR/regions-creating-enums3.rs:17:5
+ /// |
+ /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
+ /// | -- -- lifetime `'b` defined here
+ /// | |
+ /// | lifetime `'a` defined here
+ /// LL | ast::add(x, y)
+ /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
+ /// | is returning data with lifetime `'b`
+ /// ```
fn report_general_error(
&self,
mir: &Mir<'tcx>,
_ => {
diag.span_label(span, format!(
"{}requires that `{}` must outlive `{}`",
- category, fr_name, outlived_fr_name,
+ category.description(), fr_name, outlived_fr_name,
));
},
}
diag.buffer(errors_buffer);
}
+ /// Adds a suggestion to errors where a `impl Trait` is returned.
+ ///
+ /// ```text
+ /// help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as
+ /// a constraint
+ /// |
+ /// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ /// ```
fn add_static_impl_trait_suggestion(
&self,
infcx: &InferCtxt<'_, '_, 'tcx>,
mir: &Mir<'tcx>,
fr1: RegionVid,
fr2: RegionVid,
- ) -> Span {
- let (_, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
- span
+ ) -> (ConstraintCategory, Span) {
+ let (category, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
+ (category, span)
+ }
+
+ fn retrieve_closure_constraint_info(
+ &self,
+ mir: &Mir<'tcx>,
+ constraint: &OutlivesConstraint
+ ) -> (ConstraintCategory, Span) {
+ let loc = match constraint.locations {
+ Locations::All(span) => return (constraint.category, span),
+ Locations::Single(loc) => loc,
+ };
+
+ let opt_span_category = self
+ .closure_bounds_mapping[&loc]
+ .get(&(constraint.sup, constraint.sub));
+ *opt_span_category.unwrap_or(&(constraint.category, mir.source_info(loc).span))
+ }
+
+ /// Returns `true` if a closure is inferred to be an `FnMut` closure.
+ crate fn is_closure_fn_mut(
+ &self,
+ infcx: &InferCtxt<'_, '_, 'tcx>,
+ fr: RegionVid,
+ ) -> bool {
+ if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
+ if let ty::BoundRegion::BrEnv = free_region.bound_region {
+ if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty {
+ let closure_kind_ty = substs.closure_kind_ty(def_id, infcx.tcx);
+ return Some(ty::ClosureKind::FnMut) == closure_kind_ty.to_opt_closure_kind();
+ }
+ }
+ }
+
+ false
}
}
#[derive(Debug)]
crate struct RegionName {
- name: InternedString,
- source: RegionNameSource,
+ crate name: InternedString,
+ crate source: RegionNameSource,
}
#[derive(Debug)]
.defining_ty
.upvar_tys(tcx)
.position(|upvar_ty| {
- debug!(
- "get_upvar_index_for_region: upvar_ty = {:?}",
- upvar_ty,
- );
- tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
+ debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
+ tcx.any_free_region_meets(&upvar_ty, |r| {
+ let r = r.to_region_vid();
+ debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
+ r == fr
+ })
})?;
let upvar_ty = self
use super::*;
use borrow_check::nll::constraints::OutlivesConstraint;
-use dot::{self, IntoCow};
+use dot;
use std::borrow::Cow;
use std::io::{self, Write};
type Edge = OutlivesConstraint;
fn graph_id(&'this self) -> dot::Id<'this> {
- dot::Id::new("RegionInferenceContext".to_string()).unwrap()
+ dot::Id::new("RegionInferenceContext").unwrap()
}
fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> {
dot::Id::new(format!("r{}", n.index())).unwrap()
Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
}
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
- dot::LabelText::LabelStr(format!("{:?}", n).into_cow())
+ dot::LabelText::LabelStr(format!("{:?}", n).into())
}
fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
- dot::LabelText::LabelStr(format!("{:?}", e.locations).into_cow())
+ dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
}
}
fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
- vids.into_cow()
+ vids.into()
}
fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
- (&self.regioncx.constraints.raw[..]).into_cow()
+ (&self.regioncx.constraints.raw[..]).into()
}
// Render `a: b` as `a -> b`, indicating the flow
}
fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> {
let nodes = &self.nodes_per_scc[*n];
- dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into_cow())
+ dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into())
}
}
fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> {
let vids: Vec<ConstraintSccIndex> = self.regioncx.constraint_sccs.all_sccs().collect();
- vids.into_cow()
+ vids.into()
}
fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> {
let edges: Vec<_> = self.regioncx
})
.collect();
- edges.into_cow()
+ edges.into()
}
// Render `a: b` as `a -> b`, indicating the flow
use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
use rustc::mir::{
- ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
- Mir,
+ ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
+ ConstraintCategory, Local, Location, Mir,
};
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc::util::common;
use rustc_data_structures::bit_set::BitSet;
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use syntax_pos::Span;
use std::rc::Rc;
/// the SCC (see `constraint_sccs`) and for error reporting.
constraint_graph: Rc<NormalConstraintGraph>,
- /// The SCC computed from `constraints` and the constraint graph. Used to compute the values
- /// of each region.
+ /// The SCC computed from `constraints` and the constraint graph. Used to
+ /// compute the values of each region.
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
+ /// Map closure bounds to a `Span` that should be used for error reporting.
+ closure_bounds_mapping: FxHashMap<
+ Location,
+ FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
+ >,
+
/// Contains the minimum universe of any variable within the same
/// SCC. We will ensure that no SCC contains values that are not
/// visible from this index.
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
_mir: &Mir<'tcx>,
outlives_constraints: ConstraintSet,
+ closure_bounds_mapping: FxHashMap<
+ Location,
+ FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
+ >,
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>,
constraints,
constraint_graph,
constraint_sccs,
+ closure_bounds_mapping,
scc_universes,
scc_representatives,
scc_values,
subject,
outlived_free_region: non_local_ub,
blame_span: locations.span(mir),
+ category: ConstraintCategory::Boring,
};
debug!("try_promote_type_test: pushing {:#?}", requirement);
propagated_outlives_requirements.push(requirement);
longer_fr, shorter_fr,
);
- let blame_span = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
+ let blame_span_category = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
// Shrink `fr` until we find a non-local region (if we do).
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
outlived_free_region: shorter_fr_plus,
- blame_span: blame_span,
+ blame_span: blame_span_category.1,
+ category: blame_span_category.0,
});
return;
}
};
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
- let span = self.find_outlives_blame_span(mir, longer_fr, error_region);
+ let (_, span) = self.find_outlives_blame_span(mir, longer_fr, error_region);
// Obviously, this error message is far from satisfactory.
// At present, though, it only appears in unit tests --
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
+use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
debug!("visit_ty: ty={:?}", ty);
}
+ fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
+ // `user_ty` annotations represent the types that the user
+ // wrote in the progarm. We don't want to erase the regions
+ // from these types: rather, we want to add them as
+ // constraints at type-check time.
+ debug!("visit_user_ty: skipping renumber");
+ }
+
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
debug!("visit_substs(substs={:?}, location={:?})", substs, location);
debug!("visit_closure_substs: substs={:?}", substs);
}
- fn visit_ascribe_user_ty(
- &mut self,
- _place: &mut Place<'tcx>,
- _variance: &mut ty::Variance,
- _c_ty: &mut CanonicalTy<'tcx>,
- _location: Location,
- ) {
- // User-assert-ty statements represent types that the user added explicitly.
- // We don't want to erase the regions from these types: rather, we want to
- // add them as constraints at type-check time.
- debug!("visit_user_assert_ty: skipping renumber");
- }
-
fn visit_statement(
&mut self,
block: BasicBlock,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
+use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::region_infer::TypeTest;
use borrow_check::nll::type_check::Locations;
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
use rustc::infer::{self, SubregionOrigin};
+use rustc::mir::ConstraintCategory;
use rustc::ty::subst::UnpackedKind;
use rustc::ty::{self, TyCtxt};
use syntax_pos::DUMMY_SP;
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::ToRegionVid;
-use borrow_check::nll::constraints::ConstraintCategory;
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
use rustc::infer::region_constraints::GenericKind;
use rustc::infer::InferCtxt;
+use rustc::mir::ConstraintCategory;
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
use rustc::traits::query::type_op::{self, TypeOp};
use rustc::ty::{self, RegionVid, Ty};
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
-use super::{ConstraintCategory, Locations, TypeChecker};
+use super::{Locations, TypeChecker};
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
pub(super) fn equate_inputs_and_outputs(
// except according to those terms.
use borrow_check::location::LocationTable;
-use borrow_check::nll::constraints::ConstraintCategory;
use borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
use borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap};
use borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap;
use dataflow::move_paths::MoveData;
use dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
use rustc::infer::canonical::QueryRegionConstraint;
-use rustc::mir::{BasicBlock, Local, Location, Mir};
+use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, Mir};
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc::traits::query::type_op::outlives::DropckOutlives;
use rustc::traits::query::type_op::TypeOp;
use borrow_check::borrow_set::BorrowSet;
use borrow_check::location::LocationTable;
-use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
+use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
use borrow_check::nll::region_infer::values::LivenessValues;
use borrow_check::nll::region_infer::values::PlaceholderIndices;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::Subst;
+use rustc::ty::subst::{Subst, UnpackedKind};
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc;
use std::{fmt, iter};
use transform::{MirPass, MirSource};
use either::Either;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
macro_rules! span_mirbug {
($context:expr, $elem:expr, $($message:tt)*) => ({
let mut constraints = MirTypeckRegionConstraints {
liveness_constraints: LivenessValues::new(elements),
outlives_constraints: ConstraintSet::default(),
+ closure_bounds_mapping: FxHashMap(),
type_tests: Vec::default(),
};
let mut placeholder_indices = PlaceholderIndices::default();
crate outlives_constraints: ConstraintSet,
+ crate closure_bounds_mapping: FxHashMap<
+ Location,
+ FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
+ >,
+
crate type_tests: Vec<TypeTest<'tcx>>,
}
&mut self,
locations: Locations,
category: ConstraintCategory,
- op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
+ op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>,
) -> Fallible<R> {
let (r, opt_data) = op.fully_perform(self.infcx)?;
let place_ty = place.ty(mir, tcx).to_ty(tcx);
let rv_ty = rv.ty(mir, tcx);
if let Err(terr) =
- self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
- {
- span_mirbug!(
+ self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
+ {
+ span_mirbug!(
self,
stmt,
"bad assignment ({:?} = {:?}): {:?}",
rv_ty,
terr
);
- }
+ }
if let Some(user_ty) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.relate_type_and_user_type(
let locations = term_location.to_locations();
if let Err(terr) =
- self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
- {
- span_mirbug!(
+ self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
+ {
+ span_mirbug!(
self,
term,
"bad DropAndReplace ({:?} = {:?}): {:?}",
rv_ty,
terr
);
- }
+ }
}
TerminatorKind::SwitchInt {
ref discr,
let locations = term_location.to_locations();
if let Err(terr) =
- self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
- {
- span_mirbug!(
+ self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
+ {
+ span_mirbug!(
self,
term,
"call dest mismatch ({:?} <- {:?}): {:?}",
sig.output(),
terr
);
- }
+ }
// When `#![feature(unsized_locals)]` is not enabled,
// this check is done at `check_local`.
aggregate_kind, location
);
- let instantiated_predicates = match aggregate_kind {
+ let instantiated_predicates = match aggregate_kind {
AggregateKind::Adt(def, _, substs, _, _) => {
tcx.predicates_of(def.did).instantiate(tcx, substs)
}
// these extra requirements are basically like where
// clauses on the struct.
AggregateKind::Closure(def_id, substs) => {
- if let Some(closure_region_requirements) =
- tcx.mir_borrowck(*def_id).closure_requirements
- {
- let closure_constraints = closure_region_requirements.apply_requirements(
- self.infcx.tcx,
- location,
- *def_id,
- *substs,
- );
-
- self.push_region_constraints(
- location.to_locations(),
- ConstraintCategory::ClosureBounds,
- &closure_constraints,
- );
- }
-
- tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
+ self.prove_closure_bounds(tcx, *def_id, *substs, location)
}
AggregateKind::Generator(def_id, substs, _) => {
);
}
+ fn prove_closure_bounds(
+ &mut self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ def_id: DefId,
+ substs: ty::ClosureSubsts<'tcx>,
+ location: Location,
+ ) -> ty::InstantiatedPredicates<'tcx> {
+ if let Some(closure_region_requirements) =
+ tcx.mir_borrowck(def_id).closure_requirements
+ {
+ let closure_constraints = closure_region_requirements.apply_requirements(
+ tcx,
+ location,
+ def_id,
+ substs,
+ );
+
+ if let Some(ref mut borrowck_context) = self.borrowck_context {
+ let bounds_mapping = closure_constraints
+ .iter()
+ .enumerate()
+ .filter_map(|(idx, constraint)| {
+ let ty::OutlivesPredicate(k1, r2) =
+ constraint.no_late_bound_regions().unwrap_or_else(|| {
+ bug!(
+ "query_constraint {:?} contained bound regions",
+ constraint,
+ );
+ });
+
+ match k1.unpack() {
+ UnpackedKind::Lifetime(r1) => {
+ // constraint is r1: r2
+ let r1_vid = borrowck_context.universal_regions.to_region_vid(r1);
+ let r2_vid = borrowck_context.universal_regions.to_region_vid(r2);
+ let outlives_requirements = &closure_region_requirements
+ .outlives_requirements[idx];
+ Some((
+ (r1_vid, r2_vid),
+ (
+ outlives_requirements.category,
+ outlives_requirements.blame_span,
+ ),
+ ))
+ }
+ UnpackedKind::Type(_) => None,
+ }
+ })
+ .collect();
+
+ let existing = borrowck_context.constraints
+ .closure_bounds_mapping
+ .insert(location, bounds_mapping);
+ assert!(existing.is_none(), "Multiple closures at the same location.");
+ }
+
+ self.push_region_constraints(
+ location.to_locations(),
+ ConstraintCategory::ClosureBounds,
+ &closure_constraints,
+ );
+ }
+
+ tcx.predicates_of(def_id).instantiate(tcx, substs.substs)
+ }
+
fn prove_trait_ref(
&mut self,
trait_ref: ty::TraitRef<'tcx>,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use borrow_check::nll::constraints::{ConstraintCategory, OutlivesConstraint};
+use borrow_check::nll::constraints::OutlivesConstraint;
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
+use rustc::mir::ConstraintCategory;
use rustc::traits::query::Fallible;
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
) {
for ascription in ascriptions {
let source_info = self.source_info(ascription.span);
+
+ debug!(
+ "adding user ascription at span {:?} of place {:?} and {:?}",
+ source_info.span,
+ ascription.source,
+ ascription.user_ty,
+ );
+
self.cfg.push(
block,
Statement {
use std::fmt;
use std::error::Error;
+use std::borrow::{Borrow, Cow};
+use std::hash::Hash;
+use std::collections::hash_map::Entry;
use rustc::hir::{self, def_id::DefId};
use rustc::mir::interpret::ConstEvalErr;
use rustc::ty::layout::{self, LayoutOf, TyLayout};
use rustc::ty::subst::Subst;
use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::fx::FxHashMap;
use syntax::ast::Mutability;
use syntax::source_map::{Span, DUMMY_SP};
use rustc::mir::interpret::{
EvalResult, EvalError, EvalErrorKind, GlobalId,
- Scalar, Allocation, ConstValue,
+ Scalar, Allocation, AllocId, ConstValue,
};
use interpret::{self,
Place, PlaceTy, MemPlace, OpTy, Operand, Value,
}
};
let val = match normalized_op {
- Err(MemPlace { ptr, align, extra }) => {
+ Err(MemPlace { ptr, align, meta }) => {
// extract alloc-offset pair
- assert!(extra.is_none());
+ assert!(meta.is_none());
let ptr = ptr.to_ptr()?;
let alloc = ecx.memory.get(ptr.alloc_id)?;
assert!(alloc.align.abi() >= align.abi());
}
}
+impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
+ #[inline(always)]
+ fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+ where K: Borrow<Q>
+ {
+ FxHashMap::contains_key(self, k)
+ }
+
+ #[inline(always)]
+ fn insert(&mut self, k: K, v: V) -> Option<V>
+ {
+ FxHashMap::insert(self, k, v)
+ }
+
+ #[inline(always)]
+ fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+ where K: Borrow<Q>
+ {
+ FxHashMap::remove(self, k)
+ }
+
+ #[inline(always)]
+ fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
+ self.iter()
+ .filter_map(move |(k, v)| f(k, &*v))
+ .collect()
+ }
+
+ #[inline(always)]
+ fn get_or<E>(
+ &self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&V, E>
+ {
+ match self.get(&k) {
+ Some(v) => Ok(v),
+ None => {
+ vacant()?;
+ bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
+ }
+ }
+ }
+
+ #[inline(always)]
+ fn get_mut_or<E>(
+ &mut self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&mut V, E>
+ {
+ match self.entry(k) {
+ Entry::Occupied(e) => Ok(e.into_mut()),
+ Entry::Vacant(e) => {
+ let v = vacant()?;
+ Ok(e.insert(v))
+ }
+ }
+ }
+}
+
type CompileTimeEvalContext<'a, 'mir, 'tcx> =
EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
{
type MemoryData = ();
type MemoryKinds = !;
+ type PointerTag = ();
+
+ type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
- const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
+ const STATIC_KIND: Option<!> = None; // no copying of statics allowed
+ const ENFORCE_VALIDITY: bool = false; // for now, we don't
fn find_fn(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
fn find_foreign_static(
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
_def_id: DefId,
- ) -> EvalResult<'tcx, &'tcx Allocation> {
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
err!(ReadForeignStatic)
}
+ #[inline(always)]
+ fn static_with_default_tag(
+ alloc: &'_ Allocation
+ ) -> Cow<'_, Allocation<Self::PointerTag>> {
+ // We do not use a tag so we can just cheaply forward the reference
+ Cow::Borrowed(alloc)
+ }
+
fn box_alloc(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>,
use rustc::mir::{BasicBlock, Mir};
use dot;
-use dot::IntoCow;
use std::fs;
use std::io;
.basic_blocks()
.indices()
.collect::<Vec<_>>()
- .into_cow()
+ .into()
}
fn edges(&self) -> dot::Edges<Edge> {
.indices()
.flat_map(|bb| outgoing(mir, bb))
.collect::<Vec<_>>()
- .into_cow()
+ .into()
}
fn source(&self, edge: &Edge) -> Node {
```
"##,
-E0022: r##"
-Constant functions are not allowed to mutate anything. Thus, binding to an
-argument with a mutable pattern is not allowed. For example,
-
-```compile_fail
-const fn foo(mut x: u8) {
- // do stuff
-}
-```
-
-Is incorrect because the function body may not mutate `x`.
-
-Remove any mutable bindings from the argument list to fix this error. In case
-you need to mutate the argument, try lazily initializing a global variable
-instead of using a `const fn`, or refactoring the code to a functional style to
-avoid mutation if possible.
-"##,
-
E0133: r##"
Unsafe code was used outside of an unsafe function or block.
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
+use hair::util::UserAnnotatedTyHelpers;
use rustc::hir::def::{Def, CtorKind};
use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, AdtKind, Ty};
adt_def: adt,
variant_index: 0,
substs,
- user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
+ user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
fields: field_refs(cx, fields),
base: base.as_ref().map(|base| {
FruInfo {
adt_def: adt,
variant_index: index,
substs,
- user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
+ user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
fields: field_refs(cx, fields),
base: None,
}
// user.
Def::StructCtor(_def_id, CtorKind::Const) |
Def::VariantCtor(_def_id, CtorKind::Const) =>
- match &cx.tables().node_id_to_type(hir_id).sty {
- ty::Adt(adt_def, _) => user_annotated_ty_for_adt(cx, hir_id, adt_def),
- sty => bug!("unexpected sty: {:?}", sty),
- },
+ cx.user_substs_applied_to_ty_of_hir_id(hir_id),
// `Self` is used in expression as a tuple struct constructor or an unit struct constructor
- Def::SelfCtor(_) => {
- let sty = &cx.tables().node_id_to_type(hir_id).sty;
- match sty {
- ty::FnDef(ref def_id, _) => {
- Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
- // Here, we just pair a `DefId` with the
- // `user_substs`, so no new types etc are introduced.
- cx.tcx().mk_fn_def(*def_id, user_substs)
- }))
- }
- ty::Adt(ref adt_def, _) => {
- user_annotated_ty_for_adt(cx, hir_id, adt_def)
- }
- _ => {
- bug!("unexpected sty: {:?}", sty)
- }
- }
- }
+ Def::SelfCtor(_) =>
+ cx.user_substs_applied_to_ty_of_hir_id(hir_id),
+
_ =>
bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
}
}
-fn user_annotated_ty_for_adt(
- cx: &mut Cx<'a, 'gcx, 'tcx>,
- hir_id: hir::HirId,
- adt_def: &'tcx AdtDef,
-) -> Option<CanonicalTy<'tcx>> {
- let user_substs = cx.tables().user_substs(hir_id)?;
- Some(user_substs.unchecked_map(|user_substs| {
- // Here, we just pair an `AdtDef` with the
- // `user_substs`, so no new types etc are introduced.
- cx.tcx().mk_adt(adt_def, user_substs)
- }))
-}
-
fn method_callee<'a, 'gcx, 'tcx>(
cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &hir::Expr,
adt_def,
variant_index: adt_def.variant_index_with_id(def_id),
substs,
- user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt_def),
+ user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt_def),
fields: vec![],
base: None,
}
//!
use hair::*;
+use hair::util::UserAnnotatedTyHelpers;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
}
}
+impl UserAnnotatedTyHelpers<'gcx, 'tcx> for Cx<'_, 'gcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
+ self.tcx()
+ }
+
+ fn tables(&self) -> &ty::TypeckTables<'tcx> {
+ self.tables()
+ }
+}
+
fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
// Right now we insert a `with_ignore` node in the dep graph here to
// ignore the fact that `lint_levels` below depends on the entire crate.
pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
+mod util;
+
#[derive(Copy, Clone, Debug)]
pub enum LintLevel {
Inherited,
use const_eval::{const_field, const_variant_index};
+use hair::util::UserAnnotatedTyHelpers;
+
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
field: Field::new(i),
pattern: self.lower_pattern(field),
})
- .collect();
- self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+ .collect();
+
+ self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
}
PatKind::Struct(ref qpath, ref fields, _) => {
})
.collect();
- self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+ self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
}
};
fn lower_variant_or_leaf(
&mut self,
def: Def,
+ hir_id: hir::HirId,
span: Span,
ty: Ty<'tcx>,
- subpatterns: Vec<FieldPattern<'tcx>>)
- -> PatternKind<'tcx>
- {
- match def {
+ subpatterns: Vec<FieldPattern<'tcx>>,
+ ) -> PatternKind<'tcx> {
+ let mut kind = match def {
Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
let adt_def = self.tcx.adt_def(enum_id);
self.errors.push(PatternError::NonConstPath(span));
PatternKind::Wild
}
+ };
+
+ if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
+ let subpattern = Pattern {
+ span,
+ ty,
+ kind: Box::new(kind),
+ };
+
+ debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
+
+ kind = PatternKind::AscribeUserType {
+ subpattern,
+ user_ty,
+ };
}
+
+ kind
}
/// Takes a HIR Path. If the path is a constant, evaluates it and feeds
},
}
}
- _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
+ _ => self.lower_variant_or_leaf(def, id, span, ty, vec![]),
};
Pattern {
}
}
+impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> {
+ self.tcx
+ }
+
+ fn tables(&self) -> &ty::TypeckTables<'tcx> {
+ self.tables
+ }
+}
+
+
pub trait PatternFoldable<'tcx> : Sized {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.super_fold_with(folder)
--- /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.
+
+use rustc::hir;
+use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};
+
+crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
+
+ fn tables(&self) -> &ty::TypeckTables<'tcx>;
+
+ fn user_substs_applied_to_adt(
+ &self,
+ hir_id: hir::HirId,
+ adt_def: &'tcx AdtDef,
+ ) -> Option<CanonicalTy<'tcx>> {
+ let user_substs = self.tables().user_substs(hir_id)?;
+ Some(user_substs.unchecked_map(|user_substs| {
+ // Here, we just pair an `AdtDef` with the
+ // `user_substs`, so no new types etc are introduced.
+ self.tcx().mk_adt(adt_def, user_substs)
+ }))
+ }
+
+ /// Looks up the type associated with this hir-id and applies the
+ /// user-given substitutions; the hir-id must map to a suitable
+ /// type.
+ fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option<CanonicalTy<'tcx>> {
+ let user_substs = self.tables().user_substs(hir_id)?;
+ match &self.tables().node_id_to_type(hir_id).sty {
+ ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| {
+ // Ok to call `unchecked_map` because we just pair an
+ // `AdtDef` with the `user_substs`, so no new types
+ // etc are introduced.
+ self.tcx().mk_adt(adt_def, user_substs)
+ })),
+ ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
+ // Here, we just pair a `DefId` with the
+ // `user_substs`, so no new types etc are introduced.
+ self.tcx().mk_fn_def(*def_id, user_substs)
+ })),
+ sty => bug!(
+ "sty: {:?} should not have user-substs {:?} recorded ",
+ sty,
+ user_substs
+ ),
+ }
+ }
+}
pub fn cast(
&mut self,
- src: OpTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
kind: CastKind,
- dest: PlaceTy<'tcx>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let src_layout = src.layout;
let dst_layout = dest.layout;
pub(super) fn cast_scalar(
&self,
- val: Scalar,
+ val: Scalar<M::PointerTag>,
src_layout: TyLayout<'tcx>,
dest_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
v: u128,
src_layout: TyLayout<'tcx>,
dest_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
let signed = src_layout.abi.is_signed();
let v = if signed {
self.sign_extend(v, src_layout)
bits: u128,
fty: FloatTy,
dest_ty: Ty<'tcx>
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
use rustc_apfloat::FloatConvert;
match dest_ty.sty {
}
}
- fn cast_from_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
+ fn cast_from_ptr(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ ty: Ty<'tcx>
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
match ty.sty {
// Casting to a reference or fn pointer is not permitted by rustc,
fn unsize_into_ptr(
&mut self,
- src: OpTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
// The pointee types
sty: Ty<'tcx>,
dty: Ty<'tcx>,
fn unsize_into(
&mut self,
- src: OpTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
match (&src.layout.ty.sty, &dest.layout.ty.sty) {
(&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
pub memory: Memory<'a, 'mir, 'tcx, M>,
/// The virtual call stack.
- pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
+ pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag>>,
}
/// A stack frame.
#[derive(Clone)]
-pub struct Frame<'mir, 'tcx: 'mir> {
+pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
////////////////////////////////////////////////////////////////////////////////
// Function and callsite information
////////////////////////////////////////////////////////////////////////////////
pub return_to_block: StackPopCleanup,
/// The location where the result of the current stack frame should be written to.
- pub return_place: Place,
+ pub return_place: Place<Tag>,
/// The list of locals for this stack frame, stored in order as
/// `[return_ptr, arguments..., variables..., temporaries...]`.
/// The locals are stored as `Option<Value>`s.
/// `None` represents a local that is currently dead, while a live local
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
- pub locals: IndexVec<mir::Local, LocalValue<AllocId>>,
+ pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
// State of a local variable
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum LocalValue<Id=AllocId> {
+pub enum LocalValue<Tag=(), Id=AllocId> {
Dead,
// Mostly for convenience, we re-use the `Operand` type here.
// This is an optimization over just always having a pointer here;
// we can thus avoid doing an allocation when the local just stores
// immediate values *and* never has its address taken.
- Live(Operand<Id>),
+ Live(Operand<Tag, Id>),
}
-impl<'tcx> LocalValue {
- pub fn access(&self) -> EvalResult<'tcx, &Operand> {
+impl<'tcx, Tag> LocalValue<Tag> {
+ pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
match self {
LocalValue::Dead => err!(DeadLocal),
LocalValue::Live(ref val) => Ok(val),
}
}
- pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> {
+ pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
match self {
LocalValue::Dead => err!(DeadLocal),
LocalValue::Live(ref mut val) => Ok(val),
&mut self.memory
}
- pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
+ pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag>] {
&self.stack
}
/// Mark a storage as live, killing the previous content and returning it.
/// Remember to deallocate that!
- pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, LocalValue> {
+ pub fn storage_live(
+ &mut self,
+ local: mir::Local
+ ) -> EvalResult<'tcx, LocalValue<M::PointerTag>> {
+ assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
trace!("{:?} is now live", local);
let layout = self.layout_of_local(self.cur_frame(), local)?;
/// Returns the old value of the local.
/// Remember to deallocate that!
- pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue {
+ pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
+ assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
trace!("{:?} is now dead", local);
mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
}
- pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
+ pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value<M::PointerTag>> {
let ptr = self.memory.allocate_static_bytes(s.as_bytes());
Ok(Value::new_slice(Scalar::Ptr(ptr), s.len() as u64, self.tcx.tcx))
}
}
/// Return the actual dynamic size and alignment of the place at the given type.
- /// Only the "extra" (metadata) part of the place matters.
+ /// Only the `meta` part of the place matters.
pub(super) fn size_and_align_of(
&self,
- metadata: Option<Scalar>,
+ metadata: Option<Scalar<M::PointerTag>>,
layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Size, Align)> {
let metadata = match metadata {
#[inline]
pub fn size_and_align_of_mplace(
&self,
- mplace: MPlaceTy<'tcx>
+ mplace: MPlaceTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, (Size, Align)> {
- self.size_and_align_of(mplace.extra, mplace.layout)
+ self.size_and_align_of(mplace.meta, mplace.layout)
}
pub fn push_stack_frame(
instance: ty::Instance<'tcx>,
span: source_map::Span,
mir: &'mir mir::Mir<'tcx>,
- return_place: Place,
+ return_place: Place<M::PointerTag>,
return_to_block: StackPopCleanup,
) -> EvalResult<'tcx> {
::log_settings::settings().indentation += 1;
let dummy =
LocalValue::Live(Operand::Immediate(Value::Scalar(ScalarMaybeUndef::Undef)));
let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
+ // Return place is handled specially by the `eval_place` functions, and the
+ // entry in `locals` should never be used. Make it dead, to be sure.
+ locals[mir::RETURN_PLACE] = LocalValue::Dead;
// Now mark those locals as dead that we do not want to initialize
match self.tcx.describe_def(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
Ok(())
}
- pub(super) fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
+ pub(super) fn deallocate_local(
+ &mut self,
+ local: LocalValue<M::PointerTag>,
+ ) -> EvalResult<'tcx> {
// FIXME: should we tell the user that there was a local which was never written to?
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
trace!("deallocating local");
}
#[inline(always)]
- pub fn frame(&self) -> &Frame<'mir, 'tcx> {
+ pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag> {
self.stack.last().expect("no call frames exist")
}
#[inline(always)]
- pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
+ pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag> {
self.stack.last_mut().expect("no call frames exist")
}
}
}
- pub fn dump_place(&self, place: Place) {
+ pub fn dump_place(&self, place: Place<M::PointerTag>) {
// Debug output
if !log_enabled!(::log::Level::Trace) {
return;
};
-fn numeric_intrinsic<'tcx>(
+fn numeric_intrinsic<'tcx, Tag>(
name: &str,
bits: u128,
kind: Primitive,
-) -> EvalResult<'tcx, Scalar> {
+) -> EvalResult<'tcx, Scalar<Tag>> {
let size = match kind {
Primitive::Int(integer, _) => integer.size(),
_ => bug!("invalid `{}` argument: {:?}", name, bits),
pub fn emulate_intrinsic(
&mut self,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: PlaceTy<'tcx>,
+ args: &[OpTy<'tcx, M::PointerTag>],
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, bool> {
let substs = instance.substs;
pub fn hook_fn(
&mut self,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: Option<PlaceTy<'tcx>>,
+ args: &[OpTy<'tcx, M::PointerTag>],
+ dest: Option<PlaceTy<'tcx, M::PointerTag>>,
) -> EvalResult<'tcx, bool> {
let def_id = instance.def_id();
// Some fn calls are actually BinOp intrinsics
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.
+use std::borrow::{Borrow, Cow};
+use std::hash::Hash;
+
use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
+use rustc::mir::interpret::{Allocation, AllocId, EvalResult, Scalar};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
-use super::{EvalContext, PlaceTy, OpTy};
+use super::{EvalContext, PlaceTy, OpTy, MemoryKind};
+
+/// The functionality needed by memory to manage its allocations
+pub trait AllocMap<K: Hash + Eq, V> {
+ /// Test if the map contains the given key.
+ /// Deliberately takes `&mut` because that is sufficient, and some implementations
+ /// can be more efficient then (using `RefCell::get_mut`).
+ fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+ where K: Borrow<Q>;
+
+ /// Insert new entry into the map.
+ fn insert(&mut self, k: K, v: V) -> Option<V>;
+
+ /// Remove entry from the map.
+ fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+ where K: Borrow<Q>;
+
+ /// Return data based the keys and values in the map.
+ fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;
+
+ /// Return a reference to entry `k`. If no such entry exists, call
+ /// `vacant` and either forward its error, or add its result to the map
+ /// and return a reference to *that*.
+ fn get_or<E>(
+ &self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&V, E>;
+
+ /// Return a mutable reference to entry `k`. If no such entry exists, call
+ /// `vacant` and either forward its error, or add its result to the map
+ /// and return a reference to *that*.
+ fn get_mut_or<E>(
+ &mut self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&mut V, E>;
+}
/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
-/// FIXME: We should be able to get rid of the 'a here if we can get rid of the 'a in
-/// `snapshot::EvalSnapshot`.
pub trait Machine<'a, 'mir, 'tcx>: Sized {
/// Additional data that can be accessed via the Memory
type MemoryData;
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
type MemoryKinds: ::std::fmt::Debug + Copy + Eq;
- /// The memory kind to use for mutated statics -- or None if those are not supported.
- const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
+ /// Memory's allocation map
+ type MemoryMap:
+ AllocMap<AllocId, (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag>)> +
+ Default +
+ Clone;
+
+ /// Tag tracked alongside every pointer. This is inert for now, in preparation for
+ /// a future implementation of "Stacked Borrows"
+ /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
+ type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
+
+ /// The memory kind to use for copied statics -- or None if those are not supported.
+ /// Statics are copied under two circumstances: When they are mutated, and when
+ /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
+ /// that is added to the memory so that the work is not done twice.
+ const STATIC_KIND: Option<Self::MemoryKinds>;
+
+ /// Whether to enforce the validity invariant
+ const ENFORCE_VALIDITY: bool;
/// Called before a basic block terminator is executed.
/// You can use this to detect endlessly running programs.
fn find_fn(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: Option<PlaceTy<'tcx>>,
+ args: &[OpTy<'tcx, Self::PointerTag>],
+ dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;
fn call_intrinsic(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: PlaceTy<'tcx>,
+ args: &[OpTy<'tcx, Self::PointerTag>],
+ dest: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx>;
/// Called for read access to a foreign static item.
- /// This can be called multiple times for the same static item and should return consistent
- /// results. Once the item is *written* the first time, as usual for statics a copy is
- /// made and this function is not called again.
+ ///
+ /// This will only be called once per static and machine; the result is cached in
+ /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
+ /// owned allocation to the map even when the map is shared.)
fn find_foreign_static(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
def_id: DefId,
- ) -> EvalResult<'tcx, &'tcx Allocation>;
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>>;
+
+ /// Called to turn an allocation obtained from the `tcx` into one that has
+ /// the appropriate tags on each pointer.
+ ///
+ /// This should avoid copying if no work has to be done! If this returns an owned
+ /// allocation (because a copy had to be done to add the tags), machine memory will
+ /// cache the result. (This relies on `AllocMap::get_or` being able to add the
+ /// owned allocation to the map even when the map is shared.)
+ fn static_with_default_tag(
+ alloc: &'_ Allocation
+ ) -> Cow<'_, Allocation<Self::PointerTag>>;
/// Called for all binary operations on integer(-like) types when one operand is a pointer
/// value, and for the `Offset` operation that is inherently about pointers.
fn ptr_op(
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp,
- left: Scalar,
+ left: Scalar<Self::PointerTag>,
left_layout: TyLayout<'tcx>,
- right: Scalar,
+ right: Scalar<Self::PointerTag>,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)>;
+ ) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
/// Heap allocations via the `box` keyword
///
/// Returns a pointer to the allocated memory
fn box_alloc(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
- dest: PlaceTy<'tcx>,
+ dest: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx>;
/// Execute a validation operation
use std::collections::VecDeque;
use std::ptr;
+use std::borrow::Cow;
-use rustc::ty::{self, Instance, query::TyCtxtAt};
+use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, GlobalId,
- EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
- truncate};
+use rustc::mir::interpret::{
+ Pointer, AllocId, Allocation, ConstValue, GlobalId,
+ EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
+ truncate
+};
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use syntax::ast::Mutability;
-use super::{Machine, ScalarMaybeUndef};
+use super::{Machine, AllocMap, ScalarMaybeUndef};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum MemoryKind<T> {
/// Error if deallocated except during a stack pop
Stack,
+ /// Error if ever deallocated
+ Vtable,
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
Machine(T),
}
/// Allocations local to this instance of the miri engine. The kind
/// helps ensure that the same mechanism is used for allocation and
/// deallocation. When an allocation is not found here, it is a
- /// static and looked up in the `tcx` for read access. Writing to
- /// a static creates a copy here, in the machine.
- alloc_map: FxHashMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
+ /// static and looked up in the `tcx` for read access. Some machines may
+ /// have to mutate this map even on a read-only access to a static (because
+ /// they do pointer provenance tracking and the allocations in `tcx` have
+ /// the wrong type), so we let the machine override this type.
+ /// Either way, if the machine allows writing to a static, doing so will
+ /// create a copy of the static allocation here.
+ alloc_map: M::MemoryMap,
/// To be able to compare pointers with NULL, and to check alignment for accesses
/// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
Memory {
data,
- alloc_map: FxHashMap::default(),
+ alloc_map: Default::default(),
dead_alloc_map: FxHashMap::default(),
tcx,
}
}
- pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer {
- self.tcx.alloc_map.lock().create_fn_alloc(instance).into()
+ pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer<M::PointerTag> {
+ Pointer::from(self.tcx.alloc_map.lock().create_fn_alloc(instance)).with_default_tag()
}
- pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer {
- self.tcx.allocate_bytes(bytes).into()
+ pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer<M::PointerTag> {
+ Pointer::from(self.tcx.allocate_bytes(bytes)).with_default_tag()
}
pub fn allocate_with(
&mut self,
- alloc: Allocation,
+ alloc: Allocation<M::PointerTag>,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx, AllocId> {
let id = self.tcx.alloc_map.lock().reserve();
size: Size,
align: Align,
kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx, Pointer> {
- self.allocate_with(Allocation::undef(size, align), kind).map(Pointer::from)
+ ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
+ let ptr = Pointer::from(self.allocate_with(Allocation::undef(size, align), kind)?);
+ Ok(ptr.with_default_tag())
}
pub fn reallocate(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
old_size: Size,
old_align: Align,
new_size: Size,
new_align: Align,
kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx, Pointer> {
+ ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
if ptr.offset.bytes() != 0 {
return err!(ReallocateNonBasePtr);
}
}
/// Deallocate a local, or do nothing if that local has been made into a static
- pub fn deallocate_local(&mut self, ptr: Pointer) -> EvalResult<'tcx> {
+ pub fn deallocate_local(&mut self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx> {
// The allocation might be already removed by static interning.
// This can only really happen in the CTFE instance, not in miri.
if self.alloc_map.contains_key(&ptr.alloc_id) {
pub fn deallocate(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size_and_align: Option<(Size, Align)>,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx> {
/// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
/// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
- pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
+ pub fn check_align(
+ &self,
+ ptr: Scalar<M::PointerTag>,
+ required_align: Align
+ ) -> EvalResult<'tcx> {
// Check non-NULL/Undef, extract offset
let (offset, alloc_align) = match ptr {
Scalar::Ptr(ptr) => {
- let (size, align) = self.get_size_and_align(ptr.alloc_id)?;
+ let (size, align) = self.get_size_and_align(ptr.alloc_id);
// check this is not NULL -- which we can ensure only if this is in-bounds
// of some (potentially dead) allocation.
if ptr.offset > size {
return err!(PointerOutOfBounds {
- ptr,
+ ptr: ptr.erase_tag(),
access: true,
allocation_size: size,
});
/// If you want to check bounds before doing a memory access, be sure to
/// check the pointer one past the end of your access, then everything will
/// work out exactly.
- pub fn check_bounds(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> {
+ pub fn check_bounds_ptr(&self, ptr: Pointer<M::PointerTag>, access: bool) -> EvalResult<'tcx> {
let alloc = self.get(ptr.alloc_id)?;
let allocation_size = alloc.bytes.len() as u64;
if ptr.offset.bytes() > allocation_size {
return err!(PointerOutOfBounds {
- ptr,
+ ptr: ptr.erase_tag(),
access,
allocation_size: Size::from_bytes(allocation_size),
});
}
Ok(())
}
+
+ /// Check if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
+ #[inline(always)]
+ pub fn check_bounds(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ size: Size,
+ access: bool
+ ) -> EvalResult<'tcx> {
+ // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
+ self.check_bounds_ptr(ptr.offset(size, &*self)?, access)
+ }
}
/// Allocation accessors
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
- /// Helper function to obtain the global (tcx) allocation for a static
+ /// Helper function to obtain the global (tcx) allocation for a static.
+ /// This attempts to return a reference to an existing allocation if
+ /// one can be found in `tcx`. That, however, is only possible if `tcx` and
+ /// this machine use the same pointer tag, so it is indirected through
+ /// `M::static_with_default_tag`.
fn get_static_alloc(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
id: AllocId,
- ) -> EvalResult<'tcx, &'tcx Allocation> {
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag>>> {
let alloc = tcx.alloc_map.lock().get(id);
let def_id = match alloc {
Some(AllocType::Memory(mem)) => {
- return Ok(mem)
+ // We got tcx memory. Let the machine figure out whether and how to
+ // turn that into memory with the right pointer tag.
+ return Ok(M::static_with_default_tag(mem))
}
Some(AllocType::Function(..)) => {
return err!(DerefFunctionPointer)
EvalErrorKind::ReferencedConstant(err).into()
}).map(|const_val| {
if let ConstValue::ByRef(_, allocation, _) = const_val.val {
- allocation
+ // We got tcx memory. Let the machine figure out whether and how to
+ // turn that into memory with the right pointer tag.
+ M::static_with_default_tag(allocation)
} else {
bug!("Matching on non-ByRef static")
}
})
}
- pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
- match self.alloc_map.get(&id) {
- // Normal alloc?
- Some(alloc) => Ok(&alloc.1),
- // Static. No need to make any copies, just provide read access to the global static
- // memory in tcx.
- None => Self::get_static_alloc(self.tcx, id),
- }
- }
-
- pub fn get_size_and_align(&self, id: AllocId) -> EvalResult<'tcx, (Size, Align)> {
- Ok(match self.get(id) {
- Ok(alloc) => (Size::from_bytes(alloc.bytes.len() as u64), alloc.align),
- Err(err) => match err.kind {
- EvalErrorKind::DanglingPointerDeref =>
- // This should be in the dead allocation map
- *self.dead_alloc_map.get(&id).expect(
- "allocation missing in dead_alloc_map"
- ),
- // E.g. a function ptr allocation
- _ => return Err(err)
+ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::PointerTag>> {
+ // The error type of the inner closure here is somewhat funny. We have two
+ // ways of "erroring": An actual error, or because we got a reference from
+ // `get_static_alloc` that we can actually use directly without inserting anything anywhere.
+ // So the error type is `EvalResult<'tcx, &Allocation<M::PointerTag>>`.
+ let a = self.alloc_map.get_or(id, || {
+ let alloc = Self::get_static_alloc(self.tcx, id).map_err(Err)?;
+ match alloc {
+ Cow::Borrowed(alloc) => {
+ // We got a ref, cheaply return that as an "error" so that the
+ // map does not get mutated.
+ Err(Ok(alloc))
+ }
+ Cow::Owned(alloc) => {
+ // Need to put it into the map and return a ref to that
+ let kind = M::STATIC_KIND.expect(
+ "I got an owned allocation that I have to copy but the machine does \
+ not expect that to happen"
+ );
+ Ok((MemoryKind::Machine(kind), alloc))
+ }
}
- })
+ });
+ // Now unpack that funny error type
+ match a {
+ Ok(a) => Ok(&a.1),
+ Err(a) => a
+ }
}
pub fn get_mut(
&mut self,
id: AllocId,
- ) -> EvalResult<'tcx, &mut Allocation> {
- // Static?
- if !self.alloc_map.contains_key(&id) {
- // Ask the machine for what to do
- if let Some(kind) = M::MUT_STATIC_KIND {
- // The machine supports mutating statics. Make a copy, use that.
- self.deep_copy_static(id, MemoryKind::Machine(kind))?;
- } else {
- return err!(ModifiedConstantMemory)
+ ) -> EvalResult<'tcx, &mut Allocation<M::PointerTag>> {
+ let tcx = self.tcx;
+ let a = self.alloc_map.get_mut_or(id, || {
+ // Need to make a copy, even if `get_static_alloc` is able
+ // to give us a cheap reference.
+ let alloc = Self::get_static_alloc(tcx, id)?;
+ if alloc.mutability == Mutability::Immutable {
+ return err!(ModifiedConstantMemory);
+ }
+ let kind = M::STATIC_KIND.expect(
+ "An allocation is being mutated but the machine does not expect that to happen"
+ );
+ Ok((MemoryKind::Machine(kind), alloc.into_owned()))
+ });
+ // Unpack the error type manually because type inference doesn't
+ // work otherwise (and we cannot help it because `impl Trait`)
+ match a {
+ Err(e) => Err(e),
+ Ok(a) => {
+ let a = &mut a.1;
+ if a.mutability == Mutability::Immutable {
+ return err!(ModifiedConstantMemory);
+ }
+ Ok(a)
}
}
- // If we come here, we know the allocation is in our map
- let alloc = &mut self.alloc_map.get_mut(&id).unwrap().1;
- // See if we are allowed to mutate this
- if alloc.mutability == Mutability::Immutable {
- err!(ModifiedConstantMemory)
- } else {
- Ok(alloc)
+ }
+
+ pub fn get_size_and_align(&self, id: AllocId) -> (Size, Align) {
+ if let Ok(alloc) = self.get(id) {
+ return (Size::from_bytes(alloc.bytes.len() as u64), alloc.align);
+ }
+ // Could also be a fn ptr or extern static
+ match self.tcx.alloc_map.lock().get(id) {
+ Some(AllocType::Function(..)) => (Size::ZERO, Align::from_bytes(1, 1).unwrap()),
+ Some(AllocType::Static(did)) => {
+ // The only way `get` couldn't have worked here is if this is an extern static
+ assert!(self.tcx.is_foreign_item(did));
+ // Use size and align of the type
+ let ty = self.tcx.type_of(did);
+ let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
+ (layout.size, layout.align)
+ }
+ _ => {
+ // Must be a deallocated pointer
+ *self.dead_alloc_map.get(&id).expect(
+ "allocation missing in dead_alloc_map"
+ )
+ }
}
}
- pub fn get_fn(&self, ptr: Pointer) -> EvalResult<'tcx, Instance<'tcx>> {
+ pub fn get_fn(&self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx, Instance<'tcx>> {
if ptr.offset.bytes() != 0 {
return err!(InvalidFunctionPointer);
}
}
}
+ pub fn mark_immutable(&mut self, id: AllocId) -> EvalResult<'tcx> {
+ self.get_mut(id)?.mutability = Mutability::Immutable;
+ Ok(())
+ }
+
/// For debugging, print an allocation and all allocations it points to, recursively.
pub fn dump_alloc(&self, id: AllocId) {
- if !log_enabled!(::log::Level::Trace) {
- return;
- }
self.dump_allocs(vec![id]);
}
+ fn dump_alloc_helper<Tag>(
+ &self,
+ allocs_seen: &mut FxHashSet<AllocId>,
+ allocs_to_print: &mut VecDeque<AllocId>,
+ mut msg: String,
+ alloc: &Allocation<Tag>,
+ extra: String,
+ ) {
+ use std::fmt::Write;
+
+ let prefix_len = msg.len();
+ let mut relocations = vec![];
+
+ for i in 0..(alloc.bytes.len() as u64) {
+ let i = Size::from_bytes(i);
+ if let Some(&(_, target_id)) = alloc.relocations.get(&i) {
+ if allocs_seen.insert(target_id) {
+ allocs_to_print.push_back(target_id);
+ }
+ relocations.push((i, target_id));
+ }
+ if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)).is_ok() {
+ // this `as usize` is fine, since `i` came from a `usize`
+ write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
+ } else {
+ msg.push_str("__ ");
+ }
+ }
+
+ trace!(
+ "{}({} bytes, alignment {}){}",
+ msg,
+ alloc.bytes.len(),
+ alloc.align.abi(),
+ extra
+ );
+
+ if !relocations.is_empty() {
+ msg.clear();
+ write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
+ let mut pos = Size::ZERO;
+ let relocation_width = (self.pointer_size().bytes() - 1) * 3;
+ for (i, target_id) in relocations {
+ // this `as usize` is fine, since we can't print more chars than `usize::MAX`
+ write!(msg, "{:1$}", "", ((i - pos) * 3).bytes() as usize).unwrap();
+ let target = format!("({})", target_id);
+ // this `as usize` is fine, since we can't print more chars than `usize::MAX`
+ write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap();
+ pos = i + self.pointer_size();
+ }
+ trace!("{}", msg);
+ }
+ }
+
/// For debugging, print a list of allocations and all allocations they point to, recursively.
pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
if !log_enabled!(::log::Level::Trace) {
return;
}
- use std::fmt::Write;
allocs.sort();
allocs.dedup();
let mut allocs_to_print = VecDeque::from(allocs);
let mut allocs_seen = FxHashSet::default();
while let Some(id) = allocs_to_print.pop_front() {
- let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
- let prefix_len = msg.len();
- let mut relocations = vec![];
-
- let (alloc, immutable) =
- // normal alloc?
- match self.alloc_map.get(&id) {
- Some((kind, alloc)) => (alloc, match kind {
+ let msg = format!("Alloc {:<5} ", format!("{}:", id));
+
+ // normal alloc?
+ match self.alloc_map.get_or(id, || Err(())) {
+ Ok((kind, alloc)) => {
+ let extra = match kind {
MemoryKind::Stack => " (stack)".to_owned(),
+ MemoryKind::Vtable => " (vtable)".to_owned(),
MemoryKind::Machine(m) => format!(" ({:?})", m),
- }),
- None => {
- // static alloc?
- match self.tcx.alloc_map.lock().get(id) {
- Some(AllocType::Memory(a)) => (a, " (immutable)".to_owned()),
- Some(AllocType::Function(func)) => {
- trace!("{} {}", msg, func);
- continue;
- }
- Some(AllocType::Static(did)) => {
- trace!("{} {:?}", msg, did);
- continue;
- }
- None => {
- trace!("{} (deallocated)", msg);
- continue;
- }
+ };
+ self.dump_alloc_helper(
+ &mut allocs_seen, &mut allocs_to_print,
+ msg, alloc, extra
+ );
+ },
+ Err(()) => {
+ // static alloc?
+ match self.tcx.alloc_map.lock().get(id) {
+ Some(AllocType::Memory(alloc)) => {
+ self.dump_alloc_helper(
+ &mut allocs_seen, &mut allocs_to_print,
+ msg, alloc, " (immutable)".to_owned()
+ );
+ }
+ Some(AllocType::Function(func)) => {
+ trace!("{} {}", msg, func);
+ }
+ Some(AllocType::Static(did)) => {
+ trace!("{} {:?}", msg, did);
+ }
+ None => {
+ trace!("{} (deallocated)", msg);
}
- },
- };
-
- for i in 0..(alloc.bytes.len() as u64) {
- let i = Size::from_bytes(i);
- if let Some(&target_id) = alloc.relocations.get(&i) {
- if allocs_seen.insert(target_id) {
- allocs_to_print.push_back(target_id);
}
- relocations.push((i, target_id));
- }
- if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)).is_ok() {
- // this `as usize` is fine, since `i` came from a `usize`
- write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
- } else {
- msg.push_str("__ ");
- }
- }
+ },
+ };
- trace!(
- "{}({} bytes, alignment {}){}",
- msg,
- alloc.bytes.len(),
- alloc.align.abi(),
- immutable
- );
-
- if !relocations.is_empty() {
- msg.clear();
- write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
- let mut pos = Size::ZERO;
- let relocation_width = (self.pointer_size().bytes() - 1) * 3;
- for (i, target_id) in relocations {
- // this `as usize` is fine, since we can't print more chars than `usize::MAX`
- write!(msg, "{:1$}", "", ((i - pos) * 3).bytes() as usize).unwrap();
- let target = format!("({})", target_id);
- // this `as usize` is fine, since we can't print more chars than `usize::MAX`
- write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap();
- pos = i + self.pointer_size();
- }
- trace!("{}", msg);
- }
}
}
pub fn leak_report(&self) -> usize {
trace!("### LEAK REPORT ###");
- let mut_static_kind = M::MUT_STATIC_KIND.map(|k| MemoryKind::Machine(k));
- let leaks: Vec<_> = self.alloc_map
- .iter()
- .filter_map(|(&id, &(kind, _))|
- // exclude mutable statics
- if Some(kind) == mut_static_kind { None } else { Some(id) } )
- .collect();
+ let leaks: Vec<_> = self.alloc_map.filter_map_collect(|&id, &(kind, _)| {
+ // exclude statics and vtables
+ let exclude = match kind {
+ MemoryKind::Stack => false,
+ MemoryKind::Vtable => true,
+ MemoryKind::Machine(k) => Some(k) == M::STATIC_KIND,
+ };
+ if exclude { None } else { Some(id) }
+ });
let n = leaks.len();
self.dump_allocs(leaks);
n
/// The last argument controls whether we error out when there are undefined
/// or pointer bytes. You should never call this, call `get_bytes` or
/// `get_bytes_with_undef_and_ptr` instead,
+ ///
+ /// This function also guarantees that the resulting pointer will remain stable
+ /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+ /// on that.
fn get_bytes_internal(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
align: Align,
check_defined_and_ptr: bool,
) -> EvalResult<'tcx, &[u8]> {
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
self.check_align(ptr.into(), align)?;
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds(ptr.offset(size, &*self)?, true)?;
+ self.check_bounds(ptr, size, true)?;
if check_defined_and_ptr {
self.check_defined(ptr, size)?;
}
#[inline]
- fn get_bytes(&self, ptr: Pointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> {
+ fn get_bytes(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ size: Size,
+ align: Align
+ ) -> EvalResult<'tcx, &[u8]> {
self.get_bytes_internal(ptr, size, align, true)
}
#[inline]
fn get_bytes_with_undef_and_ptr(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
align: Align
) -> EvalResult<'tcx, &[u8]> {
/// so be sure to actually put data there!
fn get_bytes_mut(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
align: Align,
) -> EvalResult<'tcx, &mut [u8]> {
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
self.check_align(ptr.into(), align)?;
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds(ptr.offset(size, &self)?, true)?;
+ self.check_bounds(ptr, size, true)?;
self.mark_definedness(ptr, size, true)?;
self.clear_relocations(ptr, size)?;
}
}
-/// Reading and writing
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+/// Interning (for CTFE)
+impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
+where
+ M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
+ M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<()>)>,
+{
/// mark an allocation as static and initialized, either mutable or not
pub fn intern_static(
&mut self,
let (kind, mut alloc) = self.alloc_map.remove(&alloc_id).unwrap();
match kind {
MemoryKind::Machine(_) => bug!("Static cannot refer to machine memory"),
- MemoryKind::Stack => {},
+ MemoryKind::Stack | MemoryKind::Vtable => {},
}
// ensure llvm knows not to put this into immutable memory
alloc.mutability = mutability;
let alloc = self.tcx.intern_const_alloc(alloc);
self.tcx.alloc_map.lock().set_id_memory(alloc_id, alloc);
// recurse into inner allocations
- for &alloc in alloc.relocations.values() {
+ for &(_, alloc) in alloc.relocations.values() {
// FIXME: Reusing the mutability here is likely incorrect. It is originally
// determined via `is_freeze`, and data is considered frozen if there is no
// `UnsafeCell` *immediately* in that data -- however, this search stops
}
Ok(())
}
+}
- /// The alloc_id must refer to a (mutable) static; a deep copy of that
- /// static is made into this memory.
- fn deep_copy_static(
- &mut self,
- id: AllocId,
- kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx> {
- let alloc = Self::get_static_alloc(self.tcx, id)?;
- if alloc.mutability == Mutability::Immutable {
- return err!(ModifiedConstantMemory);
- }
- let old = self.alloc_map.insert(id, (kind, alloc.clone()));
- assert!(old.is_none(), "deep_copy_static: must not overwrite existing memory");
- Ok(())
- }
-
+/// Reading and writing
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn copy(
&mut self,
- src: Scalar,
+ src: Scalar<M::PointerTag>,
src_align: Align,
- dest: Scalar,
+ dest: Scalar<M::PointerTag>,
dest_align: Align,
size: Size,
nonoverlapping: bool,
pub fn copy_repeatedly(
&mut self,
- src: Scalar,
+ src: Scalar<M::PointerTag>,
src_align: Align,
- dest: Scalar,
+ dest: Scalar<M::PointerTag>,
dest_align: Align,
size: Size,
length: u64,
new_relocations.extend(
relocations
.iter()
- .map(|&(offset, alloc_id)| {
+ .map(|&(offset, reloc)| {
(offset + dest.offset - src.offset + (i * size * relocations.len() as u64),
- alloc_id)
+ reloc)
})
);
}
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
// behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
// `dest` could possibly overlap.
+ // The pointers above remain valid even if the `HashMap` table is moved around because they
+ // point into the `Vec` storing the bytes.
unsafe {
assert_eq!(size.bytes() as usize as u64, size.bytes());
if src.alloc_id == dest.alloc_id {
Ok(())
}
- pub fn read_c_str(&self, ptr: Pointer) -> EvalResult<'tcx, &[u8]> {
+ pub fn read_c_str(&self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx, &[u8]> {
let alloc = self.get(ptr.alloc_id)?;
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
let offset = ptr.offset.bytes() as usize;
self.check_defined(ptr, p1)?;
Ok(&alloc.bytes[offset..offset + size])
}
- None => err!(UnterminatedCString(ptr)),
+ None => err!(UnterminatedCString(ptr.erase_tag())),
}
}
- pub fn read_bytes(&self, ptr: Scalar, size: Size) -> EvalResult<'tcx, &[u8]> {
+ pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, size: Size) -> EvalResult<'tcx, &[u8]> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
if size.bytes() == 0 {
self.get_bytes(ptr.to_ptr()?, size, align)
}
- pub fn write_bytes(&mut self, ptr: Scalar, src: &[u8]) -> EvalResult<'tcx> {
+ pub fn write_bytes(&mut self, ptr: Scalar<M::PointerTag>, src: &[u8]) -> EvalResult<'tcx> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
if src.is_empty() {
Ok(())
}
- pub fn write_repeat(&mut self, ptr: Scalar, val: u8, count: Size) -> EvalResult<'tcx> {
+ pub fn write_repeat(
+ &mut self,
+ ptr: Scalar<M::PointerTag>,
+ val: u8,
+ count: Size
+ ) -> EvalResult<'tcx> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
if count.bytes() == 0 {
/// Read a *non-ZST* scalar
pub fn read_scalar(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
ptr_align: Align,
size: Size
- ) -> EvalResult<'tcx, ScalarMaybeUndef> {
+ ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
// get_bytes_unchecked tests alignment and relocation edges
let bytes = self.get_bytes_with_undef_and_ptr(
ptr, size, ptr_align.min(self.int_align(size))
} else {
let alloc = self.get(ptr.alloc_id)?;
match alloc.relocations.get(&ptr.offset) {
- Some(&alloc_id) => {
- let ptr = Pointer::new(alloc_id, Size::from_bytes(bits as u64));
+ Some(&(tag, alloc_id)) => {
+ let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits as u64), tag);
return Ok(ScalarMaybeUndef::Scalar(ptr.into()))
}
None => {},
Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size)))
}
- pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align)
- -> EvalResult<'tcx, ScalarMaybeUndef> {
+ pub fn read_ptr_sized(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ ptr_align: Align
+ ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
self.read_scalar(ptr, ptr_align, self.pointer_size())
}
/// Write a *non-ZST* scalar
pub fn write_scalar(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
ptr_align: Align,
- val: ScalarMaybeUndef,
+ val: ScalarMaybeUndef<M::PointerTag>,
type_size: Size,
) -> EvalResult<'tcx> {
let val = match val {
Scalar::Ptr(val) => {
self.get_mut(ptr.alloc_id)?.relocations.insert(
ptr.offset,
- val.alloc_id,
+ (val.tag, val.alloc_id),
);
}
_ => {}
Ok(())
}
- pub fn write_ptr_sized(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef)
- -> EvalResult<'tcx> {
+ pub fn write_ptr_sized(
+ &mut self,
+ ptr: Pointer<M::PointerTag>,
+ ptr_align: Align,
+ val: ScalarMaybeUndef<M::PointerTag>
+ ) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
self.write_scalar(ptr.into(), ptr_align, val, ptr_size)
}
/// Return all relocations overlapping with the given ptr-offset pair.
fn relocations(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
- ) -> EvalResult<'tcx, &[(Size, AllocId)]> {
+ ) -> EvalResult<'tcx, &[(Size, (M::PointerTag, AllocId))]> {
// We have to go back `pointer_size - 1` bytes, as that one would still overlap with
// the beginning of this range.
let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1);
/// Check that there ar eno relocations overlapping with the given range.
#[inline(always)]
- fn check_relocations(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn check_relocations(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
if self.relocations(ptr, size)?.len() != 0 {
err!(ReadPointerAsBytes)
} else {
/// uninitialized. This is a somewhat odd "spooky action at a distance",
/// but it allows strictly more code to run than if we would just error
/// immediately in that case.
- fn clear_relocations(&mut self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn clear_relocations(&mut self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
// Find the start and end of the given range and its outermost relocations.
let (first, last) = {
// Find all relocations overlapping the given range.
/// Error if there are relocations overlapping with the egdes of the
/// given memory range.
#[inline]
- fn check_relocation_edges(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn check_relocation_edges(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
self.check_relocations(ptr, Size::ZERO)?;
self.check_relocations(ptr.offset(size, self)?, Size::ZERO)?;
Ok(())
// FIXME: Add a fast version for the common, nonoverlapping case
fn copy_undef_mask(
&mut self,
- src: Pointer,
- dest: Pointer,
+ src: Pointer<M::PointerTag>,
+ dest: Pointer<M::PointerTag>,
size: Size,
repeat: u64,
) -> EvalResult<'tcx> {
/// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes`
/// error which will report the first byte which is undefined.
#[inline]
- fn check_defined(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn check_defined(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
let alloc = self.get(ptr.alloc_id)?;
alloc.undef_mask.is_range_defined(
ptr.offset,
pub fn mark_definedness(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
new_state: bool,
) -> EvalResult<'tcx> {
pub use self::memory::{Memory, MemoryKind};
-pub use self::machine::Machine;
+pub use self::machine::{Machine, AllocMap};
pub use self::operand::{ScalarMaybeUndef, Value, ValTy, Operand, OpTy};
+
+pub use self::validity::RefTracking;
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef<Id=AllocId> {
- Scalar(Scalar<Id>),
+pub enum ScalarMaybeUndef<Tag=(), Id=AllocId> {
+ Scalar(Scalar<Tag, Id>),
Undef,
}
-impl From<Scalar> for ScalarMaybeUndef {
+impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
#[inline(always)]
- fn from(s: Scalar) -> Self {
+ fn from(s: Scalar<Tag>) -> Self {
ScalarMaybeUndef::Scalar(s)
}
}
-impl<'tcx> ScalarMaybeUndef {
+impl<'tcx> ScalarMaybeUndef<()> {
#[inline]
- pub fn not_undef(self) -> EvalResult<'static, Scalar> {
+ pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
+ where Tag: Default
+ {
+ match self {
+ ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
+ ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+ }
+ }
+}
+
+impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> ScalarMaybeUndef
+ {
+ match self {
+ ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.erase_tag()),
+ ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+ }
+ }
+
+ #[inline]
+ pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
match self {
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
}
#[inline(always)]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
self.not_undef()?.to_ptr()
}
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
/// defined on `Value`, and do not have to work with a `Place`.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Value<Id=AllocId> {
- Scalar(ScalarMaybeUndef<Id>),
- ScalarPair(ScalarMaybeUndef<Id>, ScalarMaybeUndef<Id>),
+pub enum Value<Tag=(), Id=AllocId> {
+ Scalar(ScalarMaybeUndef<Tag, Id>),
+ ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
}
-impl<'tcx> Value {
+impl Value {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> Value<Tag>
+ where Tag: Default
+ {
+ match self {
+ Value::Scalar(x) => Value::Scalar(x.with_default_tag()),
+ Value::ScalarPair(x, y) =>
+ Value::ScalarPair(x.with_default_tag(), y.with_default_tag()),
+ }
+ }
+}
+
+impl<'tcx, Tag> Value<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> Value
+ {
+ match self {
+ Value::Scalar(x) => Value::Scalar(x.erase_tag()),
+ Value::ScalarPair(x, y) =>
+ Value::ScalarPair(x.erase_tag(), y.erase_tag()),
+ }
+ }
+
pub fn new_slice(
- val: Scalar,
+ val: Scalar<Tag>,
len: u64,
cx: impl HasDataLayout
) -> Self {
Value::ScalarPair(val.into(), Scalar::from_uint(len, cx.data_layout().pointer_size).into())
}
- pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
+ pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>) -> Self {
Value::ScalarPair(val.into(), Scalar::Ptr(vtable).into())
}
#[inline]
- pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef {
+ pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef<Tag> {
match self {
Value::Scalar(val) => val,
Value::ScalarPair(..) => bug!("Got a fat pointer where a scalar was expected"),
}
#[inline]
- pub fn to_scalar(self) -> EvalResult<'tcx, Scalar> {
+ pub fn to_scalar(self) -> EvalResult<'tcx, Scalar<Tag>> {
self.to_scalar_or_undef().not_undef()
}
#[inline]
- pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> {
+ pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
match self {
Value::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"),
Value::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?))
/// Convert the value into a pointer (or a pointer-sized integer).
/// Throws away the second half of a ScalarPair!
#[inline]
- pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> {
+ pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar<Tag>> {
match self {
Value::Scalar(ptr) |
Value::ScalarPair(ptr, _) => ptr.not_undef(),
// ScalarPair needs a type to interpret, so we often have a value and a type together
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
-pub struct ValTy<'tcx> {
- value: Value,
+pub struct ValTy<'tcx, Tag=()> {
+ value: Value<Tag>,
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
- type Target = Value;
+impl<'tcx, Tag> ::std::ops::Deref for ValTy<'tcx, Tag> {
+ type Target = Value<Tag>;
#[inline(always)]
- fn deref(&self) -> &Value {
+ fn deref(&self) -> &Value<Tag> {
&self.value
}
}
/// or still in memory. The latter is an optimization, to delay reading that chunk of
/// memory and to avoid having to store arbitrary-sized data here.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Operand<Id=AllocId> {
- Immediate(Value<Id>),
- Indirect(MemPlace<Id>),
+pub enum Operand<Tag=(), Id=AllocId> {
+ Immediate(Value<Tag, Id>),
+ Indirect(MemPlace<Tag, Id>),
}
impl Operand {
#[inline]
- pub fn to_mem_place(self) -> MemPlace {
+ pub fn with_default_tag<Tag>(self) -> Operand<Tag>
+ where Tag: Default
+ {
+ match self {
+ Operand::Immediate(x) => Operand::Immediate(x.with_default_tag()),
+ Operand::Indirect(x) => Operand::Indirect(x.with_default_tag()),
+ }
+ }
+}
+
+impl<Tag> Operand<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> Operand
+ {
+ match self {
+ Operand::Immediate(x) => Operand::Immediate(x.erase_tag()),
+ Operand::Indirect(x) => Operand::Indirect(x.erase_tag()),
+ }
+ }
+
+ #[inline]
+ pub fn to_mem_place(self) -> MemPlace<Tag>
+ where Tag: ::std::fmt::Debug
+ {
match self {
Operand::Indirect(mplace) => mplace,
_ => bug!("to_mem_place: expected Operand::Indirect, got {:?}", self),
}
#[inline]
- pub fn to_immediate(self) -> Value {
+ pub fn to_immediate(self) -> Value<Tag>
+ where Tag: ::std::fmt::Debug
+ {
match self {
Operand::Immediate(val) => val,
_ => bug!("to_immediate: expected Operand::Immediate, got {:?}", self),
}
#[derive(Copy, Clone, Debug)]
-pub struct OpTy<'tcx> {
- crate op: Operand, // ideally we'd make this private, but const_prop needs this
+pub struct OpTy<'tcx, Tag=()> {
+ crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for OpTy<'tcx> {
- type Target = Operand;
+impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> {
+ type Target = Operand<Tag>;
#[inline(always)]
- fn deref(&self) -> &Operand {
+ fn deref(&self) -> &Operand<Tag> {
&self.op
}
}
-impl<'tcx> From<MPlaceTy<'tcx>> for OpTy<'tcx> {
+impl<'tcx, Tag: Copy> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)]
- fn from(mplace: MPlaceTy<'tcx>) -> Self {
+ fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
OpTy {
op: Operand::Indirect(*mplace),
layout: mplace.layout
}
}
-impl<'tcx> From<ValTy<'tcx>> for OpTy<'tcx> {
+impl<'tcx, Tag> From<ValTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)]
- fn from(val: ValTy<'tcx>) -> Self {
+ fn from(val: ValTy<'tcx, Tag>) -> Self {
OpTy {
op: Operand::Immediate(val.value),
layout: val.layout
}
// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type
-impl<'tcx> Hash for OpTy<'tcx> {
+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> PartialEq for OpTy<'tcx> {
+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> Eq for OpTy<'tcx> {}
+impl<'tcx, Tag> Eq for OpTy<'tcx, Tag>
+ where Tag: Eq
+{}
+
+impl<'tcx, Tag> OpTy<'tcx, Tag>
+{
+ #[inline]
+ pub fn erase_tag(self) -> OpTy<'tcx>
+ {
+ OpTy {
+ op: self.op.erase_tag(),
+ layout: self.layout,
+ }
+ }
+}
// Use the existing layout if given (but sanity check in debug mode),
// or compute the layout.
/// Return None if the layout does not permit loading this as a value.
pub(super) fn try_read_value_from_mplace(
&self,
- mplace: MPlaceTy<'tcx>,
- ) -> EvalResult<'tcx, Option<Value>> {
+ mplace: MPlaceTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, Option<Value<M::PointerTag>>> {
if mplace.layout.is_unsized() {
// Dont touch unsized
return Ok(None);
/// in a `Value`, not on which data is stored there currently.
pub(crate) fn try_read_value(
&self,
- src: OpTy<'tcx>,
- ) -> EvalResult<'tcx, Result<Value, MemPlace>> {
+ src: OpTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, Result<Value<M::PointerTag>, MemPlace<M::PointerTag>>> {
Ok(match src.try_as_mplace() {
Ok(mplace) => {
if let Some(val) = self.try_read_value_from_mplace(mplace)? {
/// Read a value from a place, asserting that that is possible with the given layout.
#[inline(always)]
- pub fn read_value(&self, op: OpTy<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
+ pub fn read_value(
+ &self,
+ op: OpTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, ValTy<'tcx, M::PointerTag>> {
if let Ok(value) = self.try_read_value(op)? {
Ok(ValTy { value, layout: op.layout })
} else {
}
/// Read a scalar from a place
- pub fn read_scalar(&self, op: OpTy<'tcx>) -> EvalResult<'tcx, ScalarMaybeUndef> {
+ pub fn read_scalar(
+ &self,
+ op: OpTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
match *self.read_value(op)? {
Value::ScalarPair(..) => bug!("got ScalarPair for type: {:?}", op.layout.ty),
Value::Scalar(val) => Ok(val),
// Turn the MPlace into a string (must already be dereferenced!)
pub fn read_str(
&self,
- mplace: MPlaceTy<'tcx>,
+ mplace: MPlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, &str> {
let len = mplace.len(self)?;
let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
Ok(str)
}
- pub fn uninit_operand(&mut self, layout: TyLayout<'tcx>) -> EvalResult<'tcx, Operand> {
+ pub fn uninit_operand(
+ &mut self,
+ layout: TyLayout<'tcx>
+ ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
// This decides which types we will use the Immediate optimization for, and hence should
// match what `try_read_value` and `eval_place_to_op` support.
if layout.is_zst() {
/// Projection functions
pub fn operand_field(
&self,
- op: OpTy<'tcx>,
+ op: OpTy<'tcx, M::PointerTag>,
field: u64,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let base = match op.try_as_mplace() {
Ok(mplace) => {
// The easy case
pub fn operand_downcast(
&self,
- op: OpTy<'tcx>,
+ op: OpTy<'tcx, M::PointerTag>,
variant: usize,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
Ok(match op.try_as_mplace() {
Ok(mplace) => {
// will always be a MemPlace.
pub(super) fn deref_operand(
&self,
- src: OpTy<'tcx>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ src: OpTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_value(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
Ok(self.ref_to_mplace(val)?)
pub fn operand_projection(
&self,
- base: OpTy<'tcx>,
+ base: OpTy<'tcx, M::PointerTag>,
proj_elem: &mir::PlaceElem<'tcx>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::ProjectionElem::*;
Ok(match *proj_elem {
Field(field, _) => self.operand_field(base, field.index() as u64)?,
&self,
mir_place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
let op = match *mir_place {
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
&self,
mir_op: &mir::Operand<'tcx>,
layout: Option<TyLayout<'tcx>>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::Operand::*;
let op = match *mir_op {
// FIXME: do some more logic on `move` to invalidate the old location
pub(super) fn eval_operands(
&self,
ops: &[mir::Operand<'tcx>],
- ) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> {
+ ) -> EvalResult<'tcx, Vec<OpTy<'tcx, M::PointerTag>>> {
ops.into_iter()
.map(|op| self.eval_operand(op, None))
.collect()
pub(super) fn const_value_to_op(
&self,
val: ConstValue<'tcx>,
- ) -> EvalResult<'tcx, Operand> {
+ ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
trace!("const_value_to_op: {:?}", val);
match val {
ConstValue::Unevaluated(def_id, substs) => {
ConstValue::ByRef(id, alloc, offset) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.
- Ok(Operand::Indirect(MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)))
+ Ok(Operand::Indirect(
+ MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)
+ ).with_default_tag())
},
ConstValue::ScalarPair(a, b) =>
- Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into()))),
+ Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into())).with_default_tag()),
ConstValue::Scalar(x) =>
- Ok(Operand::Immediate(Value::Scalar(x.into()))),
+ Ok(Operand::Immediate(Value::Scalar(x.into())).with_default_tag()),
}
}
pub fn const_to_op(
&self,
cnst: &ty::Const<'tcx>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = self.const_value_to_op(cnst.val)?;
Ok(OpTy { op, layout: self.layout_of(cnst.ty)? })
}
- pub(super) fn global_to_op(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Operand> {
+ pub(super) fn global_to_op(
+ &self,
+ gid: GlobalId<'tcx>
+ ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
let cv = self.const_eval(gid)?;
self.const_value_to_op(cv.val)
}
/// Read discriminant, return the runtime value as well as the variant index.
pub fn read_discriminant(
&self,
- rval: OpTy<'tcx>,
+ rval: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, (u128, usize)> {
trace!("read_discriminant_value {:#?}", rval.layout);
if rval.layout.abi.is_uninhabited() {
pub fn binop_with_overflow(
&mut self,
op: mir::BinOp,
- left: ValTy<'tcx>,
- right: ValTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ left: ValTy<'tcx, M::PointerTag>,
+ right: ValTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let (val, overflowed) = self.binary_op_val(op, left, right)?;
let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
pub fn binop_ignore_overflow(
&mut self,
op: mir::BinOp,
- left: ValTy<'tcx>,
- right: ValTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ left: ValTy<'tcx, M::PointerTag>,
+ right: ValTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let (val, _overflowed) = self.binary_op_val(op, left, right)?;
self.write_scalar(val, dest)
bin_op: mir::BinOp,
l: char,
r: char,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
let res = match bin_op {
bin_op: mir::BinOp,
l: bool,
r: bool,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
let res = match bin_op {
// passing in raw bits
l: u128,
r: u128,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
macro_rules! float_math {
left_layout: TyLayout<'tcx>,
r: u128,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
// Shift ops can have an RHS with a different numeric type.
pub fn binary_op_val(
&self,
bin_op: mir::BinOp,
- left: ValTy<'tcx>,
- right: ValTy<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ left: ValTy<'tcx, M::PointerTag>,
+ right: ValTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
self.binary_op(
bin_op,
left.to_scalar()?, left.layout,
pub fn binary_op(
&self,
bin_op: mir::BinOp,
- left: Scalar,
+ left: Scalar<M::PointerTag>,
left_layout: TyLayout<'tcx>,
- right: Scalar,
+ right: Scalar<M::PointerTag>,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, left, left_layout.ty, right, right_layout.ty);
pub fn unary_op(
&self,
un_op: mir::UnOp,
- val: Scalar,
+ val: Scalar<M::PointerTag>,
layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::mir::UnOp::*;
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
//! All high-level functions to write to memory work on places as destinations.
use std::convert::TryFrom;
+use std::hash::Hash;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
use rustc::mir::interpret::{
- GlobalId, AllocId, Scalar, EvalResult, Pointer, PointerArithmetic
+ GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic
+};
+use super::{
+ EvalContext, Machine, AllocMap,
+ Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
};
-use super::{EvalContext, Machine, Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct MemPlace<Id=AllocId> {
+pub struct MemPlace<Tag=(), Id=AllocId> {
/// A place may have an integral pointer for ZSTs, and since it might
/// be turned back into a reference before ever being dereferenced.
/// However, it may never be undef.
- pub ptr: Scalar<Id>,
+ pub ptr: Scalar<Tag, Id>,
pub align: Align,
/// Metadata for unsized places. Interpretation is up to the type.
/// Must not be present for sized types, but can be missing for unsized types
/// (e.g. `extern type`).
- pub extra: Option<Scalar<Id>>,
+ pub meta: Option<Scalar<Tag, Id>>,
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Place<Id=AllocId> {
+pub enum Place<Tag=(), Id=AllocId> {
/// A place referring to a value allocated in the `Memory` system.
- Ptr(MemPlace<Id>),
+ Ptr(MemPlace<Tag, Id>),
/// To support alloc-free locals, we are able to write directly to a local.
/// (Without that optimization, we'd just always be a `MemPlace`.)
}
#[derive(Copy, Clone, Debug)]
-pub struct PlaceTy<'tcx> {
- place: Place,
+pub struct PlaceTy<'tcx, Tag=()> {
+ place: Place<Tag>,
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for PlaceTy<'tcx> {
- type Target = Place;
+impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
+ type Target = Place<Tag>;
#[inline(always)]
- fn deref(&self) -> &Place {
+ fn deref(&self) -> &Place<Tag> {
&self.place
}
}
/// A MemPlace with its layout. Constructing it is only possible in this module.
#[derive(Copy, Clone, Debug)]
-pub struct MPlaceTy<'tcx> {
- mplace: MemPlace,
+pub struct MPlaceTy<'tcx, Tag=()> {
+ mplace: MemPlace<Tag>,
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for MPlaceTy<'tcx> {
- type Target = MemPlace;
+impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
+ type Target = MemPlace<Tag>;
#[inline(always)]
- fn deref(&self) -> &MemPlace {
+ fn deref(&self) -> &MemPlace<Tag> {
&self.mplace
}
}
-impl<'tcx> From<MPlaceTy<'tcx>> for PlaceTy<'tcx> {
+impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
#[inline(always)]
- fn from(mplace: MPlaceTy<'tcx>) -> Self {
+ fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
PlaceTy {
place: Place::Ptr(mplace.mplace),
layout: mplace.layout
}
impl MemPlace {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
+ where Tag: Default
+ {
+ MemPlace {
+ ptr: self.ptr.with_default_tag(),
+ align: self.align,
+ meta: self.meta.map(Scalar::with_default_tag),
+ }
+ }
+}
+
+impl<Tag> MemPlace<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> MemPlace
+ {
+ MemPlace {
+ ptr: self.ptr.erase_tag(),
+ align: self.align,
+ meta: self.meta.map(Scalar::erase_tag),
+ }
+ }
+
#[inline(always)]
- pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+ pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
MemPlace {
ptr,
align,
- extra: None,
+ meta: None,
}
}
#[inline(always)]
- pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
+ pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
Self::from_scalar_ptr(ptr.into(), align)
}
#[inline(always)]
- pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
- assert_eq!(self.extra, None);
+ pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
+ assert!(self.meta.is_none());
(self.ptr, self.align)
}
- /// Extract the ptr part of the mplace
+ /// metact the ptr part of the mplace
#[inline(always)]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
// At this point, we forget about the alignment information --
// the place has been turned into a reference, and no matter where it came from,
// it now must be aligned.
/// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
/// This is the inverse of `ref_to_mplace`.
- pub fn to_ref(self) -> Value {
+ pub fn to_ref(self) -> Value<Tag> {
// We ignore the alignment of the place here -- special handling for packed structs ends
// at the `&` operator.
- match self.extra {
+ match self.meta {
None => Value::Scalar(self.ptr.into()),
- Some(extra) => Value::ScalarPair(self.ptr.into(), extra.into()),
+ Some(meta) => Value::ScalarPair(self.ptr.into(), meta.into()),
}
}
}
-impl<'tcx> MPlaceTy<'tcx> {
+impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
+ /// Produces a MemPlace that works for ZST but nothing else
#[inline]
- fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
+ pub fn dangling(layout: TyLayout<'tcx>, cx: impl HasDataLayout) -> Self {
+ MPlaceTy {
+ mplace: MemPlace::from_scalar_ptr(
+ Scalar::from_uint(layout.align.abi(), cx.pointer_size()),
+ layout.align
+ ),
+ layout
+ }
+ }
+
+ #[inline]
+ fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
}
#[inline]
pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
if self.layout.is_unsized() {
- // We need to consult `extra` metadata
+ // We need to consult `meta` metadata
match self.layout.ty.sty {
ty::Slice(..) | ty::Str =>
- return self.extra.unwrap().to_usize(cx),
+ return self.mplace.meta.unwrap().to_usize(cx),
_ => bug!("len not supported on unsized type {:?}", self.layout.ty),
}
} else {
}
#[inline]
- pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> {
+ pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
match self.layout.ty.sty {
- ty::Dynamic(..) => self.extra.unwrap().to_ptr(),
+ ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
_ => bug!("vtable not supported on type {:?}", self.layout.ty),
}
}
}
-impl<'tcx> OpTy<'tcx> {
+impl<'tcx, Tag: ::std::fmt::Debug> OpTy<'tcx, Tag> {
#[inline(always)]
- pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx>, Value> {
- match *self {
+ pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Value<Tag>> {
+ match self.op {
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
Operand::Immediate(value) => Err(value),
}
}
#[inline(always)]
- pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
+ pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
self.try_as_mplace().unwrap()
}
}
-impl<'tcx> Place {
+impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
/// Produces a Place that will error if attempted to be read from or written to
#[inline]
pub fn null(cx: impl HasDataLayout) -> Self {
}
#[inline]
- pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+ pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
}
#[inline]
- pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
+ pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
Place::Ptr(MemPlace::from_ptr(ptr, align))
}
#[inline]
- pub fn to_mem_place(self) -> MemPlace {
+ pub fn to_mem_place(self) -> MemPlace<Tag> {
match self {
Place::Ptr(mplace) => mplace,
_ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
}
#[inline]
- pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
+ pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
self.to_mem_place().to_scalar_ptr_align()
}
#[inline]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
self.to_mem_place().to_ptr()
}
}
-impl<'tcx> PlaceTy<'tcx> {
+impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
/// Produces a Place that will error if attempted to be read from or written to
#[inline]
pub fn null(cx: impl HasDataLayout, layout: TyLayout<'tcx>) -> Self {
}
#[inline]
- pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
+ pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
}
}
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
+impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
+where
+ Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
+ M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
+ M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag>)>,
+{
/// Take a value, which represents a (thin or fat) reference, and make it a place.
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref`.
pub fn ref_to_mplace(
- &self, val: ValTy<'tcx>
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ &self, val: ValTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
let layout = self.layout_of(pointee_type)?;
let align = layout.align;
let mplace = match *val {
Value::Scalar(ptr) =>
- MemPlace { ptr: ptr.not_undef()?, align, extra: None },
- Value::ScalarPair(ptr, extra) =>
- MemPlace { ptr: ptr.not_undef()?, align, extra: Some(extra.not_undef()?) },
+ MemPlace { ptr: ptr.not_undef()?, align, meta: None },
+ Value::ScalarPair(ptr, meta) =>
+ MemPlace { ptr: ptr.not_undef()?, align, meta: Some(meta.not_undef()?) },
};
Ok(MPlaceTy { mplace, layout })
}
#[inline(always)]
pub fn mplace_field(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
field: u64,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// Not using the layout method because we want to compute on u64
let offset = match base.layout.fields {
layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
// Offset may need adjustment for unsized fields
- let (extra, offset) = if field_layout.is_unsized() {
+ let (meta, offset) = if field_layout.is_unsized() {
// re-use parent metadata to determine dynamic field layout
- let (_, align) = self.size_and_align_of(base.extra, field_layout)?;
- (base.extra, offset.abi_align(align))
+ let (_, align) = self.size_and_align_of(base.meta, field_layout)?;
+ (base.meta, offset.abi_align(align))
} else {
- // base.extra could be present; we might be accessing a sized field of an unsized
+ // base.meta could be present; we might be accessing a sized field of an unsized
// struct.
(None, offset)
};
// codegen -- mostly to see if we can get away with that
.restrict_for_offset(offset); // must be last thing that happens
- Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
+ Ok(MPlaceTy { mplace: MemPlace { ptr, align, meta }, layout: field_layout })
}
// Iterates over all fields of an array. Much more efficient than doing the
// same by repeatedly calling `mplace_array`.
pub fn mplace_array_fields(
&self,
- base: MPlaceTy<'tcx>,
- ) -> EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx>>> + 'a> {
+ base: MPlaceTy<'tcx, Tag>,
+ ) ->
+ EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
+ {
let len = base.len(self)?; // also asserts that we have a type where this makes sense
let stride = match base.layout.fields {
layout::FieldPlacement::Array { stride, .. } => stride,
Ok((0..len).map(move |i| {
let ptr = base.ptr.ptr_offset(i * stride, dl)?;
Ok(MPlaceTy {
- mplace: MemPlace { ptr, align: base.align, extra: None },
+ mplace: MemPlace { ptr, align: base.align, meta: None },
layout
})
}))
pub fn mplace_subslice(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
from: u64,
to: u64,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let len = base.len(self)?; // also asserts that we have a type where this makes sense
assert!(from <= len - to);
};
let ptr = base.ptr.ptr_offset(from_offset, self)?;
- // Compute extra and new layout
+ // Compute meta and new layout
let inner_len = len - to - from;
- let (extra, ty) = match base.layout.ty.sty {
+ let (meta, ty) = match base.layout.ty.sty {
// It is not nice to match on the type, but that seems to be the only way to
// implement this.
ty::Array(inner, _) =>
let layout = self.layout_of(ty)?;
Ok(MPlaceTy {
- mplace: MemPlace { ptr, align: base.align, extra },
+ mplace: MemPlace { ptr, align: base.align, meta },
layout
})
}
pub fn mplace_downcast(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
variant: usize,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
- assert_eq!(base.extra, None);
+ assert!(base.meta.is_none());
Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
}
/// Project into an mplace
pub fn mplace_projection(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
proj_elem: &mir::PlaceElem<'tcx>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::ProjectionElem::*;
Ok(match *proj_elem {
Field(field, _) => self.mplace_field(base, field.index() as u64)?,
/// Just a convenience function, but used quite a bit.
pub fn place_field(
&mut self,
- base: PlaceTy<'tcx>,
+ base: PlaceTy<'tcx, M::PointerTag>,
field: u64,
- ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// FIXME: We could try to be smarter and avoid allocation for fields that span the
// entire place.
let mplace = self.force_allocation(base)?;
pub fn place_downcast(
&mut self,
- base: PlaceTy<'tcx>,
+ base: PlaceTy<'tcx, M::PointerTag>,
variant: usize,
- ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// Downcast just changes the layout
Ok(match base.place {
Place::Ptr(mplace) =>
/// Project into a place
pub fn place_projection(
&mut self,
- base: PlaceTy<'tcx>,
+ base: PlaceTy<'tcx, M::PointerTag>,
proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
- ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::ProjectionElem::*;
Ok(match *proj_elem {
Field(field, _) => self.place_field(base, field.index() as u64)?,
pub(super) fn eval_place_to_mplace(
&self,
mir_place: &mir::Place<'tcx>
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
Ok(match *mir_place {
Promoted(ref promoted) => {
// and miri: They use the same query to eventually obtain a `ty::Const`
// and use that for further computation.
let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
- MPlaceTy::from_aligned_ptr(alloc.into(), layout)
+ MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
}
_ => bug!("eval_place_to_mplace called on {:?}", mir_place),
/// Compute a place. You should only use this if you intend to write into this
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
- pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ pub fn eval_place(
+ &mut self,
+ mir_place: &mir::Place<'tcx>
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
let place = match *mir_place {
Local(mir::RETURN_PLACE) => PlaceTy {
/// Write a scalar to a place
pub fn write_scalar(
&mut self,
- val: impl Into<ScalarMaybeUndef>,
- dest: PlaceTy<'tcx>,
+ val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
self.write_value(Value::Scalar(val.into()), dest)
}
/// Write a value to a place
pub fn write_value(
&mut self,
- src_val: Value,
- dest: PlaceTy<'tcx>,
+ src_val: Value<M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
trace!("write_value: {:?} <- {:?}", *dest, src_val);
+ // Check that the value actually is okay for that type
+ if M::ENFORCE_VALIDITY {
+ // Something changed somewhere, better make sure it matches the type!
+ let op = OpTy { op: Operand::Immediate(src_val), layout: dest.layout };
+ self.validate_operand(op, &mut vec![], None, /*const_mode*/false)?;
+ }
+
// See if we can avoid an allocation. This is the counterpart to `try_read_value`,
// but not factored as a separate function.
let mplace = match dest.place {
self.write_value_to_mplace(src_val, dest)
}
- /// Write a value to memory
+ /// Write a value to memory. This does NOT do validation, so you better had already
+ /// done that before calling this!
fn write_value_to_mplace(
&mut self,
- value: Value,
- dest: MPlaceTy<'tcx>,
+ value: Value<M::PointerTag>,
+ dest: MPlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let (ptr, ptr_align) = dest.to_scalar_ptr_align();
// Note that it is really important that the type here is the right one, and matches the
/// Copy the data from an operand to a place
pub fn copy_op(
&mut self,
- src: OpTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
"Cannot copy unsized data");
};
// Slow path, this does not fit into an immediate. Just memcpy.
trace!("copy_op: {:?} <- {:?}", *dest, *src);
- let (dest_ptr, dest_align) = self.force_allocation(dest)?.to_scalar_ptr_align();
+ let dest = self.force_allocation(dest)?;
+ let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
self.memory.copy(
src_ptr, src_align,
dest_ptr, dest_align,
src.layout.size, false
- )
+ )?;
+ if M::ENFORCE_VALIDITY {
+ // Something changed somewhere, better make sure it matches the type!
+ self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
+ }
+ Ok(())
}
/// Make sure that a place is in memory, and return where it is.
/// This is essentially `force_to_memplace`.
pub fn force_allocation(
&mut self,
- place: PlaceTy<'tcx>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ place: PlaceTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let mplace = match place.place {
Place::Local { frame, local } => {
match *self.stack[frame].locals[local].access()? {
// that has different alignment than the outer field.
let local_layout = self.layout_of_local(frame, local)?;
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
+ // We don't have to validate as we can assume the local
+ // was already valid for its type.
self.write_value_to_mplace(value, ptr)?;
let mplace = ptr.mplace;
// Update the local
&mut self,
layout: TyLayout<'tcx>,
kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
let ptr = self.memory.allocate(layout.size, layout.align, kind)?;
Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
pub fn write_discriminant_index(
&mut self,
variant_index: usize,
- dest: PlaceTy<'tcx>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
match dest.layout.variants {
layout::Variants::Single { index } => {
/// Every place can be read from, so we can turm them into an operand
#[inline(always)]
- pub fn place_to_op(&self, place: PlaceTy<'tcx>) -> EvalResult<'tcx, OpTy<'tcx>> {
+ pub fn place_to_op(
+ &self,
+ place: PlaceTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = match place.place {
Place::Ptr(mplace) => {
Operand::Indirect(mplace)
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
/// Also return some more information so drop doesn't have to run the same code twice.
- pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx>)
- -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx>)> {
+ pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
+ -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
let vtable = mplace.vtable()?; // also sanity checks the type
let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
let layout = self.layout_of(ty)?;
}
let mplace = MPlaceTy {
- mplace: MemPlace { extra: None, ..*mplace },
+ mplace: MemPlace { meta: None, ..*mplace },
layout
};
Ok((instance, mplace))
($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
}
+// This assumes the type has two type parameters, first for the tag (set to `()`),
+// then for the id
macro_rules! impl_snapshot_for {
// FIXME(mark-i-m): Some of these should be `?` rather than `*`.
(enum $enum_name:ident {
impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
where Ctx: self::SnapshotContext<'a>,
{
- type Item = $enum_name<AllocIdSnapshot<'a>>;
+ type Item = $enum_name<(), AllocIdSnapshot<'a>>;
#[inline]
fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
where Ctx: self::SnapshotContext<'a>,
{
- type Item = $struct_name<AllocIdSnapshot<'a>>;
+ type Item = $struct_name<(), AllocIdSnapshot<'a>>;
#[inline]
fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
impl_snapshot_for!(struct Pointer {
alloc_id,
offset -> *offset, // just copy offset verbatim
+ tag -> *tag, // just copy tag
});
impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
where Ctx: SnapshotContext<'a>,
{
- type Item = Scalar<AllocIdSnapshot<'a>>;
+ type Item = Scalar<(), AllocIdSnapshot<'a>>;
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
match self {
impl_stable_hash_for!(struct ::interpret::MemPlace {
ptr,
align,
- extra,
+ meta,
});
impl_snapshot_for!(struct MemPlace {
ptr,
- extra,
+ meta,
align -> *align, // just copy alignment verbatim
});
impl<'a, Ctx> Snapshot<'a, Ctx> for Place
where Ctx: SnapshotContext<'a>,
{
- type Item = Place<AllocIdSnapshot<'a>>;
+ type Item = Place<(), AllocIdSnapshot<'a>>;
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
match self {
impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
where Ctx: SnapshotContext<'a>,
{
- type Item = Relocations<AllocIdSnapshot<'a>>;
+ type Item = Relocations<(), AllocIdSnapshot<'a>>;
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
Relocations::from_presorted(self.iter()
- .map(|(size, id)| (*size, id.snapshot(ctx)))
+ .map(|(size, ((), id))| (*size, ((), id.snapshot(ctx))))
.collect())
}
}
#[derive(Eq, PartialEq)]
struct AllocationSnapshot<'a> {
bytes: &'a [u8],
- relocations: Relocations<AllocIdSnapshot<'a>>,
+ relocations: Relocations<(), AllocIdSnapshot<'a>>,
undef_mask: &'a UndefMask,
align: &'a Align,
mutability: &'a Mutability,
instance: &'a ty::Instance<'tcx>,
span: &'a Span,
return_to_block: &'a StackPopCleanup,
- return_place: Place<AllocIdSnapshot<'a>>,
- locals: IndexVec<mir::Local, LocalValue<AllocIdSnapshot<'a>>>,
+ return_place: Place<(), AllocIdSnapshot<'a>>,
+ locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
block: &'a mir::BasicBlock,
stmt: usize,
}
fn pass_argument(
&mut self,
skip_zst: bool,
- caller_arg: &mut impl Iterator<Item=OpTy<'tcx>>,
- callee_arg: PlaceTy<'tcx>,
+ caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
+ callee_arg: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
if skip_zst && callee_arg.layout.is_zst() {
// Nothing to do.
instance: ty::Instance<'tcx>,
span: Span,
caller_abi: Abi,
- args: &[OpTy<'tcx>],
- dest: Option<PlaceTy<'tcx>>,
+ args: &[OpTy<'tcx, M::PointerTag>],
+ dest: Option<PlaceTy<'tcx, M::PointerTag>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx> {
trace!("eval_fn_call: {:#?}", instance);
let return_place = match dest {
Some(place) => *place,
- None => Place::null(&self),
+ None => Place::null(&self), // any access will error. good!
};
self.push_stack_frame(
instance,
// last incoming argument. These two iterators do not have the same type,
// so to keep the code paths uniform we accept an allocation
// (for RustCall ABI only).
- let caller_args : Cow<[OpTy<'tcx>]> =
+ let caller_args : Cow<[OpTy<'tcx, M::PointerTag>]> =
if caller_abi == Abi::RustCall && !args.is_empty() {
// Untuple
let (&untuple_arg, args) = args.split_last().unwrap();
.chain((0..untuple_arg.layout.fields.count()).into_iter()
.map(|i| self.operand_field(untuple_arg, i as u64))
)
- .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
+ .collect::<EvalResult<Vec<OpTy<'tcx, M::PointerTag>>>>()?)
} else {
// Plain arg passing
Cow::from(args)
trace!("Caller has too many args over");
return err!(FunctionArgCountMismatch);
}
+ // Don't forget to check the return type!
+ if let Some(caller_ret) = dest {
+ let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
+ if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) {
+ return err!(FunctionRetMismatch(
+ caller_ret.layout.ty, callee_ret.layout.ty
+ ));
+ }
+ } else {
+ // FIXME: The caller thinks this function cannot return. How do
+ // we verify that the callee agrees?
+ // On the plus side, the the callee ever writes to its return place,
+ // that will be detected as UB (because we set that to NULL above).
+ }
Ok(())
})();
match res {
fn drop_in_place(
&mut self,
- place: PlaceTy<'tcx>,
+ place: PlaceTy<'tcx, M::PointerTag>,
instance: ty::Instance<'tcx>,
span: Span,
target: mir::BasicBlock,
use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
-use syntax::ast::Mutability;
-
use super::{EvalContext, Machine, MemoryKind};
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
&mut self,
ty: Ty<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
- ) -> EvalResult<'tcx, Pointer> {
+ ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
debug!("get_vtable(trait_ref={:?})", trait_ref);
+ // FIXME: Cache this!
+
let layout = self.layout_of(trait_ref.self_ty())?;
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
let size = layout.size.bytes();
let vtable = self.memory.allocate(
ptr_size * (3 + methods.len() as u64),
ptr_align,
- MemoryKind::Stack,
+ MemoryKind::Vtable,
)?;
let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
}
}
- self.memory.intern_static(
- vtable.alloc_id,
- Mutability::Immutable,
- )?;
+ self.memory.mark_immutable(vtable.alloc_id)?;
Ok(vtable)
}
/// Return the drop fn instance as well as the actual dynamic type
pub fn read_drop_type_from_vtable(
&self,
- vtable: Pointer,
+ vtable: Pointer<M::PointerTag>,
) -> EvalResult<'tcx, (ty::Instance<'tcx>, ty::Ty<'tcx>)> {
// we don't care about the pointee type, we just want a pointer
let pointer_align = self.tcx.data_layout.pointer_align;
pub fn read_size_and_align_from_vtable(
&self,
- vtable: Pointer,
+ vtable: Pointer<M::PointerTag>,
) -> EvalResult<'tcx, (Size, Align)> {
let pointer_size = self.pointer_size();
let pointer_align = self.tcx.data_layout.pointer_align;
// except according to those terms.
use std::fmt::Write;
+use std::hash::Hash;
use syntax_pos::symbol::Symbol;
-use rustc::ty::layout::{self, Size, Primitive};
-use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, Size, Align, TyLayout};
+use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocType, EvalResult, EvalErrorKind, PointerArithmetic
+ Scalar, AllocType, EvalResult, EvalErrorKind
};
use super::{
- OpTy, Machine, EvalContext, ScalarMaybeUndef
+ ValTy, OpTy, MPlaceTy, Machine, EvalContext, ScalarMaybeUndef
};
-macro_rules! validation_failure{
+macro_rules! validation_failure {
($what:expr, $where:expr, $details:expr) => {{
let where_ = path_format($where);
let where_ = if where_.is_empty() {
}};
}
+macro_rules! try_validation {
+ ($e:expr, $what:expr, $where:expr, $details:expr) => {{
+ match $e {
+ Ok(x) => x,
+ Err(_) => return validation_failure!($what, $where, $details),
+ }
+ }};
+
+ ($e:expr, $what:expr, $where:expr) => {{
+ match $e {
+ Ok(x) => x,
+ Err(_) => return validation_failure!($what, $where),
+ }
+ }}
+}
+
/// We want to show a nice path to the invalid field for diagnotsics,
/// but avoid string operations in the happy case where no error happens.
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
Tag,
}
+/// State for tracking recursive validation of references
+pub struct RefTracking<'tcx, Tag> {
+ pub seen: FxHashSet<(OpTy<'tcx, Tag>)>,
+ pub todo: Vec<(OpTy<'tcx, Tag>, Vec<PathElem>)>,
+}
+
+impl<'tcx, Tag: Copy+Eq+Hash> RefTracking<'tcx, Tag> {
+ pub fn new(op: OpTy<'tcx, Tag>) -> Self {
+ let mut ref_tracking = RefTracking {
+ seen: FxHashSet(),
+ todo: vec![(op, Vec::new())],
+ };
+ ref_tracking.seen.insert(op);
+ ref_tracking
+ }
+}
+
// Adding a Deref and making a copy of the path to be put into the queue
// always go together. This one does it with only new allocation.
fn path_clone_and_deref(path: &Vec<PathElem>) -> Vec<PathElem> {
out
}
+fn scalar_format<Tag>(value: ScalarMaybeUndef<Tag>) -> String {
+ match value {
+ ScalarMaybeUndef::Undef =>
+ "uninitialized bytes".to_owned(),
+ ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) =>
+ "a pointer".to_owned(),
+ ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. }) =>
+ bits.to_string(),
+ }
+}
+
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
- fn validate_scalar(
+ /// Make sure that `value` is valid for `ty`, *assuming* `ty` is a primitive type.
+ fn validate_primitive_type(
&self,
- value: ScalarMaybeUndef,
- size: Size,
- scalar: &layout::Scalar,
+ value: ValTy<'tcx, M::PointerTag>,
path: &Vec<PathElem>,
- ty: Ty,
+ ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,
+ const_mode: bool,
) -> EvalResult<'tcx> {
- trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
- let (lo, hi) = scalar.valid_range.clone().into_inner();
-
- let value = match value {
- ScalarMaybeUndef::Scalar(scalar) => scalar,
- ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
- };
-
- let bits = match value {
- Scalar::Bits { bits, size: value_size } => {
- assert_eq!(value_size as u64, size.bytes());
- bits
+ // Go over all the primitive types
+ let ty = value.layout.ty;
+ match ty.sty {
+ ty::Bool => {
+ let value = value.to_scalar_or_undef();
+ try_validation!(value.to_bool(),
+ scalar_format(value), path, "a boolean");
},
- Scalar::Ptr(_) => {
- match ty.sty {
- ty::Bool |
- ty::Char |
- ty::Float(_) |
- ty::Int(_) |
- ty::Uint(_) => {
- return validation_failure!(
- "a pointer",
- path,
- format!("the type {}", ty.sty)
- );
+ ty::Char => {
+ let value = value.to_scalar_or_undef();
+ try_validation!(value.to_char(),
+ scalar_format(value), path, "a valid unicode codepoint");
+ },
+ ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
+ let size = value.layout.size;
+ let value = value.to_scalar_or_undef();
+ if const_mode {
+ // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
+ try_validation!(value.to_bits(size),
+ scalar_format(value), path, "initialized plain bits");
+ } else {
+ // At run-time, for now, we accept *anything* for these types, including
+ // undef. We should fix that, but let's start low.
+ }
+ }
+ _ if ty.is_box() || ty.is_region_ptr() || ty.is_unsafe_ptr() => {
+ // Handle fat pointers. We also check fat raw pointers,
+ // their metadata must be valid!
+ // This also checks that the ptr itself is initialized, which
+ // seems reasonable even for raw pointers.
+ let place = try_validation!(self.ref_to_mplace(value),
+ "undefined data in pointer", path);
+ // Check metadata early, for better diagnostics
+ if place.layout.is_unsized() {
+ let tail = self.tcx.struct_tail(place.layout.ty);
+ match tail.sty {
+ ty::Dynamic(..) => {
+ let vtable = try_validation!(place.meta.unwrap().to_ptr(),
+ "non-pointer vtable in fat pointer", path);
+ try_validation!(self.read_drop_type_from_vtable(vtable),
+ "invalid drop fn in vtable", path);
+ try_validation!(self.read_size_and_align_from_vtable(vtable),
+ "invalid size or align in vtable", path);
+ // FIXME: More checks for the vtable.
+ }
+ ty::Slice(..) | ty::Str => {
+ try_validation!(place.meta.unwrap().to_usize(self),
+ "non-integer slice length in fat pointer", path);
+ }
+ ty::Foreign(..) => {
+ // Unsized, but not fat.
+ }
+ _ =>
+ bug!("Unexpected unsized type tail: {:?}", tail),
}
- ty::RawPtr(_) |
- ty::Ref(_, _, _) |
- ty::FnPtr(_) => {}
- _ => { unreachable!(); }
}
+ // for safe ptrs, also check the ptr values itself
+ if !ty.is_unsafe_ptr() {
+ // Make sure this is non-NULL and aligned
+ let (size, align) = self.size_and_align_of(place.meta, place.layout)?;
+ match self.memory.check_align(place.ptr, align) {
+ Ok(_) => {},
+ Err(err) => match err.kind {
+ EvalErrorKind::InvalidNullPointerUsage =>
+ return validation_failure!("NULL reference", path),
+ EvalErrorKind::AlignmentCheckFailed { .. } =>
+ return validation_failure!("unaligned reference", path),
+ _ =>
+ return validation_failure!(
+ "dangling (deallocated) reference", path
+ ),
+ }
+ }
+ // non-ZST also have to be dereferencable
+ if size != Size::ZERO {
+ let ptr = try_validation!(place.ptr.to_ptr(),
+ "integer pointer in non-ZST reference", path);
+ if const_mode {
+ // Skip validation entirely for some external statics
+ let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
+ if let Some(AllocType::Static(did)) = alloc_kind {
+ // `extern static` cannot be validated as they have no body.
+ // FIXME: Statics from other crates are also skipped.
+ // They might be checked at a different type, but for now we
+ // want to avoid recursing too deeply. This is not sound!
+ if !did.is_local() || self.tcx.is_foreign_item(did) {
+ return Ok(());
+ }
+ }
+ }
+ try_validation!(self.memory.check_bounds(ptr, size, false),
+ "dangling (not entirely in bounds) reference", path);
+ }
+ if let Some(ref_tracking) = ref_tracking {
+ // Check if we have encountered this pointer+layout combination
+ // before. Proceed recursively even for integer pointers, no
+ // reason to skip them! They are (recursively) valid for some ZST,
+ // but not for others (e.g. `!` is a ZST).
+ let op = place.into();
+ if ref_tracking.seen.insert(op) {
+ trace!("Recursing below ptr {:#?}", *op);
+ ref_tracking.todo.push((op, path_clone_and_deref(path)));
+ }
+ }
+ }
+ }
+ ty::FnPtr(_sig) => {
+ let value = value.to_scalar_or_undef();
+ let ptr = try_validation!(value.to_ptr(),
+ scalar_format(value), path, "a pointer");
+ let _fn = try_validation!(self.memory.get_fn(ptr),
+ scalar_format(value), path, "a function pointer");
+ // FIXME: Check if the signature matches
+ }
+ // This should be all the primitive types
+ ty::Never => bug!("Uninhabited type should have been catched earlier"),
+ _ => bug!("Unexpected primitive type {}", value.layout.ty)
+ }
+ Ok(())
+ }
- let ptr_size = self.pointer_size();
- let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
- return if lo > hi {
- if lo - hi == 1 {
- // no gap, all values are ok
- Ok(())
- } else if hi < ptr_max || lo > 1 {
- let max = u128::max_value() >> (128 - size.bits());
- validation_failure!(
- "pointer",
- path,
- format!("something in the range {:?} or {:?}", 0..=lo, hi..=max)
- )
- } else {
- Ok(())
+ /// Make sure that `value` matches the
+ fn validate_scalar_layout(
+ &self,
+ value: ScalarMaybeUndef<M::PointerTag>,
+ size: Size,
+ path: &Vec<PathElem>,
+ layout: &layout::Scalar,
+ ) -> EvalResult<'tcx> {
+ let (lo, hi) = layout.valid_range.clone().into_inner();
+ let max_hi = u128::max_value() >> (128 - size.bits()); // as big as the size fits
+ assert!(hi <= max_hi);
+ if lo == 0 && hi == max_hi {
+ // Nothing to check
+ return Ok(());
+ }
+ // At least one value is excluded. Get the bits.
+ let value = try_validation!(value.not_undef(),
+ scalar_format(value), path, format!("something in the range {:?}", layout.valid_range));
+ let bits = match value {
+ Scalar::Ptr(ptr) => {
+ if lo == 1 && hi == max_hi {
+ // only NULL is not allowed.
+ // We can call `check_align` to check non-NULL-ness, but have to also look
+ // for function pointers.
+ let non_null =
+ self.memory.check_align(
+ Scalar::Ptr(ptr), Align::from_bytes(1, 1).unwrap()
+ ).is_ok() ||
+ self.memory.get_fn(ptr).is_ok();
+ if !non_null {
+ // could be NULL
+ return validation_failure!("a potentially NULL pointer", path);
}
- } else if hi < ptr_max || lo > 1 {
- validation_failure!(
- "pointer",
- path,
- format!("something in the range {:?}", scalar.valid_range)
- )
+ return Ok(());
} else {
- Ok(())
- };
- },
- };
-
- // char gets a special treatment, because its number space is not contiguous so `TyLayout`
- // has no special checks for chars
- match ty.sty {
- ty::Char => {
- debug_assert_eq!(size.bytes(), 4);
- if ::std::char::from_u32(bits as u32).is_none() {
+ // Conservatively, we reject, because the pointer *could* have this
+ // value.
return validation_failure!(
- "character",
+ "a pointer",
path,
- "a valid unicode codepoint"
+ format!(
+ "something that cannot possibly be outside the (wrapping) range {:?}",
+ layout.valid_range
+ )
);
}
}
- _ => {},
- }
-
+ Scalar::Bits { bits, size: value_size } => {
+ assert_eq!(value_size as u64, size.bytes());
+ bits
+ }
+ };
+ // Now compare. This is slightly subtle because this is a special "wrap-around" range.
use std::ops::RangeInclusive;
let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
if lo > hi {
- if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
+ // wrapping around
+ if in_range(0..=hi) || in_range(lo..=max_hi) {
Ok(())
} else {
validation_failure!(
bits,
path,
- format!("something in the range {:?} or {:?}", ..=hi, lo..)
+ format!("something in the range {:?} or {:?}", 0..=hi, lo..=max_hi)
)
}
} else {
- if in_range(scalar.valid_range.clone()) {
+ if in_range(layout.valid_range.clone()) {
Ok(())
} else {
validation_failure!(
bits,
path,
- format!("something in the range {:?}", scalar.valid_range)
+ if hi == max_hi {
+ format!("something greater or equal to {}", lo)
+ } else {
+ format!("something in the range {:?}", layout.valid_range)
+ }
)
}
}
}
- /// This function checks the data at `op`.
+ /// This function checks the data at `op`. `op` is assumed to cover valid memory if it
+ /// is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
/// The `path` may be pushed to, but the part that is present when the function
/// starts must not be changed!
+ ///
+ /// `ref_tracking` can be None to avoid recursive checking below references.
+ /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion)
+ /// validation (e.g., pointer values are fine in integers at runtime).
pub fn validate_operand(
&self,
- dest: OpTy<'tcx>,
+ dest: OpTy<'tcx, M::PointerTag>,
path: &mut Vec<PathElem>,
- seen: &mut FxHashSet<(OpTy<'tcx>)>,
- todo: &mut Vec<(OpTy<'tcx>, Vec<PathElem>)>,
+ mut ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,
+ const_mode: bool,
) -> EvalResult<'tcx> {
- trace!("validate_operand: {:?}, {:#?}", *dest, dest.layout);
+ trace!("validate_operand: {:?}, {:?}", *dest, dest.layout.ty);
- // Find the right variant. We have to handle this as a prelude, not via
- // proper recursion with the new inner layout, to be able to later nicely
- // print the field names of the enum field that is being accessed.
- let (variant, dest) = match dest.layout.variants {
+ // If this is a multi-variant layout, we have find the right one and proceed with that.
+ // (No good reasoning to make this recursion, but it is equivalent to that.)
+ let dest = match dest.layout.variants {
layout::Variants::NicheFilling { .. } |
layout::Variants::Tagged { .. } => {
let variant = match self.read_discriminant(dest) {
),
}
};
- let inner_dest = self.operand_downcast(dest, variant)?;
// Put the variant projection onto the path, as a field
path.push(PathElem::Field(dest.layout.ty
.ty_adt_def()
.unwrap()
.variants[variant].name));
+ // Proceed with this variant
+ let dest = self.operand_downcast(dest, variant)?;
trace!("variant layout: {:#?}", dest.layout);
- (variant, inner_dest)
+ dest
},
- layout::Variants::Single { index } => {
- // Pre-processing for trait objects: Treat them at their real type.
- // (We do not do this for slices and strings: For slices it is not needed,
- // `mplace_array_fields` does the right thing, and for strings there is no
- // real type that would show the actual length.)
- let dest = match dest.layout.ty.sty {
- ty::Dynamic(..) => {
- let dest = dest.to_mem_place(); // immediate trait objects are not a thing
- match self.unpack_dyn_trait(dest) {
- Ok(res) => res.1.into(),
- Err(_) =>
- return validation_failure!(
- "invalid vtable in fat pointer", path
- ),
- }
- }
- _ => dest
- };
- (index, dest)
- }
+ layout::Variants::Single { .. } => dest,
};
- // Remember the length, in case we need to truncate
- let path_len = path.len();
+ // First thing, find the real type:
+ // If it is a trait object, switch to the actual type that was used to create it.
+ let dest = match dest.layout.ty.sty {
+ ty::Dynamic(..) => {
+ let dest = dest.to_mem_place(); // immediate trait objects are not a thing
+ self.unpack_dyn_trait(dest)?.1.into()
+ },
+ _ => dest
+ };
- // Validate all fields
- match dest.layout.fields {
- // primitives are unions with zero fields
- // We still check `layout.fields`, not `layout.abi`, because `layout.abi`
- // is `Scalar` for newtypes around scalars, but we want to descend through the
- // fields to get a proper `path`.
- layout::FieldPlacement::Union(0) => {
- match dest.layout.abi {
- // nothing to do, whatever the pointer points to, it is never going to be read
- layout::Abi::Uninhabited =>
- return validation_failure!("a value of an uninhabited type", path),
- // check that the scalar is a valid pointer or that its bit range matches the
- // expectation.
- layout::Abi::Scalar(ref scalar_layout) => {
- let size = scalar_layout.value.size(self);
- let value = match self.read_value(dest) {
- Ok(val) => val,
- Err(err) => match err.kind {
- EvalErrorKind::PointerOutOfBounds { .. } |
- EvalErrorKind::ReadUndefBytes(_) =>
- return validation_failure!(
- "uninitialized or out-of-bounds memory", path
- ),
- _ =>
- return validation_failure!(
- "unrepresentable data", path
- ),
- }
- };
- let scalar = value.to_scalar_or_undef();
- self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
- if scalar_layout.value == Primitive::Pointer {
- // ignore integer pointers, we can't reason about the final hardware
- if let Scalar::Ptr(ptr) = scalar.not_undef()? {
- let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
- if let Some(AllocType::Static(did)) = alloc_kind {
- // statics from other crates are already checked.
- // extern statics cannot be validated as they have no body.
- if !did.is_local() || self.tcx.is_foreign_item(did) {
- return Ok(());
- }
- }
- if value.layout.ty.builtin_deref(false).is_some() {
- let ptr_op = self.ref_to_mplace(value)?.into();
- // we have not encountered this pointer+layout combination
- // before.
- if seen.insert(ptr_op) {
- trace!("Recursing below ptr {:#?}", *value);
- todo.push((ptr_op, path_clone_and_deref(path)));
- }
- }
- }
- }
- },
- _ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", dest.layout.abi),
- }
+ // If this is a scalar, validate the scalar layout.
+ // Things can be aggregates and have scalar layout at the same time, and that
+ // is very relevant for `NonNull` and similar structs: We need to validate them
+ // at their scalar layout *before* descending into their fields.
+ // FIXME: We could avoid some redundant checks here. For newtypes wrapping
+ // scalars, we do the same check on every "level" (e.g. first we check
+ // MyNewtype and then the scalar in there).
+ match dest.layout.abi {
+ layout::Abi::Uninhabited =>
+ return validation_failure!("a value of an uninhabited type", path),
+ layout::Abi::Scalar(ref layout) => {
+ let value = try_validation!(self.read_scalar(dest),
+ "uninitialized or unrepresentable data", path);
+ self.validate_scalar_layout(value, dest.layout.size, &path, layout)?;
}
- layout::FieldPlacement::Union(_) => {
+ // FIXME: Should we do something for ScalarPair? Vector?
+ _ => {}
+ }
+
+ // Check primitive types. We do this after checking the scalar layout,
+ // just to have that done as well. Primitives can have varying layout,
+ // so we check them separately and before aggregate handling.
+ // It is CRITICAL that we get this check right, or we might be
+ // validating the wrong thing!
+ let primitive = match dest.layout.fields {
+ // Primitives appear as Union with 0 fields -- except for fat pointers.
+ layout::FieldPlacement::Union(0) => true,
+ _ => dest.layout.ty.builtin_deref(true).is_some(),
+ };
+ if primitive {
+ let value = try_validation!(self.read_value(dest),
+ "uninitialized or unrepresentable data", path);
+ return self.validate_primitive_type(
+ value,
+ &path,
+ ref_tracking,
+ const_mode,
+ );
+ }
+
+ // Validate all fields of compound data structures
+ let path_len = path.len(); // Remember the length, in case we need to truncate
+ match dest.layout.fields {
+ layout::FieldPlacement::Union(..) => {
// We can't check unions, their bits are allowed to be anything.
// The fields don't need to correspond to any bit pattern of the union's fields.
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
},
- layout::FieldPlacement::Array { stride, .. } if !dest.layout.is_zst() => {
- let dest = dest.to_mem_place(); // non-ZST array/slice/str cannot be immediate
+ layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
+ // Go look at all the fields
+ for i in 0..offsets.len() {
+ let field = self.operand_field(dest, i as u64)?;
+ path.push(self.aggregate_field_path_elem(dest.layout, i));
+ self.validate_operand(
+ field,
+ path,
+ ref_tracking.as_mut().map(|r| &mut **r),
+ const_mode,
+ )?;
+ path.truncate(path_len);
+ }
+ }
+ layout::FieldPlacement::Array { stride, .. } => {
+ let dest = if dest.layout.is_zst() {
+ // it's a ZST, the memory content cannot matter
+ MPlaceTy::dangling(dest.layout, self)
+ } else {
+ // non-ZST array/slice/str cannot be immediate
+ dest.to_mem_place()
+ };
match dest.layout.ty.sty {
// Special handling for strings to verify UTF-8
ty::Str => {
- match self.read_str(dest) {
- Ok(_) => {},
- Err(err) => match err.kind {
- EvalErrorKind::PointerOutOfBounds { .. } |
- EvalErrorKind::ReadUndefBytes(_) =>
- // The error here looks slightly different than it does
- // for slices, because we do not report the index into the
- // str at which we are OOB.
- return validation_failure!(
- "uninitialized or out-of-bounds memory", path
- ),
- _ =>
- return validation_failure!(
- "non-UTF-8 data in str", path
- ),
- }
- }
+ try_validation!(self.read_str(dest),
+ "uninitialized or non-UTF-8 data in str", path);
}
// Special handling for arrays/slices of builtin integer types
ty::Array(tys, ..) | ty::Slice(tys) if {
"undefined bytes", path
)
},
- EvalErrorKind::PointerOutOfBounds { allocation_size, .. } => {
- // If the array access is out-of-bounds, the first
- // undefined access is the after the end of the array.
- let i = (allocation_size.bytes() * ty_size) as usize;
- path.push(PathElem::ArrayElem(i));
- },
- _ => (),
+ // Other errors shouldn't be possible
+ _ => return Err(err),
}
-
- return validation_failure!(
- "uninitialized or out-of-bounds memory", path
- )
}
}
},
for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
let field = field?;
path.push(PathElem::ArrayElem(i));
- self.validate_operand(field.into(), path, seen, todo)?;
+ self.validate_operand(
+ field.into(),
+ path,
+ ref_tracking.as_mut().map(|r| &mut **r),
+ const_mode,
+ )?;
path.truncate(path_len);
}
}
}
},
- layout::FieldPlacement::Array { .. } => {
- // An empty array. Nothing to do.
- }
- layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
- // Fat pointers are treated like pointers, not aggregates.
- if dest.layout.ty.builtin_deref(true).is_some() {
- // This is a fat pointer.
- let ptr = match self.read_value(dest.into())
- .and_then(|val| self.ref_to_mplace(val))
- {
- Ok(ptr) => ptr,
- Err(_) =>
- return validation_failure!(
- "undefined location or metadata in fat pointer", path
- ),
- };
- // check metadata early, for better diagnostics
- match self.tcx.struct_tail(ptr.layout.ty).sty {
- ty::Dynamic(..) => {
- match ptr.extra.unwrap().to_ptr() {
- Ok(_) => {},
- Err(_) =>
- return validation_failure!(
- "non-pointer vtable in fat pointer", path
- ),
- }
- // FIXME: More checks for the vtable.
- }
- ty::Slice(..) | ty::Str => {
- match ptr.extra.unwrap().to_usize(self) {
- Ok(_) => {},
- Err(_) =>
- return validation_failure!(
- "non-integer slice length in fat pointer", path
- ),
- }
- }
- _ =>
- bug!("Unexpected unsized type tail: {:?}",
- self.tcx.struct_tail(ptr.layout.ty)
- ),
- }
- // for safe ptrs, recursively check it
- if !dest.layout.ty.is_unsafe_ptr() {
- let ptr = ptr.into();
- if seen.insert(ptr) {
- trace!("Recursing below fat ptr {:?}", ptr);
- todo.push((ptr, path_clone_and_deref(path)));
- }
- }
- } else {
- // Not a pointer, perform regular aggregate handling below
- for i in 0..offsets.len() {
- let field = self.operand_field(dest, i as u64)?;
- path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
- self.validate_operand(field, path, seen, todo)?;
- path.truncate(path_len);
- }
- }
- }
}
Ok(())
}
- fn aggregate_field_path_elem(&self, ty: Ty<'tcx>, variant: usize, field: usize) -> PathElem {
- match ty.sty {
+ fn aggregate_field_path_elem(&self, layout: TyLayout<'tcx>, field: usize) -> PathElem {
+ match layout.ty.sty {
// generators and closures.
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
- let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
- let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
- PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
+ if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+ let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
+ PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
+ } else {
+ // The closure is not local, so we cannot get the name
+ PathElem::ClosureVar(Symbol::intern(&field.to_string()))
+ }
}
// tuples
// enums
ty::Adt(def, ..) if def.is_enum() => {
- let variant = &def.variants[variant];
+ let variant = match layout.variants {
+ layout::Variants::Single { index } => &def.variants[index],
+ _ => bug!("aggregate_field_path_elem: got enum but not in a specific variant"),
+ };
PathElem::Field(variant.fields[field].ident.name)
}
ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),
// nothing else has an aggregate layout
- _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", ty),
+ _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty),
}
}
}
}
Some(AllocType::Memory(alloc)) => {
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
- for &inner in alloc.relocations.values() {
+ for &((), inner) in alloc.relocations.values() {
collect_miri(tcx, inner, output);
}
},
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
ConstValue::ByRef(_id, alloc, _offset) => {
- for &id in alloc.relocations.values() {
+ for &((), id) in alloc.relocations.values() {
collect_miri(tcx, id, output);
}
}
// FIXME: figure out the rules and start linting
| FunctionAbiMismatch(..)
| FunctionArgMismatch(..)
+ | FunctionRetMismatch(..)
| FunctionArgCountMismatch
// fine at runtime, might be a register address or sth
| ReadBytesAsPointer
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
-#![feature(min_const_fn)]
+#![cfg_attr(stage0, feature(min_const_fn))]
#![feature(nll)]
#![feature(slice_patterns)]
/// 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>) {
}
/// Creates the relevant generic argument substitutions
- /// corresponding to a set of generic parameters.
- pub fn create_substs_for_generic_args<'a, 'b, A, P, I>(
+ /// corresponding to a set of generic parameters. This is a
+ /// rather complex little function. Let me try to explain the
+ /// role of each of its parameters:
+ ///
+ /// To start, we are given the `def_id` of the thing we are
+ /// creating the substitutions for, and a partial set of
+ /// substitutions `parent_substs`. In general, the substitutions
+ /// for an item begin with substitutions for all the "parents" of
+ /// that item -- so e.g. for a method it might include the
+ /// parameters from the impl.
+ ///
+ /// Therefore, the method begins by walking down these parents,
+ /// starting with the outermost parent and proceed inwards until
+ /// it reaches `def_id`. For each parent P, it will check `parent_substs`
+ /// first to see if the parent's substitutions are listed in there. If so,
+ /// we can append those and move on. Otherwise, it invokes the
+ /// three callback functions:
+ ///
+ /// - `args_for_def_id`: given the def-id P, supplies back the
+ /// generic arguments that were given to that parent from within
+ /// the path; so e.g. if you have `<T as Foo>::Bar`, the def-id
+ /// might refer to the trait `Foo`, and the arguments might be
+ /// `[T]`. The boolean value indicates whether to infer values
+ /// for arguments whose values were not explicitly provided.
+ /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
+ /// instantiate a `Kind`
+ /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
+ /// creates a suitable inference variable.
+ pub fn create_substs_for_generic_args<'a, 'b>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
def_id: DefId,
parent_substs: &[Kind<'tcx>],
has_self: bool,
self_ty: Option<Ty<'tcx>>,
- args_for_def_id: A,
- provided_kind: P,
- inferred_kind: I,
- ) -> &'tcx Substs<'tcx> where
- A: Fn(DefId) -> (Option<&'b GenericArgs>, bool),
- P: Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
- I: Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>
- {
+ args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs>, bool),
+ provided_kind: impl Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
+ inferred_kind: impl Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>,
+ ) -> &'tcx Substs<'tcx> {
// Collect the segments of the path: we need to substitute arguments
// for parameters throughout the entire path (wherever there are
// generic parameters).
};
if self.can_coerce(ref_ty, expected) {
if let Ok(src) = cm.span_to_snippet(sp) {
- let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756)
+ let needs_parens = match expr.node {
+ // parenthesize if needed (Issue #46756)
hir::ExprKind::Cast(_, _) |
- hir::ExprKind::Binary(_, _, _) => format!("({})", src),
- _ => src,
+ hir::ExprKind::Binary(_, _, _) => true,
+ // parenthesize borrows of range literals (Issue #54505)
+ _ if self.is_range_literal(expr) => true,
+ _ => false,
};
+ let sugg_expr = if needs_parens {
+ format!("({})", src)
+ } else {
+ src
+ };
+
if let Some(sugg) = self.can_use_as_ref(expr) {
return Some(sugg);
}
None
}
+ /// This function checks if the specified expression is a built-in range literal.
+ /// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`).
+ fn is_range_literal(&self, expr: &hir::Expr) -> bool {
+ use hir::{Path, QPath, ExprKind, TyKind};
+
+ // We support `::std::ops::Range` and `::core::ops::Range` prefixes
+ let is_range_path = |path: &Path| {
+ let mut segs = path.segments.iter()
+ .map(|seg| seg.ident.as_str());
+
+ if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
+ (segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
+ {
+ // "{{root}}" is the equivalent of `::` prefix in Path
+ root == "{{root}}" && (std_core == "std" || std_core == "core")
+ && ops == "ops" && range.starts_with("Range")
+ } else {
+ false
+ }
+ };
+
+ let span_is_range_literal = |span: &Span| {
+ // Check whether a span corresponding to a range expression
+ // is a range literal, rather than an explicit struct or `new()` call.
+ let source_map = self.tcx.sess.source_map();
+ let end_point = source_map.end_point(*span);
+
+ if let Ok(end_string) = source_map.span_to_snippet(end_point) {
+ !(end_string.ends_with("}") || end_string.ends_with(")"))
+ } else {
+ false
+ }
+ };
+
+ match expr.node {
+ // All built-in range literals but `..=` and `..` desugar to Structs
+ ExprKind::Struct(QPath::Resolved(None, ref path), _, _) |
+ // `..` desugars to its struct path
+ ExprKind::Path(QPath::Resolved(None, ref path)) => {
+ return is_range_path(&path) && span_is_range_literal(&expr.span);
+ }
+
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`
+ ExprKind::Call(ref func, _) => {
+ if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
+ if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
+ let call_to_new = segment.ident.as_str() == "new";
+
+ return is_range_path(&path) && span_is_range_literal(&expr.span)
+ && call_to_new;
+ }
+ }
+ }
+
+ _ => {}
+ }
+
+ false
+ }
+
pub fn check_for_cast(&self,
err: &mut DiagnosticBuilder<'tcx>,
expr: &hir::Expr,
/// occurred**, so that annotations like `Vec<_>` are preserved
/// properly.
pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
+ debug!(
+ "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
+ hir_id,
+ substs,
+ self.tag(),
+ );
+
if !substs.is_noop() {
let user_substs = self.infcx.canonicalize_response(&substs);
debug!("instantiate_value_path: user_substs = {:?}", user_substs);
expected: Expectation<'tcx>,
needs: Needs
) -> Ty<'tcx> {
+ debug!(
+ "check_expr_kind(expr={:?}, expected={:?}, needs={:?})",
+ expr,
+ expected,
+ needs,
+ );
+
let tcx = self.tcx;
let id = expr.id;
match expr.node {
span: Span,
node_id: ast::NodeId)
-> (Ty<'tcx>, Def) {
- debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
- segments,
- def,
- node_id);
+ debug!(
+ "instantiate_value_path(segments={:?}, self_ty={:?}, def={:?}, node_id={})",
+ segments,
+ self_ty,
+ def,
+ node_id,
+ );
let path_segs = self.def_ids_for_path_segments(segments, def);
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
self.write_substs(hir_id, substs);
+ debug!(
+ "instantiate_value_path: id={:?} substs={:?}",
+ node_id,
+ substs,
+ );
self.write_user_substs_from_substs(hir_id, substs);
(ty_substituted, new_def)
[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;
/// the heap (for normal construction via Error::new) is too costly.
#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
impl From<ErrorKind> for Error {
+ /// Converts an [`ErrorKind`] into an [`Error`].
+ ///
+ /// This conversion allocates a new error with a simple representation of error kind.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// let not_found = ErrorKind::NotFound;
+ /// let error = Error::from(not_found);
+ /// assert_eq!("entity not found", format!("{}", error));
+ /// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
Error {
#![feature(cfg_target_vendor)]
#![feature(char_error_internals)]
#![feature(compiler_builtins_lib)]
-#![feature(min_const_fn)]
+#![cfg_attr(stage0, feature(min_const_fn))]
#![feature(const_int_ops)]
#![feature(const_ip)]
#![feature(const_raw_ptr_deref)]
/// `&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`]
/// Thus the pattern of `yield`ing after a failed poll is rather common when
/// implementing low-level shared resources or synchronization primitives.
///
-/// However programmers will usually prefer to use, [`channel`]s, [`Condvar`]s,
+/// However programmers will usually prefer to use [`channel`]s, [`Condvar`]s,
/// [`Mutex`]es or [`join`] for their synchronization routines, as they avoid
/// thinking about thread scheduling.
///
pub level: StabilityLevel,
pub feature: Symbol,
pub rustc_depr: Option<RustcDeprecation>,
- /// `None` means the function is stable but needs to be allowed by the
- /// `min_const_fn` feature
+ /// `None` means the function is stable but needs to be a stable const fn, too
/// `Some` contains the feature gate required to be able to use the function
/// as const fn
pub const_stability: Option<Symbol>,
// 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() {
use std::{env};
macro_rules! set {
- // The const_fn feature also enables the min_const_fn feature, because `min_const_fn` allows
- // the declaration `const fn`, but the `const_fn` feature gate enables things inside those
- // functions that we do not want to expose to the user for now.
- (const_fn) => {{
- fn f(features: &mut Features, _: Span) {
- features.const_fn = true;
- features.min_const_fn = true;
- }
- f as fn(&mut Features, Span)
- }};
($field: ident) => {{
fn f(features: &mut Features, _: Span) {
features.$field = true;
// Allows the definition of `const fn` functions with some advanced features.
(active, const_fn, "1.2.0", Some(24111), None),
- // Allows the definition of `const fn` functions.
- (active, min_const_fn, "1.30.0", Some(53555), None),
-
// Allows let bindings and destructuring in `const fn` functions and constants.
(active, const_let, "1.22.1", Some(48821), None),
// #[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, extern_prelude, "1.30.0", Some(44660), None),
// Parentheses in patterns
(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
if header.asyncness.is_async() {
gate_feature_post!(&self, async_await, span, "async fn is unstable");
}
- if header.constness.node == ast::Constness::Const {
- gate_feature_post!(&self, min_const_fn, span, "const fn is unstable");
- }
// stability of const fn methods are covered in
// visit_trait_item and visit_impl_item below; this is
// because default methods don't pass through this
}
match ii.node {
- ast::ImplItemKind::Method(ref sig, _) => {
- if sig.header.constness.node == ast::Constness::Const {
- gate_feature_post!(&self, min_const_fn, ii.span, "const fn is unstable");
- }
- }
+ ast::ImplItemKind::Method(..) => {}
ast::ImplItemKind::Existential(..) => {
gate_feature_post!(
&self,
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;
// NB: We do not expect *any* monomorphization to be generated here.
-#![feature(min_const_fn)]
#![deny(dead_code)]
#![crate_type = "rlib"]
// compile-flags:-Clink-dead-code
-#![feature(min_const_fn)]
#![crate_type = "rlib"]
// This test makes sure that, when -Clink-dead-code is specified, we generate
#![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"
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
#![feature(cfg_target_thread_local, thread_local_internals)]
// On platforms *without* `#[thread_local]`, use
// lldb-command:run
// lldb-command:print arg
-// lldb-check:[...]$0 = Struct<i32> { b: -1, b1: 0 }
+// lldbg-check:[...]$0 = Struct<i32> { b: -1, b1: 0 }
+// lldbr-check:(associated_types::Struct<i32>) arg = Struct<i32> { b: -1, b1: 0 }
// lldb-command:continue
// lldb-command:print inferred
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i64) inferred = 1
// lldb-command:print explicitly
-// lldb-check:[...]$2 = 1
+// lldbg-check:[...]$2 = 1
+// lldbr-check:(i64) explicitly = 1
// lldb-command:continue
// lldb-command:print arg
-// lldb-check:[...]$3 = 2
+// lldbg-check:[...]$3 = 2
+// lldbr-check:(i64) arg = 2
// lldb-command:continue
// lldb-command:print arg
-// lldb-check:[...]$4 = (4, 5)
+// lldbg-check:[...]$4 = (4, 5)
+// lldbr-check:((i32, i64)) arg = { = 4 = 5 }
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$5 = 6
+// lldbg-check:[...]$5 = 6
+// lldbr-check:(i32) a = 6
// lldb-command:print b
-// lldb-check:[...]$6 = 7
+// lldbg-check:[...]$6 = 7
+// lldbr-check:(i64) b = 7
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$7 = 8
+// lldbg-check:[...]$7 = 8
+// lldbr-check:(i64) a = 8
// lldb-command:print b
-// lldb-check:[...]$8 = 9
+// lldbg-check:[...]$8 = 9
+// lldbr-check:(i32) b = 9
// lldb-command:continue
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print b
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) b = false
// lldb-command:print i
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) i = -1
-// NOTE: LLDB does not support 32bit chars
-// d ebugger:print (usize)(c)
-// c heck:$3 = 97
+// NOTE: only rust-enabled lldb supports 32bit chars
+// lldbr-command:print c
+// lldbr-check:(char) c = 'a'
// lldb-command:print i8
-// lldb-check:[...]$2 = 'D'
+// lldbg-check:[...]$2 = 'D'
+// lldbr-check:(i8) i8 = 68
// lldb-command:print i16
-// lldb-check:[...]$3 = -16
+// lldbg-check:[...]$3 = -16
+// lldbr-check:(i16) i16 = -16
// lldb-command:print i32
-// lldb-check:[...]$4 = -32
+// lldbg-check:[...]$4 = -32
+// lldbr-check:(i32) i32 = -32
// lldb-command:print i64
-// lldb-check:[...]$5 = -64
+// lldbg-check:[...]$5 = -64
+// lldbr-check:(i64) i64 = -64
// lldb-command:print u
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(usize) u = 1
// lldb-command:print u8
-// lldb-check:[...]$7 = 'd'
+// lldbg-check:[...]$7 = 'd'
+// lldbr-check:(u8) u8 = 100
// lldb-command:print u16
-// lldb-check:[...]$8 = 16
+// lldbg-check:[...]$8 = 16
+// lldbr-check:(u16) u16 = 16
// lldb-command:print u32
-// lldb-check:[...]$9 = 32
+// lldbg-check:[...]$9 = 32
+// lldbr-check:(u32) u32 = 32
// lldb-command:print u64
-// lldb-check:[...]$10 = 64
+// lldbg-check:[...]$10 = 64
+// lldbr-check:(u64) u64 = 64
// lldb-command:print f32
-// lldb-check:[...]$11 = 2.5
+// lldbg-check:[...]$11 = 2.5
+// lldbr-check:(f32) f32 = 2.5
// lldb-command:print f64
-// lldb-check:[...]$12 = 3.5
+// lldbg-check:[...]$12 = 3.5
+// lldbr-check:(f64) f64 = 3.5
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *bool_ref
-// lldb-check:[...]$0 = true
+// lldbg-check:[...]$0 = true
+// lldbr-check:(bool) *bool_ref = true
// lldb-command:print *int_ref
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) *int_ref = -1
-// NOTE: lldb doesn't support 32bit chars at the moment
-// d ebugger:print *char_ref
-// c heck:[...]$x = 97
+// NOTE: only rust-enabled lldb supports 32bit chars
+// lldbr-command:print *char_ref
+// lldbr-check:(char) *char_ref = 'a'
// lldb-command:print *i8_ref
-// lldb-check:[...]$2 = 'D'
+// lldbg-check:[...]$2 = 'D'
+// lldbr-check:(i8) *i8_ref = 68
// lldb-command:print *i16_ref
-// lldb-check:[...]$3 = -16
+// lldbg-check:[...]$3 = -16
+// lldbr-check:(i16) *i16_ref = -16
// lldb-command:print *i32_ref
-// lldb-check:[...]$4 = -32
+// lldbg-check:[...]$4 = -32
+// lldbr-check:(i32) *i32_ref = -32
// lldb-command:print *i64_ref
-// lldb-check:[...]$5 = -64
+// lldbg-check:[...]$5 = -64
+// lldbr-check:(i64) *i64_ref = -64
// lldb-command:print *uint_ref
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(usize) *uint_ref = 1
// lldb-command:print *u8_ref
-// lldb-check:[...]$7 = 'd'
+// lldbg-check:[...]$7 = 'd'
+// lldbr-check:(u8) *u8_ref = 100
// lldb-command:print *u16_ref
-// lldb-check:[...]$8 = 16
+// lldbg-check:[...]$8 = 16
+// lldbr-check:(u16) *u16_ref = 16
// lldb-command:print *u32_ref
-// lldb-check:[...]$9 = 32
+// lldbg-check:[...]$9 = 32
+// lldbr-check:(u32) *u32_ref = 32
// lldb-command:print *u64_ref
-// lldb-check:[...]$10 = 64
+// lldbg-check:[...]$10 = 64
+// lldbr-check:(u64) *u64_ref = 64
// lldb-command:print *f32_ref
-// lldb-check:[...]$11 = 2.5
+// lldbg-check:[...]$11 = 2.5
+// lldbr-check:(f32) *f32_ref = 2.5
// lldb-command:print *f64_ref
-// lldb-check:[...]$12 = 3.5
+// lldbg-check:[...]$12 = 3.5
+// lldbr-check:(f64) *f64_ref = 3.5
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *the_a_ref
-// lldb-check:[...]$0 = TheA
+// lldbg-check:[...]$0 = TheA
+// lldbr-check:(borrowed_c_style_enum::ABC) *the_a_ref = borrowed_c_style_enum::ABC::TheA
// lldb-command:print *the_b_ref
-// lldb-check:[...]$1 = TheB
+// lldbg-check:[...]$1 = TheB
+// lldbr-check:(borrowed_c_style_enum::ABC) *the_b_ref = borrowed_c_style_enum::ABC::TheB
// lldb-command:print *the_c_ref
-// lldb-check:[...]$2 = TheC
+// lldbg-check:[...]$2 = TheC
+// lldbr-check:(borrowed_c_style_enum::ABC) *the_c_ref = borrowed_c_style_enum::ABC::TheC
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *the_a_ref
-// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbr-check:(borrowed_enum::ABC::TheA) *the_a_ref = TheA { borrowed_enum::ABC::TheA: 0, borrowed_enum::ABC::TheB: 8970181431921507452 }
// lldb-command:print *the_b_ref
-// lldb-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbr-check:(borrowed_enum::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
// lldb-command:print *univariant_ref
-// lldb-check:[...]$2 = TheOnlyCase(4820353753753434)
+// lldbg-check:[...]$2 = TheOnlyCase(4820353753753434)
+// lldbr-check:(borrowed_enum::Univariant) *univariant_ref = { borrowed_enum::TheOnlyCase = { = 4820353753753434 } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *stack_val_ref
-// lldb-check:[...]$0 = SomeStruct { x: 10, y: 23.5 }
+// lldbg-check:[...]$0 = SomeStruct { x: 10, y: 23.5 }
+// lldbr-check:(borrowed_struct::SomeStruct) *stack_val_ref = SomeStruct { x: 10, y: 23.5 }
// lldb-command:print *stack_val_interior_ref_1
-// lldb-check:[...]$1 = 10
+// lldbg-check:[...]$1 = 10
+// lldbr-check:(isize) *stack_val_interior_ref_1 = 10
// lldb-command:print *stack_val_interior_ref_2
-// lldb-check:[...]$2 = 23.5
+// lldbg-check:[...]$2 = 23.5
+// lldbr-check:(f64) *stack_val_interior_ref_2 = 23.5
// lldb-command:print *ref_to_unnamed
-// lldb-check:[...]$3 = SomeStruct { x: 11, y: 24.5 }
+// lldbg-check:[...]$3 = SomeStruct { x: 11, y: 24.5 }
+// lldbr-check:(borrowed_struct::SomeStruct) *ref_to_unnamed = SomeStruct { x: 11, y: 24.5 }
// lldb-command:print *unique_val_ref
-// lldb-check:[...]$4 = SomeStruct { x: 13, y: 26.5 }
+// lldbg-check:[...]$4 = SomeStruct { x: 13, y: 26.5 }
+// lldbr-check:(borrowed_struct::SomeStruct) *unique_val_ref = SomeStruct { x: 13, y: 26.5 }
// lldb-command:print *unique_val_interior_ref_1
-// lldb-check:[...]$5 = 13
+// lldbg-check:[...]$5 = 13
+// lldbr-check:(isize) *unique_val_interior_ref_1 = 13
// lldb-command:print *unique_val_interior_ref_2
-// lldb-check:[...]$6 = 26.5
+// lldbg-check:[...]$6 = 26.5
+// lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print *stack_val_ref
-// lldb-check:[...]$0 = (-14, -19)
+// lldbg-check:[...]$0 = (-14, -19)
+// lldbr-check:((i16, f32)) *stack_val_ref = { = -14 = -19 }
// lldb-command:print *ref_to_unnamed
-// lldb-check:[...]$1 = (-15, -20)
+// lldbg-check:[...]$1 = (-15, -20)
+// lldbr-check:((i16, f32)) *ref_to_unnamed = { = -15 = -20 }
// lldb-command:print *unique_val_ref
-// lldb-check:[...]$2 = (-17, -22)
+// lldbg-check:[...]$2 = (-17, -22)
+// lldbr-check:((i16, f32)) *unique_val_ref = { = -17 = -22 }
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print *bool_ref
-// lldb-check:[...]$0 = true
+// lldbg-check:[...]$0 = true
+// lldbr-check:(bool) *bool_ref = true
// lldb-command:print *int_ref
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) *int_ref = -1
-// d ebugger:print *char_ref
-// c heck:[...]$3 = 97
+// NOTE: only rust-enabled lldb supports 32bit chars
+// lldbr-command:print *char_ref
+// lldbr-check:(char) *char_ref = 97
// lldb-command:print *i8_ref
-// lldb-check:[...]$2 = 68
+// lldbg-check:[...]$2 = 68
+// lldbr-check:(i8) *i8_ref = 68
// lldb-command:print *i16_ref
-// lldb-check:[...]$3 = -16
+// lldbg-check:[...]$3 = -16
+// lldbr-check:(i16) *i16_ref = -16
// lldb-command:print *i32_ref
-// lldb-check:[...]$4 = -32
+// lldbg-check:[...]$4 = -32
+// lldbr-check:(i32) *i32_ref = -32
// lldb-command:print *i64_ref
-// lldb-check:[...]$5 = -64
+// lldbg-check:[...]$5 = -64
+// lldbr-check:(i64) *i64_ref = -64
// lldb-command:print *uint_ref
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(usize) *uint_ref = 1
// lldb-command:print *u8_ref
-// lldb-check:[...]$7 = 100
+// lldbg-check:[...]$7 = 100
+// lldbr-check:(u8) *u8_ref = 100
// lldb-command:print *u16_ref
-// lldb-check:[...]$8 = 16
+// lldbg-check:[...]$8 = 16
+// lldbr-check:(u16) *u16_ref = 16
// lldb-command:print *u32_ref
-// lldb-check:[...]$9 = 32
+// lldbg-check:[...]$9 = 32
+// lldbr-check:(u32) *u32_ref = 32
// lldb-command:print *u64_ref
-// lldb-check:[...]$10 = 64
+// lldbg-check:[...]$10 = 64
+// lldbr-check:(u64) *u64_ref = 64
// lldb-command:print *f32_ref
-// lldb-check:[...]$11 = 2.5
+// lldbg-check:[...]$11 = 2.5
+// lldbr-check:(f32) *f32_ref = 2.5
// lldb-command:print *f64_ref
-// lldb-check:[...]$12 = 3.5
+// lldbg-check:[...]$12 = 3.5
+// lldbr-check:(f64) *f64_ref = 3.5
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print *a
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(i32) *a = 1
// lldb-command:print *b
-// lldb-check:[...]$1 = (2, 3.5)
+// lldbg-check:[...]$1 = (2, 3.5)
+// lldbr-check:((i32, f64)) *b = { = 2 = 3.5 }
#![allow(unused_variables)]
#![feature(box_syntax)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// lldb-command:run
// lldb-command:print *unique
-// lldb-check:[...]$0 = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }
+// lldbg-check:[...]$0 = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }
+// lldbr-check:(boxed_struct::StructWithSomePadding) *unique = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }
// lldb-command:print *unique_dtor
-// lldb-check:[...]$1 = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }
+// lldbg-check:[...]$1 = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }
+// lldbr-check:(boxed_struct::StructWithDestructor) *unique_dtor = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print self
-// lldb-check:[...]$0 = 1111
+// lldbg-check:[...]$0 = 1111
+// lldbr-check:(isize) self = 1111
// lldb-command:continue
// lldb-command:print self
-// lldb-check:[...]$1 = Struct { x: 2222, y: 3333 }
+// lldbg-check:[...]$1 = Struct { x: 2222, y: 3333 }
+// lldbr-check:(by_value_self_argument_in_trait_impl::Struct) self = Struct { x: 2222, y: 3333 }
// lldb-command:continue
// lldb-command:print self
-// lldb-check:[...]$2 = (4444.5, 5555, 6666, 7777.5)
+// lldbg-check:[...]$2 = (4444.5, 5555, 6666, 7777.5)
+// lldbr-check:((f64, isize, isize, f64)) self = { = 4444.5 = 5555 = 6666 = 7777.5 }
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print tuple_interior_padding
-// lldb-check:[...]$0 = (0, OneHundred)
+// lldbg-check:[...]$0 = (0, OneHundred)
+// lldbr-check:((i16, c_style_enum_in_composite::AnEnum)) tuple_interior_padding = { = 0 = c_style_enum_in_composite::AnEnum::OneHundred }
// lldb-command:print tuple_padding_at_end
-// lldb-check:[...]$1 = ((1, OneThousand), 2)
+// lldbg-check:[...]$1 = ((1, OneThousand), 2)
+// lldbr-check:(((u64, c_style_enum_in_composite::AnEnum), u64)) tuple_padding_at_end = { = { = 1 = c_style_enum_in_composite::AnEnum::OneThousand } = 2 }
// lldb-command:print tuple_different_enums
-// lldb-check:[...]$2 = (OneThousand, MountainView, OneMillion, Vienna)
+// lldbg-check:[...]$2 = (OneThousand, MountainView, OneMillion, Vienna)
+// lldbr-check:((c_style_enum_in_composite::AnEnum, c_style_enum_in_composite::AnotherEnum, c_style_enum_in_composite::AnEnum, c_style_enum_in_composite::AnotherEnum)) tuple_different_enums = { = c_style_enum_in_composite::AnEnum::OneThousand = c_style_enum_in_composite::AnotherEnum::MountainView = c_style_enum_in_composite::AnEnum::OneMillion = c_style_enum_in_composite::AnotherEnum::Vienna }
// lldb-command:print padded_struct
-// lldb-check:[...]$3 = PaddedStruct { a: 3, b: OneMillion, c: 4, d: Toronto, e: 5 }
+// lldbg-check:[...]$3 = PaddedStruct { a: 3, b: OneMillion, c: 4, d: Toronto, e: 5 }
+// lldbr-check:(c_style_enum_in_composite::PaddedStruct) padded_struct = PaddedStruct { a: 3, b: c_style_enum_in_composite::AnEnum::OneMillion, c: 4, d: c_style_enum_in_composite::AnotherEnum::Toronto, e: 5 }
// lldb-command:print packed_struct
-// lldb-check:[...]$4 = PackedStruct { a: 6, b: OneHundred, c: 7, d: Vienna, e: 8 }
+// lldbg-check:[...]$4 = PackedStruct { a: 6, b: OneHundred, c: 7, d: Vienna, e: 8 }
+// lldbr-check:(c_style_enum_in_composite::PackedStruct) packed_struct = PackedStruct { a: 6, b: c_style_enum_in_composite::AnEnum::OneHundred, c: 7, d: c_style_enum_in_composite::AnotherEnum::Vienna, e: 8 }
// lldb-command:print non_padded_struct
-// lldb-check:[...]$5 = NonPaddedStruct { a: OneMillion, b: MountainView, c: OneThousand, d: Toronto }
+// lldbg-check:[...]$5 = NonPaddedStruct { a: OneMillion, b: MountainView, c: OneThousand, d: Toronto }
+// lldbr-check:(c_style_enum_in_composite::NonPaddedStruct) non_padded_struct = NonPaddedStruct { a: c_style_enum_in_composite::AnEnum::OneMillion, b: c_style_enum_in_composite::AnotherEnum::MountainView, c: c_style_enum_in_composite::AnEnum::OneThousand, d: c_style_enum_in_composite::AnotherEnum::Toronto }
// lldb-command:print struct_with_drop
-// lldb-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9)
+// lldbg-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9)
+// lldbr-check:((c_style_enum_in_composite::StructWithDrop, i64)) struct_with_drop = { = StructWithDrop { a: c_style_enum_in_composite::AnEnum::OneHundred, b: c_style_enum_in_composite::AnotherEnum::Vienna } = 9 }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// ignore-aarch64
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// min-lldb-version: 310
// lldb-command:run
// lldb-command:print auto_one
-// lldb-check:[...]$0 = One
+// lldbg-check:[...]$0 = One
+// lldbr-check:(c_style_enum::AutoDiscriminant) auto_one = c_style_enum::AutoDiscriminant::One
// lldb-command:print auto_two
-// lldb-check:[...]$1 = Two
+// lldbg-check:[...]$1 = Two
+// lldbr-check:(c_style_enum::AutoDiscriminant) auto_two = c_style_enum::AutoDiscriminant::Two
// lldb-command:print auto_three
-// lldb-check:[...]$2 = Three
+// lldbg-check:[...]$2 = Three
+// lldbr-check:(c_style_enum::AutoDiscriminant) auto_three = c_style_enum::AutoDiscriminant::Three
// lldb-command:print manual_one_hundred
-// lldb-check:[...]$3 = OneHundred
+// lldbg-check:[...]$3 = OneHundred
+// lldbr-check:(c_style_enum::ManualDiscriminant) manual_one_hundred = c_style_enum::ManualDiscriminant::OneHundred
// lldb-command:print manual_one_thousand
-// lldb-check:[...]$4 = OneThousand
+// lldbg-check:[...]$4 = OneThousand
+// lldbr-check:(c_style_enum::ManualDiscriminant) manual_one_thousand = c_style_enum::ManualDiscriminant::OneThousand
// lldb-command:print manual_one_million
-// lldb-check:[...]$5 = OneMillion
+// lldbg-check:[...]$5 = OneMillion
+// lldbr-check:(c_style_enum::ManualDiscriminant) manual_one_million = c_style_enum::ManualDiscriminant::OneMillion
// lldb-command:print single_variant
-// lldb-check:[...]$6 = TheOnlyVariant
+// lldbg-check:[...]$6 = TheOnlyVariant
+// lldbr-check:(c_style_enum::SingleVariant) single_variant = c_style_enum::SingleVariant::TheOnlyVariant
#![allow(unused_variables)]
#![allow(dead_code)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = 0.5
+// lldbg-check:[...]$0 = 0.5
+// lldbr-check:(f64) x = 0.5
// lldb-command:print y
-// lldb-check:[...]$1 = 10
+// lldbg-check:[...]$1 = 10
+// lldbr-check:(i32) y = 10
// lldb-command:continue
// lldb-command:print *x
-// lldb-check:[...]$2 = 29
+// lldbg-check:[...]$2 = 29
+// lldbr-check:(i32) *x = 29
// lldb-command:print *y
-// lldb-check:[...]$3 = 110
+// lldbg-check:[...]$3 = 110
+// lldbr-check:(i32) *y = 110
// lldb-command:continue
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print result
-// lldb-check:[...]$0 = (17, 17)
+// lldbg-check:[...]$0 = (17, 17)
+// lldbr-check:((u32, u32)) result = { = 17 = 17 }
// lldb-command:print a_variable
-// lldb-check:[...]$1 = 123456789
+// lldbg-check:[...]$1 = 123456789
+// lldbr-check:(u32) a_variable = 123456789
// lldb-command:print another_variable
-// lldb-check:[...]$2 = 123456789.5
+// lldbg-check:[...]$2 = 123456789.5
+// lldbr-check:(f64) another_variable = 123456789.5
// lldb-command:continue
// lldb-command:print result
-// lldb-check:[...]$3 = (1212, 1212)
+// lldbg-check:[...]$3 = (1212, 1212)
+// lldbr-check:((i16, i16)) result = { = 1212 = 1212 }
// lldb-command:print a_variable
-// lldb-check:[...]$4 = 123456789
+// lldbg-check:[...]$4 = 123456789
+// lldbr-check:(u32) a_variable = 123456789
// lldb-command:print another_variable
-// lldb-check:[...]$5 = 123456789.5
+// lldbg-check:[...]$5 = 123456789.5
+// lldbr-check:(f64) another_variable = 123456789.5
// lldb-command:continue
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) a = 1
// lldb-command:print b
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) b = false
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(isize) a = 2
// lldb-command:print b
-// lldb-check:[...]$3 = 3
+// lldbg-check:[...]$3 = 3
+// lldbr-check:(u16) b = 3
// lldb-command:print c
-// lldb-check:[...]$4 = 4
+// lldbg-check:[...]$4 = 4
+// lldbr-check:(u16) c = 4
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$5 = 5
+// lldbg-check:[...]$5 = 5
+// lldbr-check:(isize) a = 5
// lldb-command:print b
-// lldb-check:[...]$6 = (6, 7)
+// lldbg-check:[...]$6 = (6, 7)
+// lldbr-check:((u32, u32)) b = { = 6 = 7 }
// lldb-command:continue
// lldb-command:print h
-// lldb-check:[...]$7 = 8
+// lldbg-check:[...]$7 = 8
+// lldbr-check:(i16) h = 8
// lldb-command:print i
-// lldb-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbg-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbr-check:(destructured_fn_argument::Struct) i = Struct { a: 9, b: 10 }
// lldb-command:print j
-// lldb-check:[...]$9 = 11
+// lldbg-check:[...]$9 = 11
+// lldbr-check:(i16) j = 11
// lldb-command:continue
// lldb-command:print k
-// lldb-check:[...]$10 = 12
+// lldbg-check:[...]$10 = 12
+// lldbr-check:(i64) k = 12
// lldb-command:print l
-// lldb-check:[...]$11 = 13
+// lldbg-check:[...]$11 = 13
+// lldbr-check:(i32) l = 13
// lldb-command:continue
// lldb-command:print m
-// lldb-check:[...]$12 = 14
+// lldbg-check:[...]$12 = 14
+// lldbr-check:(isize) m = 14
// lldb-command:print n
-// lldb-check:[...]$13 = 16
+// lldbg-check:[...]$13 = 16
+// lldbr-check:(i32) n = 16
// lldb-command:continue
// lldb-command:print o
-// lldb-check:[...]$14 = 18
+// lldbg-check:[...]$14 = 18
+// lldbr-check:(i32) o = 18
// lldb-command:continue
// lldb-command:print p
-// lldb-check:[...]$15 = 19
+// lldbg-check:[...]$15 = 19
+// lldbr-check:(i64) p = 19
// lldb-command:print q
-// lldb-check:[...]$16 = 20
+// lldbg-check:[...]$16 = 20
+// lldbr-check:(i32) q = 20
// lldb-command:print r
-// lldb-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbg-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbr-check:(destructured_fn_argument::Struct) r = Struct { a: 21, b: 22 }
// lldb-command:continue
// lldb-command:print s
-// lldb-check:[...]$18 = 24
+// lldbg-check:[...]$18 = 24
+// lldbr-check:(i32) s = 24
// lldb-command:print t
-// lldb-check:[...]$19 = 23
+// lldbg-check:[...]$19 = 23
+// lldbr-check:(i64) t = 23
// lldb-command:continue
// lldb-command:print u
-// lldb-check:[...]$20 = 25
+// lldbg-check:[...]$20 = 25
+// lldbr-check:(i16) u = 25
// lldb-command:print v
-// lldb-check:[...]$21 = 26
+// lldbg-check:[...]$21 = 26
+// lldbr-check:(i32) v = 26
// lldb-command:print w
-// lldb-check:[...]$22 = 27
+// lldbg-check:[...]$22 = 27
+// lldbr-check:(i64) w = 27
// lldb-command:print x
-// lldb-check:[...]$23 = 28
+// lldbg-check:[...]$23 = 28
+// lldbr-check:(i32) x = 28
// lldb-command:print y
-// lldb-check:[...]$24 = 29
+// lldbg-check:[...]$24 = 29
+// lldbr-check:(i64) y = 29
// lldb-command:print z
-// lldb-check:[...]$25 = 30
+// lldbg-check:[...]$25 = 30
+// lldbr-check:(i32) z = 30
// lldb-command:print ae
-// lldb-check:[...]$26 = 31
+// lldbg-check:[...]$26 = 31
+// lldbr-check:(i64) ae = 31
// lldb-command:print oe
-// lldb-check:[...]$27 = 32
+// lldbg-check:[...]$27 = 32
+// lldbr-check:(i32) oe = 32
// lldb-command:print ue
-// lldb-check:[...]$28 = 33
+// lldbg-check:[...]$28 = 33
+// lldbr-check:(u16) ue = 33
// lldb-command:continue
// lldb-command:print aa
-// lldb-check:[...]$29 = (34, 35)
+// lldbg-check:[...]$29 = (34, 35)
+// lldbr-check:((isize, isize)) aa = { = 34 = 35 }
// lldb-command:continue
// lldb-command:print bb
-// lldb-check:[...]$30 = (36, 37)
+// lldbg-check:[...]$30 = (36, 37)
+// lldbr-check:((isize, isize)) bb = { = 36 = 37 }
// lldb-command:continue
// lldb-command:print cc
-// lldb-check:[...]$31 = 38
+// lldbg-check:[...]$31 = 38
+// lldbr-check:(isize) cc = 38
// lldb-command:continue
// lldb-command:print dd
-// lldb-check:[...]$32 = (40, 41, 42)
+// lldbg-check:[...]$32 = (40, 41, 42)
+// lldbr-check:((isize, isize, isize)) dd = { = 40 = 41 = 42 }
// lldb-command:continue
// lldb-command:print *ee
-// lldb-check:[...]$33 = (43, 44, 45)
+// lldbg-check:[...]$33 = (43, 44, 45)
+// lldbr-check:((isize, isize, isize)) *ee = { = 43 = 44 = 45 }
// lldb-command:continue
// lldb-command:print *ff
-// lldb-check:[...]$34 = 46
+// lldbg-check:[...]$34 = 46
+// lldbr-check:(isize) *ff = 46
// lldb-command:print gg
-// lldb-check:[...]$35 = (47, 48)
+// lldbg-check:[...]$35 = (47, 48)
+// lldbr-check:((isize, isize)) gg = { = 47 = 48 }
// lldb-command:continue
// lldb-command:print *hh
-// lldb-check:[...]$36 = 50
+// lldbg-check:[...]$36 = 50
+// lldbr-check:(i32) *hh = 50
// lldb-command:continue
// lldb-command:print ii
-// lldb-check:[...]$37 = 51
+// lldbg-check:[...]$37 = 51
+// lldbr-check:(i32) ii = 51
// lldb-command:continue
// lldb-command:print *jj
-// lldb-check:[...]$38 = 52
+// lldbg-check:[...]$38 = 52
+// lldbr-check:(i32) *jj = 52
// lldb-command:continue
// lldb-command:print kk
-// lldb-check:[...]$39 = 53
+// lldbg-check:[...]$39 = 53
+// lldbr-check:(f64) kk = 53
// lldb-command:print ll
-// lldb-check:[...]$40 = 54
+// lldbg-check:[...]$40 = 54
+// lldbr-check:(isize) ll = 54
// lldb-command:continue
// lldb-command:print mm
-// lldb-check:[...]$41 = 55
+// lldbg-check:[...]$41 = 55
+// lldbr-check:(f64) mm = 55
// lldb-command:print *nn
-// lldb-check:[...]$42 = 56
+// lldbg-check:[...]$42 = 56
+// lldbr-check:(isize) *nn = 56
// lldb-command:continue
// lldb-command:print oo
-// lldb-check:[...]$43 = 57
+// lldbg-check:[...]$43 = 57
+// lldbr-check:(isize) oo = 57
// lldb-command:print pp
-// lldb-check:[...]$44 = 58
+// lldbg-check:[...]$44 = 58
+// lldbr-check:(isize) pp = 58
// lldb-command:print qq
-// lldb-check:[...]$45 = 59
+// lldbg-check:[...]$45 = 59
+// lldbr-check:(isize) qq = 59
// lldb-command:continue
// lldb-command:print rr
-// lldb-check:[...]$46 = 60
+// lldbg-check:[...]$46 = 60
+// lldbr-check:(isize) rr = 60
// lldb-command:print ss
-// lldb-check:[...]$47 = 61
+// lldbg-check:[...]$47 = 61
+// lldbr-check:(isize) ss = 61
// lldb-command:print tt
-// lldb-check:[...]$48 = 62
+// lldbg-check:[...]$48 = 62
+// lldbr-check:(isize) tt = 62
// lldb-command:continue
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// DESTRUCTURED STRUCT
// lldb-command:print x
-// lldb-check:[...]$0 = 400
+// lldbg-check:[...]$0 = 400
+// lldbr-check:(i16) x = 400
// lldb-command:print y
-// lldb-check:[...]$1 = 401.5
+// lldbg-check:[...]$1 = 401.5
+// lldbr-check:(f32) y = 401.5
// lldb-command:print z
-// lldb-check:[...]$2 = true
+// lldbg-check:[...]$2 = true
+// lldbr-check:(bool) z = true
// lldb-command:continue
// DESTRUCTURED TUPLE
// lldb-command:print _i8
-// lldb-check:[...]$3 = 0x6f
+// lldbg-check:[...]$3 = 0x6f
+// lldbr-check:(i8) _i8 = 111
// lldb-command:print _u8
-// lldb-check:[...]$4 = 0x70
+// lldbg-check:[...]$4 = 0x70
+// lldbr-check:(u8) _u8 = 112
// lldb-command:print _i16
-// lldb-check:[...]$5 = -113
+// lldbg-check:[...]$5 = -113
+// lldbr-check:(i16) _i16 = -113
// lldb-command:print _u16
-// lldb-check:[...]$6 = 114
+// lldbg-check:[...]$6 = 114
+// lldbr-check:(u16) _u16 = 114
// lldb-command:print _i32
-// lldb-check:[...]$7 = -115
+// lldbg-check:[...]$7 = -115
+// lldbr-check:(i32) _i32 = -115
// lldb-command:print _u32
-// lldb-check:[...]$8 = 116
+// lldbg-check:[...]$8 = 116
+// lldbr-check:(u32) _u32 = 116
// lldb-command:print _i64
-// lldb-check:[...]$9 = -117
+// lldbg-check:[...]$9 = -117
+// lldbr-check:(i64) _i64 = -117
// lldb-command:print _u64
-// lldb-check:[...]$10 = 118
+// lldbg-check:[...]$10 = 118
+// lldbr-check:(u64) _u64 = 118
// lldb-command:print _f32
-// lldb-check:[...]$11 = 119.5
+// lldbg-check:[...]$11 = 119.5
+// lldbr-check:(f32) _f32 = 119.5
// lldb-command:print _f64
-// lldb-check:[...]$12 = 120.5
+// lldbg-check:[...]$12 = 120.5
+// lldbr-check:(f64) _f64 = 120.5
// lldb-command:continue
// MORE COMPLEX CASE
// lldb-command:print v1
-// lldb-check:[...]$13 = 80000
+// lldbg-check:[...]$13 = 80000
+// lldbr-check:(i32) v1 = 80000
// lldb-command:print x1
-// lldb-check:[...]$14 = 8000
+// lldbg-check:[...]$14 = 8000
+// lldbr-check:(i16) x1 = 8000
// lldb-command:print *y1
-// lldb-check:[...]$15 = 80001.5
+// lldbg-check:[...]$15 = 80001.5
+// lldbr-check:(f32) *y1 = 80001.5
// lldb-command:print z1
-// lldb-check:[...]$16 = false
+// lldbg-check:[...]$16 = false
+// lldbr-check:(bool) z1 = false
// lldb-command:print *x2
-// lldb-check:[...]$17 = -30000
+// lldbg-check:[...]$17 = -30000
+// lldbr-check:(i16) *x2 = -30000
// lldb-command:print y2
-// lldb-check:[...]$18 = -300001.5
+// lldbg-check:[...]$18 = -300001.5
+// lldbr-check:(f32) y2 = -300001.5
// lldb-command:print *z2
-// lldb-check:[...]$19 = true
+// lldbg-check:[...]$19 = true
+// lldbr-check:(bool) *z2 = true
// lldb-command:print v2
-// lldb-check:[...]$20 = 854237.5
+// lldbg-check:[...]$20 = 854237.5
+// lldbr-check:(f64) v2 = 854237.5
// lldb-command:continue
// SIMPLE IDENTIFIER
// lldb-command:print i
-// lldb-check:[...]$21 = 1234
+// lldbg-check:[...]$21 = 1234
+// lldbr-check:(i32) i = 1234
// lldb-command:continue
// lldb-command:print simple_struct_ident
-// lldb-check:[...]$22 = Struct { x: 3537, y: 35437.5, z: true }
+// lldbg-check:[...]$22 = Struct { x: 3537, y: 35437.5, z: true }
+// lldbr-check:(destructured_for_loop_variable::Struct) simple_struct_ident = Struct { x: 3537, y: 35437.5, z: true }
// lldb-command:continue
// lldb-command:print simple_tuple_ident
-// lldb-check:[...]$23 = (34903493, 232323)
+// lldbg-check:[...]$23 = (34903493, 232323)
+// lldbr-check:((u32, i64)) simple_tuple_ident = { = 34903493 = 232323 }
// lldb-command:continue
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) a = 1
// lldb-command:print b
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) b = false
// lldb-command:print c
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(isize) c = 2
// lldb-command:print d
-// lldb-check:[...]$3 = 3
+// lldbg-check:[...]$3 = 3
+// lldbr-check:(u16) d = 3
// lldb-command:print e
-// lldb-check:[...]$4 = 4
+// lldbg-check:[...]$4 = 4
+// lldbr-check:(u16) e = 4
// lldb-command:print f
-// lldb-check:[...]$5 = 5
+// lldbg-check:[...]$5 = 5
+// lldbr-check:(isize) f = 5
// lldb-command:print g
-// lldb-check:[...]$6 = (6, 7)
+// lldbg-check:[...]$6 = (6, 7)
+// lldbr-check:((u32, u32)) g = { = 6 = 7 }
// lldb-command:print h
-// lldb-check:[...]$7 = 8
+// lldbg-check:[...]$7 = 8
+// lldbr-check:(i16) h = 8
// lldb-command:print i
-// lldb-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbg-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbr-check:(destructured_local::Struct) i = Struct { a: 9, b: 10 }
// lldb-command:print j
-// lldb-check:[...]$9 = 11
+// lldbg-check:[...]$9 = 11
+// lldbr-check:(i16) j = 11
// lldb-command:print k
-// lldb-check:[...]$10 = 12
+// lldbg-check:[...]$10 = 12
+// lldbr-check:(i64) k = 12
// lldb-command:print l
-// lldb-check:[...]$11 = 13
+// lldbg-check:[...]$11 = 13
+// lldbr-check:(i32) l = 13
// lldb-command:print m
-// lldb-check:[...]$12 = 14
+// lldbg-check:[...]$12 = 14
+// lldbr-check:(i32) m = 14
// lldb-command:print n
-// lldb-check:[...]$13 = 16
+// lldbg-check:[...]$13 = 16
+// lldbr-check:(i32) n = 16
// lldb-command:print o
-// lldb-check:[...]$14 = 18
+// lldbg-check:[...]$14 = 18
+// lldbr-check:(i32) o = 18
// lldb-command:print p
-// lldb-check:[...]$15 = 19
+// lldbg-check:[...]$15 = 19
+// lldbr-check:(i64) p = 19
// lldb-command:print q
-// lldb-check:[...]$16 = 20
+// lldbg-check:[...]$16 = 20
+// lldbr-check:(i32) q = 20
// lldb-command:print r
-// lldb-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbg-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbr-check:(destructured_local::Struct) r = Struct { a: 21, b: 22 }
// lldb-command:print s
-// lldb-check:[...]$18 = 24
+// lldbg-check:[...]$18 = 24
+// lldbr-check:(i32) s = 24
// lldb-command:print t
-// lldb-check:[...]$19 = 23
+// lldbg-check:[...]$19 = 23
+// lldbr-check:(i64) t = 23
// lldb-command:print u
-// lldb-check:[...]$20 = 25
+// lldbg-check:[...]$20 = 25
+// lldbr-check:(i32) u = 25
// lldb-command:print v
-// lldb-check:[...]$21 = 26
+// lldbg-check:[...]$21 = 26
+// lldbr-check:(i32) v = 26
// lldb-command:print w
-// lldb-check:[...]$22 = 27
+// lldbg-check:[...]$22 = 27
+// lldbr-check:(i32) w = 27
// lldb-command:print x
-// lldb-check:[...]$23 = 28
+// lldbg-check:[...]$23 = 28
+// lldbr-check:(i32) x = 28
// lldb-command:print y
-// lldb-check:[...]$24 = 29
+// lldbg-check:[...]$24 = 29
+// lldbr-check:(i64) y = 29
// lldb-command:print z
-// lldb-check:[...]$25 = 30
+// lldbg-check:[...]$25 = 30
+// lldbr-check:(i32) z = 30
// lldb-command:print ae
-// lldb-check:[...]$26 = 31
+// lldbg-check:[...]$26 = 31
+// lldbr-check:(i64) ae = 31
// lldb-command:print oe
-// lldb-check:[...]$27 = 32
+// lldbg-check:[...]$27 = 32
+// lldbr-check:(i32) oe = 32
// lldb-command:print ue
-// lldb-check:[...]$28 = 33
+// lldbg-check:[...]$28 = 33
+// lldbr-check:(i32) ue = 33
// lldb-command:print aa
-// lldb-check:[...]$29 = (34, 35)
+// lldbg-check:[...]$29 = (34, 35)
+// lldbr-check:((i32, i32)) aa = { = 34 = 35 }
// lldb-command:print bb
-// lldb-check:[...]$30 = (36, 37)
+// lldbg-check:[...]$30 = (36, 37)
+// lldbr-check:((i32, i32)) bb = { = 36 = 37 }
// lldb-command:print cc
-// lldb-check:[...]$31 = 38
+// lldbg-check:[...]$31 = 38
+// lldbr-check:(i32) cc = 38
// lldb-command:print dd
-// lldb-check:[...]$32 = (40, 41, 42)
+// lldbg-check:[...]$32 = (40, 41, 42)
+// lldbr-check:((i32, i32, i32)) dd = { = 40 = 41 = 42 }
// lldb-command:print *ee
-// lldb-check:[...]$33 = (43, 44, 45)
+// lldbg-check:[...]$33 = (43, 44, 45)
+// lldbr-check:((i32, i32, i32)) *ee = { = 43 = 44 = 45 }
// lldb-command:print *ff
-// lldb-check:[...]$34 = 46
+// lldbg-check:[...]$34 = 46
+// lldbr-check:(i32) *ff = 46
// lldb-command:print gg
-// lldb-check:[...]$35 = (47, 48)
+// lldbg-check:[...]$35 = (47, 48)
+// lldbr-check:((i32, i32)) gg = { = 47 = 48 }
// lldb-command:print *hh
-// lldb-check:[...]$36 = 50
+// lldbg-check:[...]$36 = 50
+// lldbr-check:(i32) *hh = 50
// lldb-command:print ii
-// lldb-check:[...]$37 = 51
+// lldbg-check:[...]$37 = 51
+// lldbr-check:(i32) ii = 51
// lldb-command:print *jj
-// lldb-check:[...]$38 = 52
+// lldbg-check:[...]$38 = 52
+// lldbr-check:(i32) *jj = 52
// lldb-command:print kk
-// lldb-check:[...]$39 = 53
+// lldbg-check:[...]$39 = 53
+// lldbr-check:(f64) kk = 53
// lldb-command:print ll
-// lldb-check:[...]$40 = 54
+// lldbg-check:[...]$40 = 54
+// lldbr-check:(isize) ll = 54
// lldb-command:print mm
-// lldb-check:[...]$41 = 55
+// lldbg-check:[...]$41 = 55
+// lldbr-check:(f64) mm = 55
// lldb-command:print *nn
-// lldb-check:[...]$42 = 56
+// lldbg-check:[...]$42 = 56
+// lldbr-check:(isize) *nn = 56
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// lldb-command:run
// lldb-command:print no_padding1
-// lldb-check:[...]$0 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] }
+// lldbg-check:[...]$0 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] }
+// lldbr-check:(evec_in_struct::NoPadding1) no_padding1 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] }
// lldb-command:print no_padding2
-// lldb-check:[...]$1 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] }
+// lldbg-check:[...]$1 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] }
+// lldbr-check:(evec_in_struct::NoPadding2) no_padding2 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] }
// lldb-command:print struct_internal_padding
-// lldb-check:[...]$2 = StructInternalPadding { x: [13, 14], y: [15, 16] }
+// lldbg-check:[...]$2 = StructInternalPadding { x: [13, 14], y: [15, 16] }
+// lldbr-check:(evec_in_struct::StructInternalPadding) struct_internal_padding = StructInternalPadding { x: [13, 14], y: [15, 16] }
// lldb-command:print single_vec
-// lldb-check:[...]$3 = SingleVec { x: [17, 18, 19, 20, 21] }
+// lldbg-check:[...]$3 = SingleVec { x: [17, 18, 19, 20, 21] }
+// lldbr-check:(evec_in_struct::SingleVec) single_vec = SingleVec { x: [17, 18, 19, 20, 21] }
// lldb-command:print struct_padded_at_end
-// lldb-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
+// lldbg-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
+// lldbr-check:(evec_in_struct::StructPaddedAtEnd) struct_padded_at_end = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print len
-// lldb-check:[...]$0 = 20
+// lldbg-check:[...]$0 = 20
+// lldbr-check:(i32) len = 20
// lldb-command:print local0
-// lldb-check:[...]$1 = 19
+// lldbg-check:[...]$1 = 19
+// lldbr-check:(i32) local0 = 19
// lldb-command:print local1
-// lldb-check:[...]$2 = true
+// lldbg-check:[...]$2 = true
+// lldbr-check:(bool) local1 = true
// lldb-command:print local2
-// lldb-check:[...]$3 = 20.5
+// lldbg-check:[...]$3 = 20.5
+// lldbr-check:(f64) local2 = 20.5
// lldb-command:continue
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = 111102
+// lldbg-check:[...]$0 = 111102
+// lldbr-check:(isize) x = 111102
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$2 = 2000
+// lldbg-check:[...]$2 = 2000
+// lldbr-check:(i32) a = 2000
// lldb-command:print b
-// lldb-check:[...]$3 = 3000
+// lldbg-check:[...]$3 = 3000
+// lldbr-check:(i64) b = 3000
// lldb-command:continue
// lldb-command:run
// lldb-command:print *t0
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(i32) *t0 = 1
// lldb-command:print *t1
-// lldb-check:[...]$1 = 2.5
+// lldbg-check:[...]$1 = 2.5
+// lldbr-check:(f64) *t1 = 2.5
// lldb-command:print ret
-// lldb-check:[...]$2 = ((1, 2.5), (2.5, 1))
+// lldbg-check:[...]$2 = ((1, 2.5), (2.5, 1))
+// lldbr-check:(((i32, f64), (f64, i32))) ret = { = { = 1 = 2.5 } = { = 2.5 = 1 } }
// lldb-command:continue
// lldb-command:print *t0
-// lldb-check:[...]$3 = 3.5
+// lldbg-check:[...]$3 = 3.5
+// lldbr-check:(f64) *t0 = 3.5
// lldb-command:print *t1
-// lldb-check:[...]$4 = 4
+// lldbg-check:[...]$4 = 4
+// lldbr-check:(u16) *t1 = 4
// lldb-command:print ret
-// lldb-check:[...]$5 = ((3.5, 4), (4, 3.5))
+// lldbg-check:[...]$5 = ((3.5, 4), (4, 3.5))
+// lldbr-check:(((f64, u16), (u16, f64))) ret = { = { = 3.5 = 4 } = { = 4 = 3.5 } }
// lldb-command:continue
// lldb-command:print *t0
-// lldb-check:[...]$6 = 5
+// lldbg-check:[...]$6 = 5
+// lldbr-check:(i32) *t0 = 5
// lldb-command:print *t1
-// lldb-check:[...]$7 = Struct { a: 6, b: 7.5 }
+// lldbg-check:[...]$7 = Struct { a: 6, b: 7.5 }
+// lldbr-check:(generic_function::Struct) *t1 = Struct { a: 6, b: 7.5 }
// lldb-command:print ret
-// lldb-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5))
+// lldbg-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5))
+// lldbr-check:(((i32, generic_function::Struct), (generic_function::Struct, i32))) ret = { = { = 5 = Struct { a: 6, b: 7.5 } } = { = Struct { a: 6, b: 7.5 } = 5 } }
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = -1
+// lldbg-check:[...]$0 = -1
+// lldbr-check:(i32) x = -1
// lldb-command:print y
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i32) y = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = -1
+// lldbg-check:[...]$2 = -1
+// lldbr-check:(i32) x = -1
// lldb-command:print y
-// lldb-check:[...]$3 = 2.5
+// lldbg-check:[...]$3 = 2.5
+// lldbr-check:(f64) y = 2.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = -2.5
+// lldbg-check:[...]$4 = -2.5
+// lldbr-check:(f64) x = -2.5
// lldb-command:print y
-// lldb-check:[...]$5 = 1
+// lldbg-check:[...]$5 = 1
+// lldbr-check:(i32) y = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = -2.5
+// lldbg-check:[...]$6 = -2.5
+// lldbr-check:(f64) x = -2.5
// lldb-command:print y
-// lldb-check:[...]$7 = 2.5
+// lldbg-check:[...]$7 = 2.5
+// lldbr-check:(f64) y = 2.5
// lldb-command:continue
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
// compile-flags:-g
// min-lldb-version: 310
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(generic_method_on_generic_struct::Struct<(u32, i32)>) *self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(u16) arg2 = 2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(generic_method_on_generic_struct::Struct<(u32, i32)>) self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(i16) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(generic_method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(i32) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(generic_method_on_generic_struct::Struct<f64>) self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(i64) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(generic_method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10.5
+// lldbg-check:[...]$14 = -10.5
+// lldbr-check:(f32) arg2 = -10.5
// lldb-command:continue
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print int_int
-// lldb-check:[...]$0 = AGenericStruct<i32, i32> { key: 0, value: 1 }
+// lldbg-check:[...]$0 = AGenericStruct<i32, i32> { key: 0, value: 1 }
+// lldbr-check:(generic_struct::AGenericStruct<i32, i32>) int_int = AGenericStruct<i32, i32> { key: 0, value: 1 }
// lldb-command:print int_float
-// lldb-check:[...]$1 = AGenericStruct<i32, f64> { key: 2, value: 3.5 }
+// lldbg-check:[...]$1 = AGenericStruct<i32, f64> { key: 2, value: 3.5 }
+// lldbr-check:(generic_struct::AGenericStruct<i32, f64>) int_float = AGenericStruct<i32, f64> { key: 2, value: 3.5 }
// lldb-command:print float_int
-// lldb-check:[...]$2 = AGenericStruct<f64, i32> { key: 4.5, value: 5 }
+// lldbg-check:[...]$2 = AGenericStruct<f64, i32> { key: 4.5, value: 5 }
+// lldbr-check:(generic_struct::AGenericStruct<f64, i32>) float_int = AGenericStruct<f64, i32> { key: 4.5, value: 5 }
// lldb-command:print float_int_float
-// lldb-check:[...]$3 = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
+// lldbg-check:[...]$3 = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
+// lldbr-check:(generic_struct::AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>>) float_int_float = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print case1
-// lldb-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbr-check:(generic_tuple_style_enum::Regular<u16, u32, u64>::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
// lldb-command:print case2
-// lldb-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case2) case2 = Regular<i16, i32, i64>::Case2 { generic_tuple_style_enum::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum::Regular<i16, i32, i64>::Case2: 286331153, generic_tuple_style_enum::Regular<i16, i32, i64>::Case3: 286331153 }
// lldb-command:print case3
-// lldb-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case3) case3 = Regular<i16, i32, i64>::Case3 { generic_tuple_style_enum::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum::Regular<i16, i32, i64>::Case2: 6438275382588823897 }
// lldb-command:print univariant
-// lldb-check:[...]$3 = TheOnlyCase(-1)
+// lldbg-check:[...]$3 = TheOnlyCase(-1)
+// lldbr-check:(generic_tuple_style_enum::Univariant<i64>) univariant = { generic_tuple_style_enum::TheOnlyCase = { = -1 } }
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// lldb-command:run
// lldb-command:print string1.length
-// lldb-check:[...]$0 = 48
+// lldbg-check:[...]$0 = 48
+// lldbr-check:(usize) length = 48
// lldb-command:print string2.length
-// lldb-check:[...]$1 = 49
+// lldbg-check:[...]$1 = 49
+// lldbr-check:(usize) length = 49
// lldb-command:print string3.length
-// lldb-check:[...]$2 = 50
+// lldbg-check:[...]$2 = 50
+// lldbr-check:(usize) length = 50
// lldb-command:continue
// lldb-command:run
// lldb-command:print v
-// lldb-check:[...]$0 = vec![1, 2, 3]
+// lldbg-check:[...]$0 = vec![1, 2, 3]
+// lldbr-check:(alloc::vec::Vec<i32>) v = vec![1, 2, 3]
// lldb-command:print zs
-// lldb-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
-// lldb-command:continue
+// lldbg-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
+// lldbr-check:(issue_22656::StructWithZeroSizedField) zs = StructWithZeroSizedField { x: ZeroSizedStruct { }, y: 123, z: ZeroSizedStruct { }, w: 456 }
+// lldbr-command:continue
#![allow(unused_variables)]
#![allow(dead_code)]
// FIRST ITERATION
// lldb-command:print x
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(i32) x = -1
// lldb-command:continue
// SECOND ITERATION
// lldb-command:print x
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = -2
+// lldbg-check:[...]$3 = -2
+// lldbr-check:(i32) x = -2
// lldb-command:continue
// THIRD ITERATION
// lldb-command:print x
-// lldb-check:[...]$4 = 3
+// lldbg-check:[...]$4 = 3
+// lldbr-check:(i32) x = 3
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = -3
+// lldbg-check:[...]$5 = -3
+// lldbr-check:(i32) x = -3
// lldb-command:continue
// AFTER LOOP
// lldb-command:print x
-// lldb-check:[...]$6 = 1000000
+// lldbg-check:[...]$6 = 1000000
+// lldbr-check:(i32) x = 1000000
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// BEFORE if
// lldb-command:print x
-// lldb-check:[...]$0 = 999
+// lldbg-check:[...]$0 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// AT BEGINNING of 'then' block
// lldb-command:print x
-// lldb-check:[...]$2 = 999
+// lldbg-check:[...]$2 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$3 = -1
+// lldbg-check:[...]$3 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// AFTER 1st redeclaration of 'x'
// lldb-command:print x
-// lldb-check:[...]$4 = 1001
+// lldbg-check:[...]$4 = 1001
+// lldbr-check:(i32) x = 1001
// lldb-command:print y
-// lldb-check:[...]$5 = -1
+// lldbg-check:[...]$5 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// AFTER 2st redeclaration of 'x'
// lldb-command:print x
-// lldb-check:[...]$6 = 1002
+// lldbg-check:[...]$6 = 1002
+// lldbr-check:(i32) x = 1002
// lldb-command:print y
-// lldb-check:[...]$7 = 1003
+// lldbg-check:[...]$7 = 1003
+// lldbr-check:(i32) y = 1003
// lldb-command:continue
// AFTER 1st if expression
// lldb-command:print x
-// lldb-check:[...]$8 = 999
+// lldbg-check:[...]$8 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$9 = -1
+// lldbg-check:[...]$9 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// BEGINNING of else branch
// lldb-command:print x
-// lldb-check:[...]$10 = 999
+// lldbg-check:[...]$10 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$11 = -1
+// lldbg-check:[...]$11 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// BEGINNING of else branch
// lldb-command:print x
-// lldb-check:[...]$12 = 1004
+// lldbg-check:[...]$12 = 1004
+// lldbr-check:(i32) x = 1004
// lldb-command:print y
-// lldb-check:[...]$13 = 1005
+// lldbg-check:[...]$13 = 1005
+// lldbr-check:(i32) y = 1005
// lldb-command:continue
// BEGINNING of else branch
// lldb-command:print x
-// lldb-check:[...]$14 = 999
+// lldbg-check:[...]$14 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$15 = -1
+// lldbg-check:[...]$15 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print shadowed
-// lldb-check:[...]$0 = 231
+// lldbg-check:[...]$0 = 231
+// lldbr-check:(i32) shadowed = 231
// lldb-command:print not_shadowed
-// lldb-check:[...]$1 = 232
+// lldbg-check:[...]$1 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$2 = 233
+// lldbg-check:[...]$2 = 233
+// lldbr-check:(i32) shadowed = 233
// lldb-command:print not_shadowed
-// lldb-check:[...]$3 = 232
+// lldbg-check:[...]$3 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:print local_to_arm
-// lldb-check:[...]$4 = 234
+// lldbg-check:[...]$4 = 234
+// lldbr-check:(i32) local_to_arm = 234
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$5 = 236
+// lldbg-check:[...]$5 = 236
+// lldbr-check:(i32) shadowed = 236
// lldb-command:print not_shadowed
-// lldb-check:[...]$6 = 232
+// lldbg-check:[...]$6 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$7 = 237
+// lldbg-check:[...]$7 = 237
+// lldbr-check:(isize) shadowed = 237
// lldb-command:print not_shadowed
-// lldb-check:[...]$8 = 232
+// lldbg-check:[...]$8 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:print local_to_arm
-// lldb-check:[...]$9 = 238
+// lldbg-check:[...]$9 = 238
+// lldbr-check:(isize) local_to_arm = 238
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$10 = 239
+// lldbg-check:[...]$10 = 239
+// lldbr-check:(isize) shadowed = 239
// lldb-command:print not_shadowed
-// lldb-check:[...]$11 = 232
+// lldbg-check:[...]$11 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$12 = 241
+// lldbg-check:[...]$12 = 241
+// lldbr-check:(isize) shadowed = 241
// lldb-command:print not_shadowed
-// lldb-check:[...]$13 = 232
+// lldbg-check:[...]$13 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$14 = 243
+// lldbg-check:[...]$14 = 243
+// lldbr-check:(i32) shadowed = 243
// lldb-command:print *local_to_arm
-// lldb-check:[...]$15 = 244
+// lldbg-check:[...]$15 = 244
+// lldbr-check:(i32) *local_to_arm = 244
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$16 = 231
+// lldbg-check:[...]$16 = 231
+// lldbr-check:(i32) shadowed = 231
// lldb-command:print not_shadowed
-// lldb-check:[...]$17 = 232
+// lldbg-check:[...]$17 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 1000
+// lldbg-check:[...]$2 = 1000
+// lldbr-check:(isize) x = 1000
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 2.5
+// lldbg-check:[...]$3 = 2.5
+// lldbr-check:(f64) x = 2.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = true
+// lldbg-check:[...]$4 = true
+// lldbr-check:(bool) x = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = false
+// lldbg-check:[...]$5 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// FIRST ITERATION
// lldb-command:print x
-// lldb-check:[...]$0 = 0
+// lldbg-check:[...]$0 = 0
+// lldbr-check:(i32) x = 0
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 101
+// lldbg-check:[...]$2 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 101
+// lldbg-check:[...]$3 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = -987
+// lldbg-check:[...]$4 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = 101
+// lldbg-check:[...]$5 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// SECOND ITERATION
// lldb-command:print x
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$7 = 2
+// lldbg-check:[...]$7 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 102
+// lldbg-check:[...]$8 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$9 = 102
+// lldbg-check:[...]$9 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$10 = -987
+// lldbg-check:[...]$10 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$11 = 102
+// lldbg-check:[...]$11 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$12 = 2
+// lldbg-check:[...]$12 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 1000
+// lldbg-check:[...]$2 = 1000
+// lldbr-check:(isize) x = 1000
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 2.5
+// lldbg-check:[...]$3 = 2.5
+// lldbr-check:(f64) x = 2.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = true
+// lldbg-check:[...]$4 = true
+// lldbr-check:(bool) x = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = false
+// lldbg-check:[...]$5 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// FIRST ITERATION
// lldb-command:print x
-// lldb-check:[...]$0 = 0
+// lldbg-check:[...]$0 = 0
+// lldbr-check:(i32) x = 0
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 101
+// lldbg-check:[...]$2 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 101
+// lldbg-check:[...]$3 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = -987
+// lldbg-check:[...]$4 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = 101
+// lldbg-check:[...]$5 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// SECOND ITERATION
// lldb-command:print x
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$7 = 2
+// lldbg-check:[...]$7 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 102
+// lldbg-check:[...]$8 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$9 = 102
+// lldbg-check:[...]$9 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$10 = -987
+// lldbg-check:[...]$10 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$11 = 102
+// lldbg-check:[...]$11 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$12 = 2
+// lldbg-check:[...]$12 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 10
+// lldbg-check:[...]$0 = 10
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$1 = 34
+// lldbg-check:[...]$1 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$2 = 890242
+// lldbg-check:[...]$2 = 890242
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$3 = 34
+// lldbg-check:[...]$3 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$4 = 10
+// lldbg-check:[...]$4 = 10
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$5 = 34
+// lldbg-check:[...]$5 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$6 = 102
+// lldbg-check:[...]$6 = 102
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$7 = 34
+// lldbg-check:[...]$7 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
-// lldb-command:print a
-// lldb-check:[...]$8 = 110
-// lldb-command:print b
-// lldb-check:[...]$9 = 34
-// lldb-command:continue
-
-// lldb-command:print a
-// lldb-check:[...]$10 = 10
-// lldb-command:print b
-// lldb-check:[...]$11 = 34
-// lldb-command:continue
-
-// lldb-command:print a
-// lldb-check:[...]$12 = 10
-// lldb-command:print b
-// lldb-check:[...]$13 = 34
-// lldb-command:print c
-// lldb-check:[...]$14 = 400
-// lldb-command:continue
+// Don't test this with rust-enabled lldb for now; see issue #48807
+// lldbg-command:print a
+// lldbg-check:[...]$8 = 110
+// lldbg-command:print b
+// lldbg-check:[...]$9 = 34
+// lldbg-command:continue
+
+// lldbg-command:print a
+// lldbg-check:[...]$10 = 10
+// lldbg-command:print b
+// lldbg-check:[...]$11 = 34
+// lldbg-command:continue
+
+// lldbg-command:print a
+// lldbg-check:[...]$12 = 10
+// lldbg-command:print b
+// lldbg-check:[...]$13 = 34
+// lldbg-command:print c
+// lldbg-check:[...]$14 = 400
+// lldbg-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// STRUCT EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$0 = -1
+// lldbg-check:[...]$0 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$1 = 10
+// lldbg-check:[...]$1 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$2 = 11
+// lldbg-check:[...]$2 = 11
+// lldbr-check:(isize) val = 11
// lldb-command:print ten
-// lldb-check:[...]$3 = 10
+// lldbg-check:[...]$3 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$4 = -1
+// lldbg-check:[...]$4 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$5 = 10
+// lldbg-check:[...]$5 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// FUNCTION CALL
// lldb-command:print val
-// lldb-check:[...]$6 = -1
+// lldbg-check:[...]$6 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$7 = 10
+// lldbg-check:[...]$7 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$8 = 12
+// lldbg-check:[...]$8 = 12
+// lldbr-check:(isize) val = 12
// lldb-command:print ten
-// lldb-check:[...]$9 = 10
+// lldbg-check:[...]$9 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$10 = -1
+// lldbg-check:[...]$10 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$11 = 10
+// lldbg-check:[...]$11 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// TUPLE EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$12 = -1
+// lldbg-check:[...]$12 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$13 = 10
+// lldbg-check:[...]$13 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$14 = 13
+// lldbg-check:[...]$14 = 13
+// lldbr-check:(isize) val = 13
// lldb-command:print ten
-// lldb-check:[...]$15 = 10
+// lldbg-check:[...]$15 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$16 = -1
+// lldbg-check:[...]$16 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$17 = 10
+// lldbg-check:[...]$17 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// VEC EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$18 = -1
+// lldbg-check:[...]$18 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$19 = 10
+// lldbg-check:[...]$19 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$20 = 14
+// lldbg-check:[...]$20 = 14
+// lldbr-check:(isize) val = 14
// lldb-command:print ten
-// lldb-check:[...]$21 = 10
+// lldbg-check:[...]$21 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$22 = -1
+// lldbg-check:[...]$22 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$23 = 10
+// lldbg-check:[...]$23 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// REPEAT VEC EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$24 = -1
+// lldbg-check:[...]$24 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$25 = 10
+// lldbg-check:[...]$25 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$26 = 15
+// lldbg-check:[...]$26 = 15
+// lldbr-check:(isize) val = 15
// lldb-command:print ten
-// lldb-check:[...]$27 = 10
+// lldbg-check:[...]$27 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$28 = -1
+// lldbg-check:[...]$28 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$29 = 10
+// lldbg-check:[...]$29 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// ASSIGNMENT EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$30 = -1
+// lldbg-check:[...]$30 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$31 = 10
+// lldbg-check:[...]$31 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$32 = 16
+// lldbg-check:[...]$32 = 16
+// lldbr-check:(isize) val = 16
// lldb-command:print ten
-// lldb-check:[...]$33 = 10
+// lldbg-check:[...]$33 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$34 = -1
+// lldbg-check:[...]$34 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$35 = 10
+// lldbg-check:[...]$35 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// ARITHMETIC EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$36 = -1
+// lldbg-check:[...]$36 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$37 = 10
+// lldbg-check:[...]$37 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$38 = 17
+// lldbg-check:[...]$38 = 17
+// lldbr-check:(isize) val = 17
// lldb-command:print ten
-// lldb-check:[...]$39 = 10
+// lldbg-check:[...]$39 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$40 = -1
+// lldbg-check:[...]$40 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$41 = 10
+// lldbg-check:[...]$41 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// INDEX EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$42 = -1
+// lldbg-check:[...]$42 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$43 = 10
+// lldbg-check:[...]$43 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$44 = 18
+// lldbg-check:[...]$44 = 18
+// lldbr-check:(isize) val = 18
// lldb-command:print ten
-// lldb-check:[...]$45 = 10
+// lldbg-check:[...]$45 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$46 = -1
+// lldbg-check:[...]$46 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$47 = 10
+// lldbg-check:[...]$47 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
#![allow(unused_variables)]
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(method_on_generic_struct::Struct<(u32, i32)>) *self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(method_on_generic_struct::Struct<(u32, i32)>) self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(method_on_generic_struct::Struct<f64>) self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 100 }
+// lldbg-check:[...]$0 = Struct { x: 100 }
+// lldbr-check:(method_on_struct::Struct) *self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 100 }
+// lldbg-check:[...]$3 = Struct { x: 100 }
+// lldbr-check:(method_on_struct::Struct) self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 200 }
+// lldbg-check:[...]$6 = Struct { x: 200 }
+// lldbr-check:(method_on_struct::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 200 }
+// lldbg-check:[...]$9 = Struct { x: 200 }
+// lldbr-check:(method_on_struct::Struct) self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 200 }
+// lldbg-check:[...]$12 = Struct { x: 200 }
+// lldbr-check:(method_on_struct::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 100 }
+// lldbg-check:[...]$0 = Struct { x: 100 }
+// lldbr-check:(method_on_trait::Struct) *self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 100 }
+// lldbg-check:[...]$3 = Struct { x: 100 }
+// lldbr-check:(method_on_trait::Struct) self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 200 }
+// lldbg-check:[...]$6 = Struct { x: 200 }
+// lldbr-check:(method_on_trait::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 200 }
+// lldbg-check:[...]$9 = Struct { x: 200 }
+// lldbr-check:(method_on_trait::Struct) self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 200 }
+// lldbg-check:[...]$12 = Struct { x: 200 }
+// lldbr-check:(method_on_trait::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = TupleStruct(100, -100.5)
+// lldbg-check:[...]$0 = TupleStruct(100, -100.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 100 = -100.5 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = TupleStruct(100, -100.5)
+// lldbg-check:[...]$3 = TupleStruct(100, -100.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) self = { = 100 = -100.5 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = TupleStruct(200, -200.5)
+// lldbg-check:[...]$6 = TupleStruct(200, -200.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 200 = -200.5 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = TupleStruct(200, -200.5)
+// lldbg-check:[...]$9 = TupleStruct(200, -200.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) self = { = 200 = -200.5 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = TupleStruct(200, -200.5)
+// lldbg-check:[...]$12 = TupleStruct(200, -200.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 200 = -200.5 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// lldb-command:run
// lldb-command:print xxx
-// lldb-check:[...]$0 = 12345
+// lldbg-check:[...]$0 = 12345
+// lldbr-check:(u32) xxx = 12345
// lldb-command:continue
// lldb-command:print yyy
-// lldb-check:[...]$1 = 67890
+// lldbg-check:[...]$1 = 67890
+// lldbr-check:(u64) yyy = 67890
// lldb-command:continue
// lldb-command:run
// lldb-command:print abc
-// lldb-check:[...]$0 = 10101
+// lldbg-check:[...]$0 = 10101
+// lldbr-check:(i32) abc = 10101
// lldb-command:continue
// lldb-command:print abc
-// lldb-check:[...]$1 = 20202
+// lldbg-check:[...]$1 = 20202
+// lldbr-check:(i32) abc = 20202
// lldb-command:continue
// lldb-command:print abc
-// lldb-check:[...]$2 = 30303
+// lldbg-check:[...]$2 = 30303
+// lldbr-check:(i32) abc = 30303
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 10101
+// lldbg-check:[...]$0 = 10101
+// lldbr-check:(i32) a = 10101
// lldb-command:continue
// lldb-command:print b
-// lldb-check:[...]$1 = 20202
+// lldbg-check:[...]$1 = 20202
+// lldbr-check:(i32) b = 20202
// lldb-command:continue
// lldb-command:print c
-// lldb-check:[...]$2 = 30303
+// lldbg-check:[...]$2 = 30303
+// lldbr-check:(i32) c = 30303
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:print y
-// lldb-check:[...]$3 = true
+// lldbg-check:[...]$3 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$5 = 20
+// lldbg-check:[...]$5 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = true
+// lldbg-check:[...]$6 = true
+// lldbr-check:(bool) x = true
// lldb-command:print y
-// lldb-check:[...]$7 = 2220
+// lldbg-check:[...]$7 = 2220
+// lldbr-check:(i32) y = 2220
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 203203.5
+// lldbg-check:[...]$8 = 203203.5
+// lldbr-check:(f64) x = 203203.5
// lldb-command:print y
-// lldb-check:[...]$9 = 2220
+// lldbg-check:[...]$9 = 2220
+// lldbr-check:(i32) y = 2220
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$10 = 10.5
+// lldbg-check:[...]$10 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$11 = 20
+// lldbg-check:[...]$11 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print packed
-// lldb-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbg-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbr-check:(packed_struct_with_destructor::Packed) packed = Packed { x: 123, y: 234, z: 345 }
// lldb-command:print packedInPacked
-// lldb-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbg-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInPacked) packedInPacked = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
// lldb-command:print packedInUnpacked
-// lldb-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbg-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInUnpacked) packedInUnpacked = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
// lldb-command:print unpackedInPacked
-// lldb-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 }
+// lldbg-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 }
+// lldbr-check:(packed_struct_with_destructor::UnpackedInPacked) unpackedInPacked = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 }
// lldb-command:print packedInPackedWithDrop
-// lldb-check:[...]$4 = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } }
+// lldbg-check:[...]$4 = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInPackedWithDrop) packedInPackedWithDrop = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } }
// lldb-command:print packedInUnpackedWithDrop
-// lldb-check:[...]$5 = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } }
+// lldbg-check:[...]$5 = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInUnpackedWithDrop) packedInUnpackedWithDrop = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } }
// lldb-command:print unpackedInPackedWithDrop
-// lldb-check:[...]$6 = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 }
+// lldbg-check:[...]$6 = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 }
+// lldbr-check:(packed_struct_with_destructor::UnpackedInPackedWithDrop) unpackedInPackedWithDrop = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 }
// lldb-command:print deeplyNested
-// lldb-check:[...]$7 = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } }
+// lldbg-check:[...]$7 = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } }
+// lldbr-check:(packed_struct_with_destructor::DeeplyNested) deeplyNested = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } }
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print packed
-// lldb-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbg-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbr-check:(packed_struct::Packed) packed = Packed { x: 123, y: 234, z: 345 }
// lldb-command:print packedInPacked
-// lldb-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbg-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbr-check:(packed_struct::PackedInPacked) packedInPacked = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
// lldb-command:print packedInUnpacked
-// lldb-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbg-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbr-check:(packed_struct::PackedInUnpacked) packedInUnpacked = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
// lldb-command:print unpackedInPacked
-// lldb-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 }
+// lldbg-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 }
+// lldbr-check:(packed_struct::UnpackedInPacked) unpackedInPacked = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 }
// lldb-command:print sizeof(packed)
-// lldb-check:[...]$4 = 14
+// lldbg-check:[...]$4 = 14
+// lldbr-check:(usize) = 14
// lldb-command:print sizeof(packedInPacked)
-// lldb-check:[...]$5 = 40
+// lldbg-check:[...]$5 = 40
+// lldbr-check:(usize) = 40
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 100 }
+// lldbg-check:[...]$0 = Struct { x: 100 }
+// lldbr-check:(self_in_default_method::Struct) *self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 100 }
+// lldbg-check:[...]$3 = Struct { x: 100 }
+// lldbr-check:(self_in_default_method::Struct) self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 200 }
+// lldbg-check:[...]$6 = Struct { x: 200 }
+// lldbr-check:(self_in_default_method::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 200 }
+// lldbg-check:[...]$9 = Struct { x: 200 }
+// lldbr-check:(self_in_default_method::Struct) self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 200 }
+// lldbg-check:[...]$12 = Struct { x: 200 }
+// lldbr-check:(self_in_default_method::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
#![feature(box_syntax)]
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 987 }
+// lldbg-check:[...]$0 = Struct { x: 987 }
+// lldbr-check:(self_in_generic_default_method::Struct) *self = Struct { x: 987 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(u16) arg2 = 2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 987 }
+// lldbg-check:[...]$3 = Struct { x: 987 }
+// lldbr-check:(self_in_generic_default_method::Struct) self = Struct { x: 987 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(i16) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 879 }
+// lldbg-check:[...]$6 = Struct { x: 879 }
+// lldbr-check:(self_in_generic_default_method::Struct) *self = Struct { x: 879 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(i32) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 879 }
+// lldbg-check:[...]$9 = Struct { x: 879 }
+// lldbr-check:(self_in_generic_default_method::Struct) self = Struct { x: 879 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(i64) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 879 }
+// lldbg-check:[...]$12 = Struct { x: 879 }
+// lldbr-check:(self_in_generic_default_method::Struct) *self = Struct { x: 879 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10.5
+// lldbg-check:[...]$14 = -10.5
+// lldbr-check:(f32) arg2 = -10.5
// lldb-command:continue
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:print y
-// lldb-check:[...]$3 = true
+// lldbg-check:[...]$3 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$5 = 20
+// lldbg-check:[...]$5 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:print y
-// lldb-check:[...]$3 = true
+// lldbg-check:[...]$3 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$5 = 20
+// lldbg-check:[...]$5 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = 10.5
+// lldbg-check:[...]$6 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$7 = 20
+// lldbg-check:[...]$7 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 11.5
+// lldbg-check:[...]$8 = 11.5
+// lldbr-check:(f64) x = 11.5
// lldb-command:print y
-// lldb-check:[...]$9 = 20
+// lldbg-check:[...]$9 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 10
+// lldbg-check:[...]$3 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = 10
+// lldbg-check:[...]$5 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = false
+// lldbg-check:[...]$6 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// lldb-command:run
// lldb-command:print no_padding16
-// lldb-check:[...]$0 = NoPadding16 { x: 10000, y: -10001 }
+// lldbg-check:[...]$0 = NoPadding16 { x: 10000, y: -10001 }
+// lldbr-check:(simple_struct::NoPadding16) no_padding16 = NoPadding16 { x: 10000, y: -10001 }
// lldb-command:print no_padding32
-// lldb-check:[...]$1 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }
+// lldbg-check:[...]$1 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }
+// lldbr-check:(simple_struct::NoPadding32) no_padding32 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }
// lldb-command:print no_padding64
-// lldb-check:[...]$2 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }
+// lldbg-check:[...]$2 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }
+// lldbr-check:(simple_struct::NoPadding64) no_padding64 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }
// lldb-command:print no_padding163264
-// lldb-check:[...]$3 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }
+// lldbg-check:[...]$3 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }
+// lldbr-check:(simple_struct::NoPadding163264) no_padding163264 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }
// lldb-command:print internal_padding
-// lldb-check:[...]$4 = InternalPadding { x: 10012, y: -10013 }
+// lldbg-check:[...]$4 = InternalPadding { x: 10012, y: -10013 }
+// lldbr-check:(simple_struct::InternalPadding) internal_padding = InternalPadding { x: 10012, y: -10013 }
// lldb-command:print padding_at_end
-// lldb-check:[...]$5 = PaddingAtEnd { x: -10014, y: 10015 }
+// lldbg-check:[...]$5 = PaddingAtEnd { x: -10014, y: 10015 }
+// lldbr-check:(simple_struct::PaddingAtEnd) padding_at_end = PaddingAtEnd { x: -10014, y: 10015 }
#![allow(unused_variables)]
#![allow(dead_code)]
// lldb-command:run
// lldb-command:print/d noPadding8
-// lldb-check:[...]$0 = (-100, 100)
+// lldbg-check:[...]$0 = (-100, 100)
+// lldbr-check:((i8, u8)) noPadding8 = { = -100 -100 = 100 100 }
// lldb-command:print noPadding16
-// lldb-check:[...]$1 = (0, 1, 2)
+// lldbg-check:[...]$1 = (0, 1, 2)
+// lldbr-check:((i16, i16, u16)) noPadding16 = { = 0 = 1 = 2 }
// lldb-command:print noPadding32
-// lldb-check:[...]$2 = (3, 4.5, 5)
+// lldbg-check:[...]$2 = (3, 4.5, 5)
+// lldbr-check:((i32, f32, u32)) noPadding32 = { = 3 = 4.5 = 5 }
// lldb-command:print noPadding64
-// lldb-check:[...]$3 = (6, 7.5, 8)
+// lldbg-check:[...]$3 = (6, 7.5, 8)
+// lldbr-check:((i64, f64, u64)) noPadding64 = { = 6 = 7.5 = 8 }
// lldb-command:print internalPadding1
-// lldb-check:[...]$4 = (9, 10)
+// lldbg-check:[...]$4 = (9, 10)
+// lldbr-check:((i16, i32)) internalPadding1 = { = 9 = 10 }
// lldb-command:print internalPadding2
-// lldb-check:[...]$5 = (11, 12, 13, 14)
+// lldbg-check:[...]$5 = (11, 12, 13, 14)
+// lldbr-check:((i16, i32, u32, u64)) internalPadding2 = { = 11 = 12 = 13 = 14 }
// lldb-command:print paddingAtEnd
-// lldb-check:[...]$6 = (15, 16)
+// lldbg-check:[...]$6 = (15, 16)
+// lldbr-check:((i32, i16)) paddingAtEnd = { = 15 = 16 }
#![allow(unused_variables)]
#![allow(dead_code)]
// STRUCT
// lldb-command:print arg1
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) arg1 = 1
// lldb-command:print arg2
-// lldb-check:[...]$1 = 2
+// lldbg-check:[...]$1 = 2
+// lldbr-check:(isize) arg2 = 2
// lldb-command:continue
// ENUM
// lldb-command:print arg1
-// lldb-check:[...]$2 = -3
+// lldbg-check:[...]$2 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$3 = 4.5
+// lldbg-check:[...]$3 = 4.5
+// lldbr-check:(f64) arg2 = 4.5
// lldb-command:print arg3
-// lldb-check:[...]$4 = 5
+// lldbg-check:[...]$4 = 5
+// lldbr-check:(usize) arg3 = 5
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print three_simple_structs
-// lldb-check:[...]$0 = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } }
+// lldbg-check:[...]$0 = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } }
+// lldbr-check:(struct_in_struct::ThreeSimpleStructs) three_simple_structs = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } }
// lldb-command:print internal_padding_parent
-// lldb-check:[...]$1 = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } }
+// lldbg-check:[...]$1 = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } }
+// lldbr-check:(struct_in_struct::InternalPaddingParent) internal_padding_parent = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } }
// lldb-command:print padding_at_end_parent
-// lldb-check:[...]$2 = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } }
+// lldbg-check:[...]$2 = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } }
+// lldbr-check:(struct_in_struct::PaddingAtEndParent) padding_at_end_parent = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } }
// lldb-command:print mixed
-// lldb-check:[...]$3 = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 }
+// lldbg-check:[...]$3 = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 }
+// lldbr-check:(struct_in_struct::Mixed) mixed = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 }
// lldb-command:print bag
-// lldb-check:[...]$4 = Bag { x: Simple { x: 22 } }
+// lldbg-check:[...]$4 = Bag { x: Simple { x: 22 } }
+// lldbr-check:(struct_in_struct::Bag) bag = Bag { x: Simple { x: 22 } }
// lldb-command:print bag_in_bag
-// lldb-check:[...]$5 = BagInBag { x: Bag { x: Simple { x: 23 } } }
+// lldbg-check:[...]$5 = BagInBag { x: Bag { x: Simple { x: 23 } } }
+// lldbr-check:(struct_in_struct::BagInBag) bag_in_bag = BagInBag { x: Bag { x: Simple { x: 23 } } }
// lldb-command:print tjo
-// lldb-check:[...]$6 = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } }
+// lldbg-check:[...]$6 = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } }
+// lldbr-check:(struct_in_struct::ThatsJustOverkill) tjo = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } }
// lldb-command:print tree
-// lldb-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
+// lldbg-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
+// lldbr-check:(struct_in_struct::Tree) tree = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:p struct1
-// lldb-check:(struct_namespace::Struct1) $0 = [...]
+// lldbg-check:(struct_namespace::Struct1) $0 = [...]
+// lldbr-check:(struct_namespace::Struct1) struct1 = Struct1 { a: 0, b: 1 }
// lldb-command:p struct2
-// lldb-check:(struct_namespace::Struct2) $1 = [...]
+// lldbg-check:(struct_namespace::Struct2) $1 = [...]
+// lldbr-check:(struct_namespace::Struct2) struct2 = { = 2 }
// lldb-command:p mod1_struct1
-// lldb-check:(struct_namespace::mod1::Struct1) $2 = [...]
+// lldbg-check:(struct_namespace::mod1::Struct1) $2 = [...]
+// lldbr-check:(struct_namespace::mod1::Struct1) mod1_struct1 = Struct1 { a: 3, b: 4 }
// lldb-command:p mod1_struct2
-// lldb-check:(struct_namespace::mod1::Struct2) $3 = [...]
+// lldbg-check:(struct_namespace::mod1::Struct2) $3 = [...]
+// lldbr-check:(struct_namespace::mod1::Struct2) mod1_struct2 = { = 5 }
#![allow(unused_variables)]
#![allow(dead_code)]
// lldb-command:run
// lldb-command:print case1
-// lldb-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
+// lldbg-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
+// lldbr-check:(struct_style_enum::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 }
// lldb-command:print case2
-// lldb-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
+// lldbg-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
+// lldbr-check:(struct_style_enum::Regular::Case2) case2 = Case2 { struct_style_enum::Regular::Case1: 0, struct_style_enum::Regular::Case2: 286331153, struct_style_enum::Regular::Case3: 286331153 }
// lldb-command:print case3
-// lldb-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
+// lldbg-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
+// lldbr-check:(struct_style_enum::Regular::Case3) case3 = Case3 { struct_style_enum::Regular::Case1: 0, struct_style_enum::Regular::Case2: 6438275382588823897 }
// lldb-command:print univariant
-// lldb-check:[...]$3 = TheOnlyCase { a: -1 }
+// lldbg-check:[...]$3 = TheOnlyCase { a: -1 }
+// lldbr-check:(struct_style_enum::Univariant) univariant = Univariant { struct_style_enum::TheOnlyCase: TheOnlyCase { a: -1 } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print simple
-// lldb-check:[...]$0 = WithDestructor { x: 10, y: 20 }
+// lldbg-check:[...]$0 = WithDestructor { x: 10, y: 20 }
+// lldbr-check:(struct_with_destructor::WithDestructor) simple = WithDestructor { x: 10, y: 20 }
// lldb-command:print noDestructor
-// lldb-check:[...]$1 = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbg-check:[...]$1 = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbr-check:(struct_with_destructor::NoDestructorGuarded) noDestructor = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 }
// lldb-command:print withDestructor
-// lldb-check:[...]$2 = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbg-check:[...]$2 = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbr-check:(struct_with_destructor::WithDestructorGuarded) withDestructor = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }
// lldb-command:print nested
-// lldb-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
+// lldbg-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
+// lldbr-check:(struct_with_destructor::NestedOuter) nested = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print no_padding1
-// lldb-check:[...]$0 = ((0, 1), 2, 3)
+// lldbg-check:[...]$0 = ((0, 1), 2, 3)
+// lldbr-check:(((u32, u32), u32, u32)) no_padding1 = { = { = 0 = 1 } = 2 = 3 }
// lldb-command:print no_padding2
-// lldb-check:[...]$1 = (4, (5, 6), 7)
+// lldbg-check:[...]$1 = (4, (5, 6), 7)
+// lldbr-check:((u32, (u32, u32), u32)) no_padding2 = { = 4 = { = 5 = 6 } = 7 }
// lldb-command:print no_padding3
-// lldb-check:[...]$2 = (8, 9, (10, 11))
+// lldbg-check:[...]$2 = (8, 9, (10, 11))
+// lldbr-check:((u32, u32, (u32, u32))) no_padding3 = { = 8 = 9 = { = 10 = 11 } }
// lldb-command:print internal_padding1
-// lldb-check:[...]$3 = (12, (13, 14))
+// lldbg-check:[...]$3 = (12, (13, 14))
+// lldbr-check:((i16, (i32, i32))) internal_padding1 = { = 12 = { = 13 = 14 } }
// lldb-command:print internal_padding2
-// lldb-check:[...]$4 = (15, (16, 17))
+// lldbg-check:[...]$4 = (15, (16, 17))
+// lldbr-check:((i16, (i16, i32))) internal_padding2 = { = 15 = { = 16 = 17 } }
// lldb-command:print padding_at_end1
-// lldb-check:[...]$5 = (18, (19, 20))
+// lldbg-check:[...]$5 = (18, (19, 20))
+// lldbr-check:((i32, (i32, i16))) padding_at_end1 = { = 18 = { = 19 = 20 } }
// lldb-command:print padding_at_end2
-// lldb-check:[...]$6 = ((21, 22), 23)
+// lldbg-check:[...]$6 = ((21, 22), 23)
+// lldbr-check:(((i32, i16), i32)) padding_at_end2 = { = { = 21 = 22 } = 23 }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// lldb-command:run
// lldb-command:print no_padding16
-// lldb-check:[...]$0 = NoPadding16(10000, -10001)
+// lldbg-check:[...]$0 = NoPadding16(10000, -10001)
+// lldbr-check:(tuple_struct::NoPadding16) no_padding16 = { = 10000 = -10001 }
// lldb-command:print no_padding32
-// lldb-check:[...]$1 = NoPadding32(-10002, -10003.5, 10004)
+// lldbg-check:[...]$1 = NoPadding32(-10002, -10003.5, 10004)
+// lldbr-check:(tuple_struct::NoPadding32) no_padding32 = { = -10002 = -10003.5 = 10004 }
// lldb-command:print no_padding64
-// lldb-check:[...]$2 = NoPadding64(-10005.5, 10006, 10007)
+// lldbg-check:[...]$2 = NoPadding64(-10005.5, 10006, 10007)
+// lldbr-check:(tuple_struct::NoPadding64) no_padding64 = { = -10005.5 = 10006 = 10007 }
// lldb-command:print no_padding163264
-// lldb-check:[...]$3 = NoPadding163264(-10008, 10009, 10010, 10011)
+// lldbg-check:[...]$3 = NoPadding163264(-10008, 10009, 10010, 10011)
+// lldbr-check:(tuple_struct::NoPadding163264) no_padding163264 = { = -10008 = 10009 = 10010 = 10011 }
// lldb-command:print internal_padding
-// lldb-check:[...]$4 = InternalPadding(10012, -10013)
+// lldbg-check:[...]$4 = InternalPadding(10012, -10013)
+// lldbr-check:(tuple_struct::InternalPadding) internal_padding = { = 10012 = -10013 }
// lldb-command:print padding_at_end
-// lldb-check:[...]$5 = PaddingAtEnd(-10014, 10015)
+// lldbg-check:[...]$5 = PaddingAtEnd(-10014, 10015)
+// lldbr-check:(tuple_struct::PaddingAtEnd) padding_at_end = { = -10014 = 10015 }
// This test case mainly makes sure that no field names are generated for tuple structs (as opposed
// to all fields having the name "<unnamed_field>"). Otherwise they are handled the same a normal
// lldb-command:run
// lldb-command:print case1
-// lldb-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbr-check:(tuple_style_enum::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
// lldb-command:print case2
-// lldb-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbr-check:(tuple_style_enum::Regular::Case2) case2 = Case2 { tuple_style_enum::Regular::Case1: 0, tuple_style_enum::Regular::Case2: 286331153, tuple_style_enum::Regular::Case3: 286331153 }
// lldb-command:print case3
-// lldb-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbr-check:(tuple_style_enum::Regular::Case3) case3 = Case3 { tuple_style_enum::Regular::Case1: 0, tuple_style_enum::Regular::Case2: 6438275382588823897 }
// lldb-command:print univariant
-// lldb-check:[...]$3 = TheOnlyCase(-1)
+// lldbg-check:[...]$3 = TheOnlyCase(-1)
+// lldbr-check:(tuple_style_enum::Univariant) univariant = { tuple_style_enum::TheOnlyCase = { = -1 } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print u
-// lldb-check:[...]$0 = U { a: ('\x02', '\x02'), b: 514 }
-// lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = U { a: ('\x01', '\x01'), b: 257 }
+// lldbg-check:[...]$0 = U { a: ('\x02', '\x02'), b: 514 }
+// lldbr-check:(union_smoke::U) u = { a = { = 2 = 2 } b = 514 }
+
+// Don't test this with rust-enabled lldb for now; see
+// https://github.com/rust-lang-nursery/lldb/issues/18
+// lldbg-command:print union_smoke::SU
+// lldbg-check:[...]$1 = U { a: ('\x01', '\x01'), b: 257 }
#![allow(unused)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *the_a
-// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbr-check:(unique_enum::ABC::TheA) *the_a = TheA { unique_enum::ABC::TheA: 0, unique_enum::ABC::TheB: 8970181431921507452 }
// lldb-command:print *the_b
-// lldb-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbr-check:(unique_enum::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 }
// lldb-command:print *univariant
-// lldb-check:[...]$2 = TheOnlyCase(123234)
+// lldbg-check:[...]$2 = TheOnlyCase(123234)
+// lldbr-check:(unique_enum::Univariant) *univariant = { unique_enum::TheOnlyCase = { = 123234 } }
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print variable
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) variable = 1
// lldb-command:print constant
-// lldb-check:[...]$1 = 2
+// lldbg-check:[...]$1 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$4 = 6
+// lldbg-check:[...]$4 = 6
+// lldbr-check:(isize) *owned = 6
// lldb-command:print closure_local
-// lldb-check:[...]$5 = 8
+// lldbg-check:[...]$5 = 8
+// lldbr-check:(isize) closure_local = 8
// lldb-command:continue
// lldb-command:print variable
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(isize) variable = 1
// lldb-command:print constant
-// lldb-check:[...]$7 = 2
+// lldbg-check:[...]$7 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$9 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$9 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$10 = 6
+// lldbg-check:[...]$10 = 6
+// lldbr-check:(isize) *owned = 6
// lldb-command:print closure_local
-// lldb-check:[...]$11 = 8
+// lldbg-check:[...]$11 = 8
+// lldbr-check:(isize) closure_local = 8
// lldb-command:continue
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print constant
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) constant = 1
// lldb-command:print a_struct
-// lldb-check:[...]$1 = Struct { a: -2, b: 3.5, c: 4 }
+// lldbg-check:[...]$1 = Struct { a: -2, b: 3.5, c: 4 }
+// lldbr-check:(var_captured_in_sendable_closure::Struct) a_struct = Struct { a: -2, b: 3.5, c: 4 }
// lldb-command:print *owned
-// lldb-check:[...]$2 = 5
+// lldbg-check:[...]$2 = 5
+// lldbr-check:(isize) *owned = 5
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print variable
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) variable = 1
// lldb-command:print constant
-// lldb-check:[...]$1 = 2
+// lldbg-check:[...]$1 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$4 = 6
+// lldbg-check:[...]$4 = 6
+// lldbr-check:(isize) *owned = 6
// lldb-command:continue
// lldb-command:print variable
-// lldb-check:[...]$5 = 2
+// lldbg-check:[...]$5 = 2
+// lldbr-check:(isize) variable = 2
// lldb-command:print constant
-// lldb-check:[...]$6 = 2
+// lldbg-check:[...]$6 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$7 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$7 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$9 = 6
+// lldbg-check:[...]$9 = 6
+// lldbr-check:(isize) *owned = 6
#![feature(box_syntax)]
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// ignore-windows
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// min-lldb-version: 310
// lldb-command:run
// lldb-command:print empty
-// lldb-check:[...]$0 = &[]
+// lldbg-check:[...]$0 = &[]
+// lldbr-check:(&[i64]) empty = &[]
// lldb-command:print singleton
-// lldb-check:[...]$1 = &[1]
+// lldbg-check:[...]$1 = &[1]
+// lldbr-check:(&[i64]) singleton = &[1]
// lldb-command:print multiple
-// lldb-check:[...]$2 = &[2, 3, 4, 5]
+// lldbg-check:[...]$2 = &[2, 3, 4, 5]
+// lldbr-check:(&[i64]) multiple = &[2, 3, 4, 5]
// lldb-command:print slice_of_slice
-// lldb-check:[...]$3 = &[3, 4]
+// lldbg-check:[...]$3 = &[3, 4]
+// lldbr-check:(&[i64]) slice_of_slice = &[3, 4]
// lldb-command:print padded_tuple
-// lldb-check:[...]$4 = &[(6, 7), (8, 9)]
+// lldbg-check:[...]$4 = &[(6, 7), (8, 9)]
+// lldbr-check:(&[(i32, i16)]) padded_tuple = { data_ptr = *0x555555554ff0 length = 2 }
// lldb-command:print padded_struct
-// lldb-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
+// lldbg-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
+// lldbr-check:(&[vec_slices::AStruct]) padded_struct = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
#![allow(dead_code, unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = [1, 2, 3]
+// lldbg-check:[...]$0 = [1, 2, 3]
+// lldbr-check:([i32; 3]) a = [1, 2, 3]
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes
-#![feature(min_const_fn)]
-
static TEST_SIGNED: i128 = const_signed(-222);
static TEST_UNSIGNED: u128 = const_unsigned(200);
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -O
-#![feature(min_const_fn)]
-
static TEST_SIGNED: i128 = const_signed(-222);
static TEST_UNSIGNED: u128 = const_unsigned(200);
// error-pattern:index out of bounds: the len is 5 but the index is 5
-#![feature(min_const_fn)]
const fn test(x: usize) -> i32 {
[42;5][x]
}
-#![feature(min_const_fn, rustc_attrs, rustc_private, step_trait)]
+#![feature(rustc_attrs, rustc_private, step_trait)]
#[macro_use] extern crate rustc_data_structures;
extern crate rustc_serialize;
async_closure,
async_fn,
async_fn_with_internal_borrow,
+ Foo::async_method,
|x| {
async move {
unsafe { await!(unsafe_async_fn(x)) }
// Crate that exports a const fn. Used for testing cross-crate.
#![crate_type="rlib"]
-#![feature(min_const_fn)]
pub const fn foo() -> usize { 22 }
// run-pass
#![allow(dead_code)]
-#![feature(min_const_fn)]
const fn add(x: usize, y: usize) -> usize {
x + y
// except according to those terms.
// run-pass
-#![feature(min_const_fn)]
struct Foo { value: u32 }
// run-pass
// Test a call whose argument is the result of another call.
-#![feature(min_const_fn)]
-
const fn sub(x: u32, y: u32) -> u32 {
x - y
}
// run-pass
-#![feature(min_const_fn)]
-
struct A;
impl A {
// run-pass
#![allow(unreachable_patterns)]
-#![feature(min_const_fn)]
#[derive(PartialEq, Eq)]
enum Cake {
// run-pass
#![allow(dead_code)]
-#![feature(min_const_fn)]
use std::mem;
#![allow(dead_code)]
// A quick test of 'unsafe const fn' functionality
-#![feature(min_const_fn)]
-
const unsafe fn dummy(v: u32) -> u32 {
!v
}
// except according to those terms.
// run-pass
-#![feature(min_const_fn)]
const FOO: isize = 10;
const BAR: isize = 3;
// https://github.com/rust-lang/rust/issues/48279
-#![feature(min_const_fn)]
-
#[derive(PartialEq, Eq)]
pub struct NonZeroU32 {
value: u32
// https://github.com/rust-lang/rust/issues/46114
-#![feature(min_const_fn)]
-
#[derive(Eq, PartialEq)]
struct A { value: u32 }
// https://github.com/rust-lang/rust/issues/43754
-#![feature(min_const_fn)]
const fn foo(x: usize) -> usize {
return x;
}
+++ /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.
-
-// run-pass
-
-fn main() {}
-
-fn foo() -> impl std::fmt::Debug { "cake" }
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// run-pass
-
-use std::iter::once;
-
-struct Foo {
- x: i32,
-}
-
-impl Foo {
- fn inside(&self) -> impl Iterator<Item = &i32> {
- once(&self.x)
- }
-}
-
-fn main() {
- println!("hi");
-}
+++ /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.
-
-// run-pass
-
-// Tests for nested self-reference which caused a stack overflow.
-
-use std::fmt::Debug;
-use std::ops::*;
-
-fn gen() -> impl PartialOrd + PartialEq + Debug { }
-
-struct Bar {}
-trait Foo<T = Self> {}
-impl Foo for Bar {}
-
-fn foo() -> impl Foo {
- Bar {}
-}
-
-fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 }
-fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 }
-
-fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
#![crate_type = "lib"]
const fn foo(i: i32) -> i32 {
// run-pass
#![allow(dead_code)]
-#![feature(min_const_fn)]
struct A {
field: usize,
}
// except according to those terms.
// run-pass
-#![feature(min_const_fn)]
const fn foo() -> *const i8 {
b"foo" as *const _ as *const i8
// except according to those terms.
// run-pass
-#![feature(min_const_fn)]
const fn foo() -> i64 {
3
+++ /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.
-
-// run-pass
-fn iter<'a>(data: &'a [usize]) -> impl Iterator<Item = usize> + 'a {
- data.iter()
- .map(
- |x| x // fn(&'a usize) -> &'(ReScope) usize
- )
- .map(
- |x| *x // fn(&'(ReScope) usize) -> usize
- )
-}
-
-fn main() {
-}
// run-pass
#![allow(dead_code)]
-#![feature(min_const_fn)]
const fn f() -> usize {
5
}
--- /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 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// run-pass
-// #39665
-
-fn batches(n: &u32) -> impl Iterator<Item=&u32> {
- std::iter::once(n)
-}
-
-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.
+
+// 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)
+
// compile-flags: -Cmetadata=aux
-#![feature(min_const_fn)]
-
pub const fn foo() {}
pub const unsafe fn bar() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
#![crate_name = "foo"]
// @has foo/fn.bar.html
#![crate_type="lib"]
-#![feature(min_const_fn)]
-
pub struct Foo;
impl Foo {
// 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) {}
-}
LL | *y = 1;
| ------ first borrow later used here
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
--> $DIR/borrowck-describe-lvalue.rs:305:16
|
LL | || {
- | --
- | ||
- | |return type of closure is [closure@$DIR/borrowck-describe-lvalue.rs:305:16: 311:18 x:&'2 mut i32]
- | lifetime `'1` represents this closure's body
-LL | / || { //[mir]~ ERROR unsatisfied lifetime constraints
+ | - inferred to be a `FnMut` closure
+LL | / || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body
LL | | let y = &mut x;
LL | | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
LL | | *y = 1;
LL | | drop(y);
LL | | }
- | |_________________^ returning this value requires that `'1` must outlive `'2`
+ | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
- = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
error[E0503]: cannot use `f.x` because it was mutably borrowed
--> $DIR/borrowck-describe-lvalue.rs:53:9
LL | *y = 1;
| ------ first borrow later used here
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
--> $DIR/borrowck-describe-lvalue.rs:305:16
|
LL | || {
- | --
- | ||
- | |return type of closure is [closure@$DIR/borrowck-describe-lvalue.rs:305:16: 311:18 x:&'2 mut i32]
- | lifetime `'1` represents this closure's body
-LL | / || { //[mir]~ ERROR unsatisfied lifetime constraints
+ | - inferred to be a `FnMut` closure
+LL | / || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body
LL | | let y = &mut x;
LL | | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
LL | | *y = 1;
LL | | drop(y);
LL | | }
- | |_________________^ returning this value requires that `'1` must outlive `'2`
+ | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
- = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
error[E0503]: cannot use `f.x` because it was mutably borrowed
--> $DIR/borrowck-describe-lvalue.rs:53:9
// FIXME(#49824) -- the free region error below should probably not be there
let mut x = 0;
|| {
- || { //[mir]~ ERROR unsatisfied lifetime constraints
+ || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body
let y = &mut x;
&mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
//[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
-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
error[E0507]: cannot move out of borrowed content
- --> $DIR/move-in-static-initializer-issue-38520.rs:27:23
+ --> $DIR/move-in-static-initializer-issue-38520.rs:25:23
|
LL | static Y: usize = get(*&X); //[ast]~ ERROR E0507
| ^^^ cannot move out of borrowed content
error[E0507]: cannot move out of borrowed content
- --> $DIR/move-in-static-initializer-issue-38520.rs:29:22
+ --> $DIR/move-in-static-initializer-issue-38520.rs:27:22
|
LL | const Z: usize = get(*&X); //[ast]~ ERROR E0507
| ^^^ cannot move out of borrowed content
error[E0507]: cannot move out of borrowed content
- --> $DIR/move-in-static-initializer-issue-38520.rs:27:23
+ --> $DIR/move-in-static-initializer-issue-38520.rs:25:23
|
LL | static Y: usize = get(*&X); //[ast]~ ERROR E0507
| ^^^ cannot move out of borrowed content
error[E0507]: cannot move out of borrowed content
- --> $DIR/move-in-static-initializer-issue-38520.rs:29:22
+ --> $DIR/move-in-static-initializer-issue-38520.rs:27:22
|
LL | const Z: usize = get(*&X); //[ast]~ ERROR E0507
| ^^^ cannot move out of borrowed content
// permitted as `Foo` is not copy (even in a static/const
// initializer).
-#![feature(min_const_fn)]
-
struct Foo(usize);
const fn get(x: Foo) -> usize {
+++ /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
+
// Crate that exports a const fn. Used for testing cross-crate.
#![crate_type="rlib"]
-#![feature(min_const_fn)]
pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable
--> $DIR/const-pointer-values-in-various-types.rs:24:5
|
LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type usize
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:36:5
|
LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type u64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:51:5
|
LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type i64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:60:5
|
LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type f64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:78:5
|
LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type u64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:93:5
|
LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type i64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:102:5
|
LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type f64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
#![warn(const_err)]
-#![feature(min_const_fn)]
-
const fn foo(x: u32) -> u32 {
x
}
warning: this constant cannot be used
- --> $DIR/issue-43197.rs:20:5
+ --> $DIR/issue-43197.rs:18:5
|
LL | const X: u32 = 0-1;
| ^^^^^^^^^^^^^^^---^
| ^^^^^^^^^
warning: this constant cannot be used
- --> $DIR/issue-43197.rs:22:5
+ --> $DIR/issue-43197.rs:20:5
|
LL | const Y: u32 = foo(0-1);
| ^^^^^^^^^^^^^^^^^^^---^^
| attempt to subtract with overflow
error[E0080]: referenced constant has errors
- --> $DIR/issue-43197.rs:24:26
+ --> $DIR/issue-43197.rs:22:26
|
LL | const Y: u32 = foo(0-1);
| --- attempt to subtract with overflow
| ^
error[E0080]: erroneous constant used
- --> $DIR/issue-43197.rs:24:26
+ --> $DIR/issue-43197.rs:22:26
|
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
error[E0080]: referenced constant has errors
- --> $DIR/issue-43197.rs:24:23
+ --> $DIR/issue-43197.rs:22:23
|
LL | const X: u32 = 0-1;
| --- attempt to subtract with overflow
| ^
error[E0080]: erroneous constant used
- --> $DIR/issue-43197.rs:24:23
+ --> $DIR/issue-43197.rs:22:23
|
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
// compile-pass
-#![feature(min_const_fn)]
-
struct S(pub &'static u32, pub u32);
const fn g(ss: &S) -> &u32 { &ss.1 }
static FOO: bool = unsafe { mem::transmute(3u8) };
//~^ ERROR this static likely exhibits undefined behavior
-//~^^ type validation failed: encountered 3, but expected something in the range 0..=1
fn main() {}
--> $DIR/ub-enum.rs:45:1
|
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered character at .Some.0.1, but expected a valid unicode codepoint
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--- /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.
+
+#![feature(const_transmute)]
+
+use std::mem;
+use std::ptr::NonNull;
+use std::num::{NonZeroU8, NonZeroUsize};
+
+const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+//~^ ERROR this constant likely exhibits undefined behavior
+const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+fn main() {}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-nonnull.rs:17:1
+ |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-nonnull.rs:20:1
+ |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-nonnull.rs:22:1
+ |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /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.
+
+#![feature(const_transmute)]
+
+use std::mem;
+
+const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const NULL: &u16 = unsafe { mem::transmute(0usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+fn main() {}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:15:1
+ |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:18:1
+ |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:21:1
+ |
+LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:24:1
+ |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-union Foo {
- a: u8,
- b: Bar,
-}
+#![feature(const_transmute)]
+
+use std::mem;
#[derive(Copy, Clone)]
enum Bar {}
-const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b};
+const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
//~^ ERROR this constant likely exhibits undefined behavior
fn main() {
error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/ub-uninhabit.rs:19:1
+ --> $DIR/ub-uninhabit.rs:18:1
|
-LL | const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
+LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-error: aborting due to previous error
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-uninhabit.rs:21:1
+ |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-uninhabit.rs:24:1
+ |
+LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at [0]
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0080`.
+++ /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
-
-union Foo {
- a: &'static u8,
- b: usize,
-}
-
-// This might point to an invalid address, but that's the user's problem
-const USIZE_AS_STATIC_REF: &'static u8 = unsafe { Foo { b: 1337 }.a};
-
-fn main() {
-}
LL | | a: 42,
LL | | b: unsafe { UNION.field3 },
LL | | };
- | |__^ type validation failed: encountered undefined bytes at .b
+ | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--- /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.
+
+#![allow(unused)]
+
+// normalize-stderr-test "alignment \d+" -> "alignment N"
+// normalize-stderr-test "offset \d+" -> "offset N"
+// normalize-stderr-test "allocation \d+" -> "allocation N"
+// normalize-stderr-test "size \d+" -> "size N"
+
+union BoolTransmute {
+ val: u8,
+ bl: bool,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct SliceRepr {
+ ptr: *const u8,
+ len: usize,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct BadSliceRepr {
+ ptr: *const u8,
+ len: &'static u8,
+}
+
+union SliceTransmute {
+ repr: SliceRepr,
+ bad: BadSliceRepr,
+ slice: &'static [u8],
+ str: &'static str,
+ my_str: &'static MyStr,
+ my_slice: &'static MySliceBool,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct DynRepr {
+ ptr: *const u8,
+ vtable: *const u8,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct DynRepr2 {
+ ptr: *const u8,
+ vtable: *const u64,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct BadDynRepr {
+ ptr: *const u8,
+ vtable: usize,
+}
+
+union DynTransmute {
+ repr: DynRepr,
+ repr2: DynRepr2,
+ bad: BadDynRepr,
+ rust: &'static Trait,
+}
+
+trait Trait {}
+impl Trait for bool {}
+
+// custom unsized type
+struct MyStr(str);
+
+// custom unsized type with sized fields
+struct MySlice<T: ?Sized>(bool, T);
+type MySliceBool = MySlice<[bool]>;
+
+// OK
+const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
+// bad str
+const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad str
+const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad str in user-defined unsized type
+const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// OK
+const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice};
+// bad slice
+const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad slice
+const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// bad trait object
+const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad trait object
+const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad trait object
+const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// bad data *inside* the trait object
+const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad data *inside* the slice
+const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// good MySliceBool
+const I1: &MySliceBool = &MySlice(true, [false]);
+// bad: sized field is not okay
+const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad: unsized part is not okay
+const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// invalid UTF-8
+const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
+//~^ ERROR this constant likely exhibits undefined behavior
+// invalid UTF-8 in user-defined str-like
+const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+fn main() {
+}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:87:1
+ |
+LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:90:1
+ |
+LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:93:1
+ |
+LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:99:1
+ |
+LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:102:1
+ |
+LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:106:1
+ |
+LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:109:1
+ |
+LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:112:1
+ |
+LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:116:1
+ |
+LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:119:1
+ |
+LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:125:1
+ |
+LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:128:1
+ |
+LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:132:1
+ |
+LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:135:1
+ |
+LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo };
-fn main() {
-}
+fn main() {}
--- /dev/null
+// compile-pass
+
+// Some constants that *are* valid
+#![feature(const_transmute)]
+
+use std::mem;
+use std::ptr::NonNull;
+use std::num::{NonZeroU8, NonZeroUsize};
+
+const NON_NULL_PTR1: NonNull<u8> = unsafe { mem::transmute(1usize) };
+const NON_NULL_PTR2: NonNull<u8> = unsafe { mem::transmute(&0) };
+
+const NON_NULL_U8: NonZeroU8 = unsafe { mem::transmute(1u8) };
+const NON_NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(1usize) };
+
+const UNIT: () = ();
+
+fn main() {}
// compile-pass
-#![feature(min_const_fn)]
-
#[derive(PartialEq, Eq)]
enum Cake {
BlackForest,
--- /dev/null
+const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable
+ x == y
+}
+
+fn main() {}
--- /dev/null
+error: function pointers in const fn are unstable
+ --> $DIR/cmp_fn_pointers.rs:1:14
+ |
+LL | const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable
+ | ^
+
+error: aborting due to previous error
+
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:49:25
+ --> $DIR/min_const_fn.rs:47:25
|
LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:51:36
+ --> $DIR/min_const_fn.rs:49:36
|
LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:56:28
+ --> $DIR/min_const_fn.rs:54:28
|
LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:58:42
+ --> $DIR/min_const_fn.rs:56:42
|
LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:63:27
+ --> $DIR/min_const_fn.rs:61:27
|
LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:65:38
+ --> $DIR/min_const_fn.rs:63:38
|
LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:70:39
+ --> $DIR/min_const_fn.rs:68:39
|
LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:88:16
+ --> $DIR/min_const_fn.rs:86:16
|
LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:90:18
+ --> $DIR/min_const_fn.rs:88:18
|
LL | const fn foo11_2<T: Send>(t: T) -> T { t }
| ^
error: only int, `bool` and `char` operations are stable in const fn
- --> $DIR/min_const_fn.rs:92:33
+ --> $DIR/min_const_fn.rs:90:33
|
LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
| ^^^^^^^
error: only int, `bool` and `char` operations are stable in const fn
- --> $DIR/min_const_fn.rs:94:35
+ --> $DIR/min_const_fn.rs:92:35
|
LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
| ^^^^^^^
error: only int and `bool` operations are stable in const fn
- --> $DIR/min_const_fn.rs:96:35
+ --> $DIR/min_const_fn.rs:94:35
|
LL | const fn foo19_3(f: f32) -> f32 { -f }
| ^^
error: only int, `bool` and `char` operations are stable in const fn
- --> $DIR/min_const_fn.rs:98:43
+ --> $DIR/min_const_fn.rs:96:43
|
LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
| ^^^^^
error: cannot access `static` items in const fn
- --> $DIR/min_const_fn.rs:102:27
+ --> $DIR/min_const_fn.rs:100:27
|
LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
| ^^^
error: cannot access `static` items in const fn
- --> $DIR/min_const_fn.rs:103:36
+ --> $DIR/min_const_fn.rs:101:36
|
LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
| ^^^^
error: casting pointers to ints is unstable in const fn
- --> $DIR/min_const_fn.rs:104:42
+ --> $DIR/min_const_fn.rs:102:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
error: casting pointers to ints is unstable in const fn
- --> $DIR/min_const_fn.rs:106:42
+ --> $DIR/min_const_fn.rs:104:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:108:38
+ --> $DIR/min_const_fn.rs:106:38
|
LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
| ^^^^^^^^^^^^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:110:29
+ --> $DIR/min_const_fn.rs:108:29
|
LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^^
error: local variables in const fn are unstable
- --> $DIR/min_const_fn.rs:111:34
+ --> $DIR/min_const_fn.rs:109:34
|
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
| ^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:112:44
+ --> $DIR/min_const_fn.rs:110:44
|
LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
| ^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:114:44
+ --> $DIR/min_const_fn.rs:112:44
|
LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
| ^^^^^^
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:116:14
+ --> $DIR/min_const_fn.rs:114:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:121:6
+ --> $DIR/min_const_fn.rs:119:6
|
LL | impl<T: std::fmt::Debug> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:126:6
+ --> $DIR/min_const_fn.rs:124:6
|
LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:131:6
+ --> $DIR/min_const_fn.rs:129:6
|
LL | impl<T: Sync + Sized> Foo<T> {
| ^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:137:24
+ --> $DIR/min_const_fn.rs:135:24
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:139:34
+ --> $DIR/min_const_fn.rs:137:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:141:22
+ --> $DIR/min_const_fn.rs:139:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^^^^^^^^^^^^^^^^^^^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:142:23
+ --> $DIR/min_const_fn.rs:140:23
|
LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:143:23
+ --> $DIR/min_const_fn.rs:141:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:144:32
+ --> $DIR/min_const_fn.rs:142:32
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0716]: temporary value dropped while borrowed
- --> $DIR/min_const_fn.rs:144:64
+ --> $DIR/min_const_fn.rs:142:64
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^ - temporary value is freed at the end of this statement
= note: borrowed value must be valid for the static lifetime...
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:149:41
+ --> $DIR/min_const_fn.rs:147:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:152:21
+ --> $DIR/min_const_fn.rs:150:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:154:27
+ --> $DIR/min_const_fn.rs:152:27
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
-
// ok
const fn foo1() {}
const fn foo2(x: i32) -> i32 { x }
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:49:25
+ --> $DIR/min_const_fn.rs:47:25
|
LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:51:36
+ --> $DIR/min_const_fn.rs:49:36
|
LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:56:28
+ --> $DIR/min_const_fn.rs:54:28
|
LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:58:42
+ --> $DIR/min_const_fn.rs:56:42
|
LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:63:27
+ --> $DIR/min_const_fn.rs:61:27
|
LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:65:38
+ --> $DIR/min_const_fn.rs:63:38
|
LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:70:39
+ --> $DIR/min_const_fn.rs:68:39
|
LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:88:16
+ --> $DIR/min_const_fn.rs:86:16
|
LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:90:18
+ --> $DIR/min_const_fn.rs:88:18
|
LL | const fn foo11_2<T: Send>(t: T) -> T { t }
| ^
error: only int, `bool` and `char` operations are stable in const fn
- --> $DIR/min_const_fn.rs:92:33
+ --> $DIR/min_const_fn.rs:90:33
|
LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
| ^^^^^^^
error: only int, `bool` and `char` operations are stable in const fn
- --> $DIR/min_const_fn.rs:94:35
+ --> $DIR/min_const_fn.rs:92:35
|
LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
| ^^^^^^^
error: only int and `bool` operations are stable in const fn
- --> $DIR/min_const_fn.rs:96:35
+ --> $DIR/min_const_fn.rs:94:35
|
LL | const fn foo19_3(f: f32) -> f32 { -f }
| ^^
error: only int, `bool` and `char` operations are stable in const fn
- --> $DIR/min_const_fn.rs:98:43
+ --> $DIR/min_const_fn.rs:96:43
|
LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
| ^^^^^
error: cannot access `static` items in const fn
- --> $DIR/min_const_fn.rs:102:27
+ --> $DIR/min_const_fn.rs:100:27
|
LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
| ^^^
error: cannot access `static` items in const fn
- --> $DIR/min_const_fn.rs:103:36
+ --> $DIR/min_const_fn.rs:101:36
|
LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
| ^^^^
error: casting pointers to ints is unstable in const fn
- --> $DIR/min_const_fn.rs:104:42
+ --> $DIR/min_const_fn.rs:102:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
error: casting pointers to ints is unstable in const fn
- --> $DIR/min_const_fn.rs:106:42
+ --> $DIR/min_const_fn.rs:104:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:108:38
+ --> $DIR/min_const_fn.rs:106:38
|
LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
| ^^^^^^^^^^^^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:110:29
+ --> $DIR/min_const_fn.rs:108:29
|
LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^^
error: local variables in const fn are unstable
- --> $DIR/min_const_fn.rs:111:34
+ --> $DIR/min_const_fn.rs:109:34
|
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
| ^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:112:44
+ --> $DIR/min_const_fn.rs:110:44
|
LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
| ^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:114:44
+ --> $DIR/min_const_fn.rs:112:44
|
LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
| ^^^^^^
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:116:14
+ --> $DIR/min_const_fn.rs:114:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:121:6
+ --> $DIR/min_const_fn.rs:119:6
|
LL | impl<T: std::fmt::Debug> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:126:6
+ --> $DIR/min_const_fn.rs:124:6
|
LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:131:6
+ --> $DIR/min_const_fn.rs:129:6
|
LL | impl<T: Sync + Sized> Foo<T> {
| ^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:137:24
+ --> $DIR/min_const_fn.rs:135:24
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:139:34
+ --> $DIR/min_const_fn.rs:137:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:141:22
+ --> $DIR/min_const_fn.rs:139:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^^^^^^^^^^^^^^^^^^^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:142:23
+ --> $DIR/min_const_fn.rs:140:23
|
LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:143:23
+ --> $DIR/min_const_fn.rs:141:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:144:32
+ --> $DIR/min_const_fn.rs:142:32
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:149:41
+ --> $DIR/min_const_fn.rs:147:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:152:21
+ --> $DIR/min_const_fn.rs:150:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:154:27
+ --> $DIR/min_const_fn.rs:152:27
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn_dyn.rs:21:5
+ --> $DIR/min_const_fn_dyn.rs:19:5
|
LL | x.0.field;
| ^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn_dyn.rs:24:66
+ --> $DIR/min_const_fn_dyn.rs:22:66
|
LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
| ^^
error[E0716]: temporary value dropped while borrowed
- --> $DIR/min_const_fn_dyn.rs:24:67
+ --> $DIR/min_const_fn_dyn.rs:22:67
|
LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
| ^ - temporary value is freed at the end of this statement
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
-
struct HasDyn {
field: &'static dyn std::fmt::Debug,
}
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn_dyn.rs:21:5
+ --> $DIR/min_const_fn_dyn.rs:19:5
|
LL | x.0.field;
| ^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn_dyn.rs:24:66
+ --> $DIR/min_const_fn_dyn.rs:22:66
|
LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
| ^^
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
-
struct HasPtr {
field: fn(),
}
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn_fn_ptr.rs:23:5
+ --> $DIR/min_const_fn_fn_ptr.rs:21:5
|
LL | x.0.field;
| ^^^^^^^^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn_fn_ptr.rs:26:59
+ --> $DIR/min_const_fn_fn_ptr.rs:24:59
|
LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
| ^^^^^
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(integer_atomics, min_const_fn)]
+#![feature(integer_atomics)]
// compile-pass
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(min_const_fn)]
-
// ok
const unsafe fn foo4() -> i32 { 42 }
const unsafe fn foo5<T>() -> *const T { 0 as *const T }
error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
- --> $DIR/min_const_fn_unsafe.rs:29:51
+ --> $DIR/min_const_fn_unsafe.rs:27:51
|
LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
| ^^
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
error[E0658]: unions in const fn are unstable (see issue #51909)
- --> $DIR/min_const_fn_unsafe.rs:36:5
+ --> $DIR/min_const_fn_unsafe.rs:34:5
|
LL | Foo { x: () }.y //~ ERROR not allowed in const fn
| ^^^^^^^^^^^^^^^
= help: add #![feature(const_fn_union)] to the crate attributes to enable
error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
- --> $DIR/min_const_fn_unsafe.rs:21:14
+ --> $DIR/min_const_fn_unsafe.rs:19:14
|
LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
| ^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
- --> $DIR/min_const_fn_unsafe.rs:24:14
+ --> $DIR/min_const_fn_unsafe.rs:22:14
|
LL | unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
| ^^^^^^^^^^^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
- --> $DIR/min_const_fn_unsafe.rs:27:14
+ --> $DIR/min_const_fn_unsafe.rs:25:14
|
LL | unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
- --> $DIR/min_const_fn_unsafe.rs:29:51
+ --> $DIR/min_const_fn_unsafe.rs:27:51
|
LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
| ^^ dereference of raw pointer
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: access to union field is unsafe and unsafe operations are not allowed in const fn
- --> $DIR/min_const_fn_unsafe.rs:36:5
+ --> $DIR/min_const_fn_unsafe.rs:34:5
|
LL | Foo { x: () }.y //~ ERROR not allowed in const fn
| ^^^^^^^^^^^^^^^ access to union field
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promotion.rs:13:27
+ --> $DIR/promotion.rs:11:27
|
LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promotion.rs:14:28
+ --> $DIR/promotion.rs:12:28
|
LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
| ^^^^^^^^ creates a temporary which is freed while still in use
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promotion.rs:15:28
+ --> $DIR/promotion.rs:13:28
|
LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promotion.rs:16:34
+ --> $DIR/promotion.rs:14:34
|
LL | let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promotion.rs:17:42
+ --> $DIR/promotion.rs:15:42
|
LL | let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promotion.rs:18:42
+ --> $DIR/promotion.rs:16:42
|
LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
-#![feature(min_const_fn)]
-
use std::cell::Cell;
const fn foo1() {}
error[E0597]: borrowed value does not live long enough
- --> $DIR/promotion.rs:13:27
+ --> $DIR/promotion.rs:11:27
|
LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough
| ^^^^^^ temporary value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/promotion.rs:14:28
+ --> $DIR/promotion.rs:12:28
|
LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
| ^^^^^^^^ temporary value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/promotion.rs:15:28
+ --> $DIR/promotion.rs:13:28
|
LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
| ^^^^^^ temporary value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/promotion.rs:16:34
+ --> $DIR/promotion.rs:14:34
|
LL | let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
| ^^^^^^ temporary value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/promotion.rs:17:42
+ --> $DIR/promotion.rs:15:42
|
LL | let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
| ^^^^^^ temporary value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/promotion.rs:18:42
+ --> $DIR/promotion.rs:16:42
|
LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
| ^^^^^^ temporary value does not live long enough
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-2.rs:17:9
|
+LL | s: &'a String
+ | ---------- help: consider changing this to be mutable: `&'a mut String`
+...
LL | self.s.push('x');
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-3.rs:17:9
|
+LL | s: &'a String
+ | ---------- help: consider changing this to be mutable: `&'a mut String`
+...
LL | self.s.push('x');
| ^^^^^^ cannot borrow as mutable
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// normalize-stderr-test: "The system cannot find the file specified\." -> "No such file or directory"
-// ignore-tidy-linelength
+// normalize-stderr-test: "not-a-file.md:.*\(" -> "not-a-file.md: $$FILE_NOT_FOUND_MSG ("
#![feature(external_doc)]
-error: couldn't read $DIR/not-a-file.md: No such file or directory (os error 2)
- --> $DIR/external-doc-error.rs:16:1
+error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
+ --> $DIR/external-doc-error.rs:5:1
|
LL | #[doc(include = "not-a-file.md")] //~ ERROR: couldn't read
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /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() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test use of const fn without the `const_fn` feature gate.
-// `min_const_fn` is checked in its own file
-#![feature(min_const_fn)]
+// Test use of advanced const fn without the `const_fn` feature gate.
const fn foo() -> usize { 0 } // ok
error[E0379]: trait fns cannot be declared const
- --> $DIR/feature-gate-const_fn.rs:18:5
+ --> $DIR/feature-gate-const_fn.rs:16:5
|
LL | const fn foo() -> u32; //~ ERROR const fn is unstable
| ^^^^^ trait fns cannot be const
error[E0379]: trait fns cannot be declared const
- --> $DIR/feature-gate-const_fn.rs:20:5
+ --> $DIR/feature-gate-const_fn.rs:18:5
|
LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^ trait fns cannot be const
error[E0379]: trait fns cannot be declared const
- --> $DIR/feature-gate-const_fn.rs:29:5
+ --> $DIR/feature-gate-const_fn.rs:27:5
|
LL | const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
| ^^^^^ trait fns cannot be const
error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:18:5
+ --> $DIR/feature-gate-const_fn.rs:16:5
|
LL | const fn foo() -> u32; //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(const_fn)] to the crate attributes to enable
error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:20:5
+ --> $DIR/feature-gate-const_fn.rs:18:5
|
LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test use of min_const_fn without feature gate.
-const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+const fn foo() -> usize { 0 } // stabilized
trait Foo {
const fn foo() -> u32; //~ ERROR const fn is unstable
}
impl Foo {
- const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+ const fn baz() -> u32 { 0 } // stabilized
}
impl Foo for u32 {
- const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
- //~| ERROR trait fns cannot be declared const
+ const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
}
static FOO: usize = foo();
error[E0379]: trait fns cannot be declared const
--> $DIR/feature-gate-min_const_fn.rs:27:5
|
-LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+LL | const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
| ^^^^^ trait fns cannot be const
-error[E0658]: const fn is unstable (see issue #53555)
- --> $DIR/feature-gate-min_const_fn.rs:13:1
- |
-LL | const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(min_const_fn)] to the crate attributes to enable
-
error[E0658]: const fn is unstable (see issue #24111)
--> $DIR/feature-gate-min_const_fn.rs:16:5
|
|
= help: add #![feature(const_fn)] to the crate attributes to enable
-error[E0658]: const fn is unstable (see issue #53555)
- --> $DIR/feature-gate-min_const_fn.rs:23:5
- |
-LL | const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(min_const_fn)] to the crate attributes to enable
-
-error[E0658]: const fn is unstable (see issue #53555)
- --> $DIR/feature-gate-min_const_fn.rs:27:5
- |
-LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(min_const_fn)] to the crate attributes to enable
-
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
Some errors occurred: E0379, E0658.
For more information about an error, try `rustc --explain E0379`.
+++ /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.
+
+// compile-pass
+
+fn main() {}
+
+fn foo() -> impl std::fmt::Debug { "cake" }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+use std::iter::once;
+
+struct Foo {
+ x: i32,
+}
+
+impl Foo {
+ fn inside(&self) -> impl Iterator<Item = &i32> {
+ once(&self.x)
+ }
+}
+
+fn main() {
+ println!("hi");
+}
--- /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
+
+// Tests for nested self-reference which caused a stack overflow.
+
+use std::fmt::Debug;
+use std::ops::*;
+
+fn gen() -> impl PartialOrd + PartialEq + Debug { }
+
+struct Bar {}
+trait Foo<T = Self> {}
+impl Foo for Bar {}
+
+fn foo() -> impl Foo {
+ Bar {}
+}
+
+fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 }
+fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 }
+
+fn main() {}
//https://github.com/rust-lang/rust/issues/31364
-#![feature(min_const_fn)]
const fn a() -> usize { b() }
const fn b() -> usize { a() }
const ARR: [i32; a()] = [5; 6]; //~ ERROR could not evaluate constant expression
error[E0080]: could not evaluate constant expression
- --> $DIR/infinite-recursion-const-fn.rs:16:1
+ --> $DIR/infinite-recursion-const-fn.rs:15:1
|
LL | const fn a() -> usize { b() }
| ---
--- /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`.
--- /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
+fn iter<'a>(data: &'a [usize]) -> impl Iterator<Item = usize> + 'a {
+ data.iter()
+ .map(
+ |x| x // fn(&'a usize) -> &'(ReScope) usize
+ )
+ .map(
+ |x| *x // fn(&'(ReScope) usize) -> usize
+ )
+}
+
+fn main() {
+}
error: unsatisfied lifetime constraints
- --> $DIR/issue-10291.rs:12:65
+ --> $DIR/issue-10291.rs:13:9
|
-LL | fn test<'x>(x: &'x isize) {
- | -- lifetime `'x` defined here
-LL | drop::<Box<for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
- | _________________________________________________________________^
-LL | | x //~ ERROR E0312
-LL | | }));
- | |_____^ closure body requires that `'x` must outlive `'static`
+LL | fn test<'x>(x: &'x isize) {
+ | -- lifetime `'x` defined here
+LL | drop::<Box<for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+LL | x //~ ERROR E0312
+ | ^ returning this value requires that `'x` must outlive `'static`
error: aborting due to previous error
#![allow(safe_extern_statics, warnings)]
extern {
- pub static symbol: ();
+ pub static symbol: u32;
}
-static CRASH: () = symbol;
+static CRASH: u32 = symbol;
//~^ ERROR could not evaluate static initializer
//~| tried to read from foreign (extern) static
error[E0080]: could not evaluate static initializer
- --> $DIR/issue-14227.rs:16:20
+ --> $DIR/issue-14227.rs:16:21
|
-LL | static CRASH: () = symbol;
- | ^^^^^^ tried to read from foreign (extern) static
+LL | static CRASH: u32 = symbol;
+ | ^^^^^^ tried to read from foreign (extern) static
error: aborting due to previous error
| 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
+// 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
+
+trait DictLike<'a> {
+ type ItemsIterator: Iterator<Item=u8>;
+ fn get(c: Self::ItemsIterator) {
+ c.into_iter();
+ }
+}
+
+trait DictLike2<'a> {
+ type ItemsIterator: Iterator<Item=u8>;
+
+ fn items(&self) -> Self::ItemsIterator;
+
+ fn get(&self) {
+ for _ in self.items() {}
+ }
+}
+
+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.
+
+// compile-flags: --test
+
+#![test] //~ ERROR only functions may be used as tests
--- /dev/null
+error: only functions may be used as tests
+ --> $DIR/issue-28134.rs:13:1
+ |
+LL | #![test] //~ ERROR only functions may be used as tests
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
// compile-pass
#![allow(dead_code)]
-#![feature(min_const_fn)]
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.
+//
+// compile-pass
+
+fn main() {
+ let mut i = [1, 2, 3];
+ i[i[0]] = 0;
+ i[i[0] - 1] = 0;
+}
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-1.rs:18:9
|
LL | || {
- | --
- | ||
- | |return type of closure is &'2 mut std::boxed::Box<()>
- | lifetime `'1` represents this closure's body
+ | - inferred to be a `FnMut` closure
LL | &mut x
- | ^^^^^^ returning this value requires that `'1` must outlive `'2`
+ | ^^^^^^ returns a reference to a captured variable which escapes the closure body
|
- = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
error: aborting due to previous error
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-3.rs:18:9
|
LL | || {
- | --
- | ||
- | |return type of closure is [closure@$DIR/issue-40510-3.rs:18:9: 20:10 x:&'2 mut std::vec::Vec<()>]
- | lifetime `'1` represents this closure's body
+ | - inferred to be a `FnMut` closure
LL | / || {
LL | | x.push(())
LL | | }
- | |_________^ returning this value requires that `'1` must outlive `'2`
+ | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
- = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
error: aborting due to previous error
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-49824.rs:22:9
|
LL | || {
- | --
- | ||
- | |return type of closure is [closure@$DIR/issue-49824.rs:22:9: 24:10 x:&'2 mut i32]
- | lifetime `'1` represents this closure's body
+ | - inferred to be a `FnMut` closure
LL | / || {
LL | | let _y = &mut x;
LL | | }
- | |_________^ returning this value requires that `'1` must outlive `'2`
+ | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
- = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
error: aborting due to previous error
foo();
}
+fn baz() -> impl Copy { //~ ERROR: function is never used
+ "I'm unused, too"
+}
+
// Code with #[allow(dead_code)] should be marked live (and thus anything it
// calls is marked live)
#[allow(dead_code)]
LL | fn bar() { //~ ERROR: function is never used
| ^^^^^^^^
-error: aborting due to 9 previous errors
+error: function is never used: `baz`
+ --> $DIR/lint-dead-code-1.rs:112:1
+ |
+LL | fn baz() -> impl Copy { //~ ERROR: function is never used
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 10 previous errors
-// 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.
-
-// normalize-stderr-test: "The system cannot find the file specified\." -> "No such file or directory"
-// ignore-tidy-linelength
+// normalize-stderr-test: "existed:.*\(" -> "existed: $$FILE_NOT_FOUND_MSG ("
// test that errors in a (selection) of macros don't kill compilation
// immediately, so that we get more errors listed at a time.
error[E0665]: `Default` cannot be derived for enums, only structs
- --> $DIR/macros-nonfatal-errors.rs:20:10
+ --> $DIR/macros-nonfatal-errors.rs:9:10
|
LL | #[derive(Default)] //~ ERROR
| ^^^^^^^
error: inline assembly must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:24:10
+ --> $DIR/macros-nonfatal-errors.rs:13:10
|
LL | asm!(invalid); //~ ERROR
| ^^^^^^^
error: concat_idents! requires ident args.
- --> $DIR/macros-nonfatal-errors.rs:26:5
+ --> $DIR/macros-nonfatal-errors.rs:15:5
|
LL | concat_idents!("not", "idents"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:28:17
+ --> $DIR/macros-nonfatal-errors.rs:17:17
|
LL | option_env!(invalid); //~ ERROR
| ^^^^^^^
error: expected string literal
- --> $DIR/macros-nonfatal-errors.rs:29:10
+ --> $DIR/macros-nonfatal-errors.rs:18:10
|
LL | env!(invalid); //~ ERROR
| ^^^^^^^
error: expected string literal
- --> $DIR/macros-nonfatal-errors.rs:30:10
+ --> $DIR/macros-nonfatal-errors.rs:19:10
|
LL | env!(foo, abr, baz); //~ ERROR
| ^^^
error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
- --> $DIR/macros-nonfatal-errors.rs:31:5
+ --> $DIR/macros-nonfatal-errors.rs:20:5
|
LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: format argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:33:13
+ --> $DIR/macros-nonfatal-errors.rs:22:13
|
LL | format!(invalid); //~ ERROR
| ^^^^^^^
| ^^^^^
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:35:14
+ --> $DIR/macros-nonfatal-errors.rs:24:14
|
LL | include!(invalid); //~ ERROR
| ^^^^^^^
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:37:18
+ --> $DIR/macros-nonfatal-errors.rs:26:18
|
LL | include_str!(invalid); //~ ERROR
| ^^^^^^^
-error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: No such file or directory (os error 2)
- --> $DIR/macros-nonfatal-errors.rs:38:5
+error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
+ --> $DIR/macros-nonfatal-errors.rs:27:5
|
LL | include_str!("i'd be quite surprised if a file with this name existed"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:39:20
+ --> $DIR/macros-nonfatal-errors.rs:28:20
|
LL | include_bytes!(invalid); //~ ERROR
| ^^^^^^^
-error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: No such file or directory (os error 2)
- --> $DIR/macros-nonfatal-errors.rs:40:5
+error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
+ --> $DIR/macros-nonfatal-errors.rs:29:5
|
LL | include_bytes!("i'd be quite surprised if a file with this name existed"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trace_macros! accepts only `true` or `false`
- --> $DIR/macros-nonfatal-errors.rs:42:5
+ --> $DIR/macros-nonfatal-errors.rs:31:5
|
LL | trace_macros!(invalid); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^
#[rustc_regions]
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
- //~^ ERROR unsatisfied lifetime constraints
// Only works if 'x: 'y:
demand_y(x, y, x.get())
+ //~^ ERROR unsatisfied lifetime constraints
});
}
|
LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
| _______________________________________________^
-LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
+LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |_____^
|
|
LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
+LL | | // Only works if 'x: 'y:
... |
LL | | });
LL | | }
= note: defining type: DefId(0/0:6 ~ propagate_approximated_ref[317d]::supply[0]) with substs []
error: unsatisfied lifetime constraints
- --> $DIR/propagate-approximated-ref.rs:53:47
+ --> $DIR/propagate-approximated-ref.rs:56:9
|
-LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
- | _______________________________________________^
-LL | | //~^ ERROR unsatisfied lifetime constraints
-LL | |
-LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get())
-LL | | });
- | |_____^ closure body requires that `'a` must outlive `'b`
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
error: aborting due to previous error
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
//~^ ERROR borrowed data escapes outside of function
- //~| ERROR unsatisfied lifetime constraints
// Only works if 'x: 'y:
demand_y(x, y, x.get())
+ //~^ ERROR unsatisfied lifetime constraints
});
}
LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
| _______________________________________________^
LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
+LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |_____^
|
LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
LL | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
+LL | |
... |
LL | | });
LL | | }
| ------ `cell_a` is a reference that is only valid in the function body
LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
+LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |______^ `cell_a` escapes the function body here
error: unsatisfied lifetime constraints
- --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:49:9
|
-LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
- | _______________________________________________^
-LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
-LL | |
-LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get())
-LL | | });
- | |_____^ closure body requires that `'a` must outlive `'b`
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
error: aborting due to 2 previous errors
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
//~^ ERROR borrowed data escapes outside of function
- //~| ERROR unsatisfied lifetime constraints
// Only works if 'x: 'y:
demand_y(x, y, x.get())
+ //~^ ERROR unsatisfied lifetime constraints
});
}
LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
| _______________________________________________^
LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
+LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |_____^
|
LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
+LL | | // Only works if 'x: 'y:
... |
LL | | });
LL | | }
| ------ `cell_a` is a reference that is only valid in the function body
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
+LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |______^ `cell_a` escapes the function body here
error: unsatisfied lifetime constraints
- --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:51:9
|
-LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
- | _______________________________________________^
-LL | | //~^ ERROR borrowed data escapes outside of function
-LL | | //~| ERROR unsatisfied lifetime constraints
-LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get())
-LL | | });
- | |_____^ closure body requires that `'a` must outlive `'b`
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
error: aborting due to 2 previous errors
#[rustc_regions]
fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
- //~^ ERROR unsatisfied lifetime constraints
// Only works if 'x: 'y:
demand_y(outlives1, outlives2, x.get())
+ //~^ ERROR unsatisfied lifetime constraints
});
}
|
LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
| _____________________________________________^
-LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(outlives1, outlives2, x.get())
+LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |_____^
|
|
LL | / fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
LL | | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
-LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
+LL | | // Only works if 'x: 'y:
... |
LL | | });
LL | | }
= note: defining type: DefId(0/0:6 ~ propagate_approximated_val[317d]::test[0]) with substs []
error: unsatisfied lifetime constraints
- --> $DIR/propagate-approximated-val.rs:46:45
+ --> $DIR/propagate-approximated-val.rs:49:9
|
-LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
- | _____________________________________________^
-LL | | //~^ ERROR unsatisfied lifetime constraints
-LL | |
-LL | | // Only works if 'x: 'y:
-LL | | demand_y(outlives1, outlives2, x.get())
-LL | | });
- | |_____^ closure body requires that `'a` must outlive `'b`
+LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(outlives1, outlives2, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
error: aborting due to previous error
--- /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 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+fn main() {
+ let mut v: Vec<()> = Vec::new();
+ || &mut v;
+}
--- /dev/null
+error: captured variable cannot escape `FnMut` closure body
+ --> $DIR/issue-53040.rs:15:8
+ |
+LL | || &mut v;
+ | - ^^^^^^ returns a reference to a captured variable which escapes the closure body
+ | |
+ | inferred to be a `FnMut` closure
+ |
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:55:29
+ --> $DIR/projection-one-region-closure.rs:55:39
|
LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| lifetime `'a` defined here
...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
--> $DIR/projection-one-region-closure.rs:66:29
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:66:29
+ --> $DIR/projection-one-region-closure.rs:66:39
|
LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| lifetime `'a` defined here
...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
--> $DIR/projection-one-region-closure.rs:80:29
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:47:29
+ --> $DIR/projection-one-region-trait-bound-closure.rs:47:39
|
LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| lifetime `'a` defined here
...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:57:29
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:57:29
+ --> $DIR/projection-one-region-trait-bound-closure.rs:57:39
|
LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| lifetime `'a` defined here
...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:70:29
--- /dev/null
+#![feature(nll)]
+
+enum Foo<'a> {
+ Bar { field: &'a u32 }
+}
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo::Bar { field: &y };
+ //~^ ERROR `y` does not live long enough
+ let Foo::Bar::<'static> { field: _z } = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo::Bar { field: &y };
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::Bar::<'static> { field: _z } => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_enum_variant.rs:9:33
+ |
+LL | let foo = Foo::Bar { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_enum_variant.rs:16:33
+ |
+LL | let foo = Foo::Bar { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(nll)]
+
+struct Foo<'a> { field: &'a u32 }
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo { field: &y };
+ //~^ ERROR `y` does not live long enough
+ let Foo::<'static> { field: _z } = foo;
+}
+
+fn in_main() {
+ let y = 22;
+ let foo = Foo { field: &y };
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::<'static> { field: _z } => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_struct.rs:7:28
+ |
+LL | let foo = Foo { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_struct.rs:14:28
+ |
+LL | let foo = Foo { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(nll)]
+
+enum Foo<'a> {
+ Bar(&'a u32)
+}
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo::Bar(&y);
+ //~^ ERROR `y` does not live long enough
+ let Foo::Bar::<'static>(_z) = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo::Bar(&y);
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::Bar::<'static>(_z) => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_enum_variant.rs:9:24
+ |
+LL | let foo = Foo::Bar(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_enum_variant.rs:16:24
+ |
+LL | let foo = Foo::Bar(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(nll)]
+
+struct Foo<'a>(&'a u32);
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo(&y);
+ //~^ ERROR `y` does not live long enough
+ let Foo::<'static>(_z) = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo(&y);
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::<'static>(_z) => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_struct.rs:7:19
+ |
+LL | let foo = Foo(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_struct.rs:14:19
+ |
+LL | let foo = Foo(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// run-rustfix
+
+// Regression test for changes introduced while fixing #54505
+
+// This test uses non-literals for Ranges
+// (expecting no parens with borrow suggestion)
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(&std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
+
+ take_range(&::std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
+
+ take_range(&std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFrom { start: 1 }
+
+ take_range(&::std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
+
+ take_range(&std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFull {}
+
+ take_range(&::std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFull {}
+
+ take_range(&std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
+
+ take_range(&::std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
+
+ take_range(&std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeTo { end: 5 }
+
+ take_range(&::std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeTo { end: 5 }
+
+ take_range(&std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
+
+ take_range(&::std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
+}
--- /dev/null
+// run-rustfix
+
+// Regression test for changes introduced while fixing #54505
+
+// This test uses non-literals for Ranges
+// (expecting no parens with borrow suggestion)
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
+
+ take_range(::std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
+
+ take_range(std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFrom { start: 1 }
+
+ take_range(::std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
+
+ take_range(std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFull {}
+
+ take_range(::std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFull {}
+
+ take_range(std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
+
+ take_range(::std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
+
+ take_range(std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeTo { end: 5 }
+
+ take_range(::std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeTo { end: 5 }
+
+ take_range(std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
+
+ take_range(::std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:16:16
+ |
+LL | take_range(std::ops::Range { start: 0, end: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&std::ops::Range { start: 0, end: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:21:16
+ |
+LL | take_range(::std::ops::Range { start: 0, end: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&::std::ops::Range { start: 0, end: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:26:16
+ |
+LL | take_range(std::ops::RangeFrom { start: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFrom`
+ | help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:31:16
+ |
+LL | take_range(::std::ops::RangeFrom { start: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFrom`
+ | help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:36:16
+ |
+LL | take_range(std::ops::RangeFull {});
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFull`
+ | help: consider borrowing here: `&std::ops::RangeFull {}`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:41:16
+ |
+LL | take_range(::std::ops::RangeFull {});
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFull`
+ | help: consider borrowing here: `&::std::ops::RangeFull {}`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:46:16
+ |
+LL | take_range(std::ops::RangeInclusive::new(0, 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeInclusive`
+ | help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:51:16
+ |
+LL | take_range(::std::ops::RangeInclusive::new(0, 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeInclusive`
+ | help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:56:16
+ |
+LL | take_range(std::ops::RangeTo { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeTo`
+ | help: consider borrowing here: `&std::ops::RangeTo { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:61:16
+ |
+LL | take_range(::std::ops::RangeTo { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeTo`
+ | help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:66:16
+ |
+LL | take_range(std::ops::RangeToInclusive { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeToInclusive`
+ | help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeToInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:71:16
+ |
+LL | take_range(::std::ops::RangeToInclusive { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeToInclusive`
+ | help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// error-pattern: `#[panic_handler]` function required, but not found
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+// This test doesn't use std
+// (so all Ranges resolve to core::ops::Range...)
+
+#![no_std]
+#![feature(lang_items)]
+
+use core::ops::RangeBounds;
+
+#[cfg(not(target_arch = "wasm32"))]
+#[lang = "eh_personality"]
+extern fn eh_personality() {}
+
+#[cfg(target_os = "windows")]
+#[lang = "eh_unwind_resume"]
+extern fn eh_unwind_resume() {}
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(0..1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..1)
+
+ take_range(1..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(1..)
+
+ take_range(..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..)
+
+ take_range(0..=1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..=1)
+
+ take_range(..5);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..5)
+
+ take_range(..=42);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..=42)
+}
--- /dev/null
+error: `#[panic_handler]` function required, but not found
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:28:16
+ |
+LL | take_range(0..1);
+ | ^^^^
+ | |
+ | expected reference, found struct `core::ops::Range`
+ | help: consider borrowing here: `&(0..1)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:33:16
+ |
+LL | take_range(1..);
+ | ^^^
+ | |
+ | expected reference, found struct `core::ops::RangeFrom`
+ | help: consider borrowing here: `&(1..)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:38:16
+ |
+LL | take_range(..);
+ | ^^
+ | |
+ | expected reference, found struct `core::ops::RangeFull`
+ | help: consider borrowing here: `&(..)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:43:16
+ |
+LL | take_range(0..=1);
+ | ^^^^^
+ | |
+ | expected reference, found struct `core::ops::RangeInclusive`
+ | help: consider borrowing here: `&(0..=1)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:48:16
+ |
+LL | take_range(..5);
+ | ^^^
+ | |
+ | expected reference, found struct `core::ops::RangeTo`
+ | help: consider borrowing here: `&(..5)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:53:16
+ |
+LL | take_range(..=42);
+ | ^^^^^
+ | |
+ | expected reference, found struct `core::ops::RangeToInclusive`
+ | help: consider borrowing here: `&(..=42)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(&(0..1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..1)
+
+ take_range(&(1..));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(1..)
+
+ take_range(&(..));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..)
+
+ take_range(&(0..=1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..=1)
+
+ take_range(&(..5));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..5)
+
+ take_range(&(..=42));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..=42)
+}
--- /dev/null
+// run-rustfix
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(0..1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..1)
+
+ take_range(1..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(1..)
+
+ take_range(..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..)
+
+ take_range(0..=1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..=1)
+
+ take_range(..5);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..5)
+
+ take_range(..=42);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..=42)
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:14:16
+ |
+LL | take_range(0..1);
+ | ^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&(0..1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:19:16
+ |
+LL | take_range(1..);
+ | ^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFrom`
+ | help: consider borrowing here: `&(1..)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:24:16
+ |
+LL | take_range(..);
+ | ^^
+ | |
+ | expected reference, found struct `std::ops::RangeFull`
+ | help: consider borrowing here: `&(..)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:29:16
+ |
+LL | take_range(0..=1);
+ | ^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeInclusive`
+ | help: consider borrowing here: `&(0..=1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:34:16
+ |
+LL | take_range(..5);
+ | ^^^
+ | |
+ | expected reference, found struct `std::ops::RangeTo`
+ | help: consider borrowing here: `&(..5)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:39:16
+ |
+LL | take_range(..=42);
+ | ^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeToInclusive`
+ | help: consider borrowing here: `&(..=42)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
error: unsatisfied lifetime constraints
- --> $DIR/regions-addr-of-upvar-self.rs:19:18
+ --> $DIR/regions-addr-of-upvar-self.rs:20:17
|
-LL | pub fn chase_cat(&mut self) {
- | - let's call the lifetime of this reference `'1`
-LL | let _f = || {
- | __________________^
-LL | | let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
-LL | | *p = 3;
-LL | | };
- | |_________^ closure body requires that `'1` must outlive `'static`
+LL | pub fn chase_cat(&mut self) {
+ | - let's call the lifetime of this reference `'1`
+LL | let _f = || {
+LL | let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
+ | ^ type annotation requires that `'1` must outlive `'static`
error[E0597]: `self` does not live long enough
--> $DIR/regions-addr-of-upvar-self.rs:20:46
= note: borrowed value must be valid for the static lifetime...
error: unsatisfied lifetime constraints
- --> $DIR/regions-nested-fns.rs:23:68
+ --> $DIR/regions-nested-fns.rs:24:27
|
-LL | fn nested<'x>(x: &'x isize) {
- | -- lifetime `'x` defined here
+LL | fn nested<'x>(x: &'x isize) {
+ | -- lifetime `'x` defined here
...
-LL | ignore::< Box<for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
- | ____________________________________________________________________^
-LL | | if false { return x; } //~ ERROR E0312
-LL | | if false { return ay; }
-LL | | return z;
-LL | | }));
- | |_____^ closure body requires that `'x` must outlive `'static`
+LL | if false { return x; } //~ ERROR E0312
+ | ^ returning this value requires that `'x` must outlive `'static`
error: aborting due to 4 previous errors
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:24
|
LL | let mut f = || &mut x; //~ ERROR cannot infer
- | -- ^^^^^^ returning this value requires that `'1` must outlive `'2`
- | ||
- | |return type of closure is &'2 mut i32
- | lifetime `'1` represents this closure's body
+ | - ^^^^^^ returns a reference to a captured variable which escapes the closure body
+ | |
+ | inferred to be a `FnMut` closure
|
- = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
error: aborting due to previous error
--- /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`.
--- /dev/null
+// run-rustfix
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetimes)]
+#![allow(dead_code, unused_variables)]
+
+fn september() {}
+//~^ ERROR lifetime parameter `'a` never used
+//~| HELP remove it
+
+fn october<'b, T>(s: &'b T) -> &'b T {
+ //~^ ERROR lifetime parameter `'a` never used
+ //~| HELP remove it
+ s
+}
+
+fn november<'a>(s: &'a str) -> (&'a str) {
+ //~^ ERROR lifetime parameter `'b` never used
+ //~| HELP remove it
+ s
+}
+
+fn main() {}
-// 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.
+// run-rustfix
// Test that we DO warn when lifetime name is not used at all.
#![deny(unused_lifetimes)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
+#![allow(dead_code, unused_variables)]
-fn d<'a>() { } //~ ERROR `'a` never used
+fn september<'a>() {}
+//~^ ERROR lifetime parameter `'a` never used
+//~| HELP remove it
-fn main() { }
+fn october<'a, 'b, T>(s: &'b T) -> &'b T {
+ //~^ ERROR lifetime parameter `'a` never used
+ //~| HELP remove it
+ s
+}
+
+fn november<'a, 'b>(s: &'a str) -> (&'a str) {
+ //~^ ERROR lifetime parameter `'b` never used
+ //~| HELP remove it
+ s
+}
+
+fn main() {}
error: lifetime parameter `'a` never used
- --> $DIR/zero-uses-in-fn.rs:17:6
+ --> $DIR/zero-uses-in-fn.rs:8:14
|
-LL | fn d<'a>() { } //~ ERROR `'a` never used
- | ^^
+LL | fn september<'a>() {}
+ | -^^- help: remove it
|
note: lint level defined here
- --> $DIR/zero-uses-in-fn.rs:13:9
+ --> $DIR/zero-uses-in-fn.rs:5:9
|
LL | #![deny(unused_lifetimes)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: lifetime parameter `'a` never used
+ --> $DIR/zero-uses-in-fn.rs:12:12
+ |
+LL | fn october<'a, 'b, T>(s: &'b T) -> &'b T {
+ | ^^--
+ | |
+ | help: remove it
+
+error: lifetime parameter `'b` never used
+ --> $DIR/zero-uses-in-fn.rs:18:17
+ |
+LL | fn november<'a, 'b>(s: &'a str) -> (&'a str) {
+ | --^^
+ | |
+ | help: remove it
+
+error: aborting due to 3 previous errors
-// 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.
-
// Test that we DO warn when lifetime name is not used at all.
#![deny(unused_lifetimes)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
+#![allow(dead_code, unused_variables)]
-struct Foo { }
+struct Foo {}
-impl<'a> Foo { } //~ ERROR `'a` never used
+impl<'a> Foo {} //~ ERROR `'a` never used
-fn main() { }
+fn main() {}
error: lifetime parameter `'a` never used
- --> $DIR/zero-uses-in-impl.rs:19:6
+ --> $DIR/zero-uses-in-impl.rs:8:6
|
-LL | impl<'a> Foo { } //~ ERROR `'a` never used
- | ^^
+LL | impl<'a> Foo {} //~ ERROR `'a` never used
+ | -^^- help: remove it
|
note: lint level defined here
- --> $DIR/zero-uses-in-impl.rs:13:9
+ --> $DIR/zero-uses-in-impl.rs:3:9
|
LL | #![deny(unused_lifetimes)]
| ^^^^^^^^^^^^^^^^
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`
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// #39665
+
+fn batches(n: &u32) -> impl Iterator<Item=&u32> {
+ std::iter::once(n)
+}
+
+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.
-
-#![allow(unused)]
-
-// normalize-stderr-test "alignment \d+" -> "alignment N"
-// normalize-stderr-test "offset \d+" -> "offset N"
-// normalize-stderr-test "allocation \d+" -> "allocation N"
-// normalize-stderr-test "size \d+" -> "size N"
-
-union BoolTransmute {
- val: u8,
- bl: bool,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct SliceRepr {
- ptr: *const u8,
- len: usize,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct BadSliceRepr {
- ptr: *const u8,
- len: &'static u8,
-}
-
-union SliceTransmute {
- repr: SliceRepr,
- bad: BadSliceRepr,
- slice: &'static [u8],
- str: &'static str,
- my_str: &'static MyStr,
- my_slice: &'static MySliceBool,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct DynRepr {
- ptr: *const u8,
- vtable: *const u8,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct DynRepr2 {
- ptr: *const u8,
- vtable: *const u64,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct BadDynRepr {
- ptr: *const u8,
- vtable: usize,
-}
-
-union DynTransmute {
- repr: DynRepr,
- repr2: DynRepr2,
- bad: BadDynRepr,
- rust: &'static Trait,
-}
-
-trait Trait {}
-impl Trait for bool {}
-
-// custom unsized type
-struct MyStr(str);
-
-// custom unsized type with sized fields
-struct MySlice<T: ?Sized>(bool, T);
-type MySliceBool = MySlice<[bool]>;
-
-// OK
-const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
-// bad str
-const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad str
-const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad str in user-defined unsized type
-const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// OK
-const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice};
-// bad slice
-const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad slice
-const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// bad trait object
-const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad trait object
-const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad trait object
-const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// bad data *inside* the trait object
-const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad data *inside* the slice
-const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// good MySliceBool
-const I1: &MySliceBool = &MySlice(true, [false]);
-// bad: sized field is not okay
-const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad: unsized part is not okay
-const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// invalid UTF-8
-const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
-//~^ ERROR this constant likely exhibits undefined behavior
-// invalid UTF-8 in user-defined str-like
-const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
-//~^ ERROR this constant likely exhibits undefined behavior
-
-fn main() {
-}
+++ /dev/null
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:87:1
- |
-LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or out-of-bounds memory at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:90:1
- |
-LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:93:1
- |
-LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:99:1
- |
-LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or out-of-bounds memory at .<deref>[1]
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:102:1
- |
-LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:106:1
- |
-LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid vtable in fat pointer at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:109:1
- |
-LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid vtable in fat pointer at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:112:1
- |
-LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:116:1
- |
-LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:119:1
- |
-LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:125:1
- |
-LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:128:1
- |
-LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:132:1
- |
-LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-UTF-8 data in str at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:135:1
- |
-LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-UTF-8 data in str at .<deref>.0
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error: aborting due to 14 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
// 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`
// A quick test of 'unsafe const fn' functionality
-#![feature(min_const_fn)]
-
const unsafe fn dummy(v: u32) -> u32 {
!v
}
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/unsafe-const-fn.rs:19:18
+ --> $DIR/unsafe-const-fn.rs:17:18
|
LL | const VAL: u32 = dummy(0xFFFF);
| ^^^^^^^^^^^^^ call to unsafe function
/// Version of LLDB
pub lldb_version: Option<String>,
+ /// Whether LLDB has native rust support
+ pub lldb_native_rust: bool,
+
/// Version of LLVM
pub llvm_version: Option<String>,
// Ignore if actual version is smaller the minimum required
// version
lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
+ } else if line.starts_with("rust-lldb") && !config.lldb_native_rust {
+ true
} else {
false
}
let android_cross_path = opt_path(matches, "android-cross-path");
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target,
&android_cross_path);
+ let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
Some("auto") | None => ColorConfig::AutoColor,
gdb,
gdb_version,
gdb_native_rust,
- lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
+ lldb_version,
+ lldb_native_rust,
llvm_version: matches.opt_str("llvm-version"),
system_llvm: matches.opt_present("system-llvm"),
android_cross_path: android_cross_path,
None
}
-fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
+/// Returns (LLDB version, LLDB is rust-enabled)
+fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) {
// Extract the major LLDB version from the given version string.
// LLDB version strings are different for Apple and non-Apple platforms.
- // At the moment, this function only supports the Apple variant, which looks
- // like this:
+ // The Apple variant looks like this:
//
// LLDB-179.5 (older versions)
// lldb-300.2.51 (new versions)
//
// We are only interested in the major version number, so this function
// will return `Some("179")` and `Some("300")` respectively.
+ //
+ // Upstream versions look like:
+ // lldb version 6.0.1
+ //
+ // There doesn't seem to be a way to correlate the Apple version
+ // with the upstream version, and since the tests were originally
+ // written against Apple versions, we make a fake Apple version by
+ // multiplying the first number by 100. This is a hack, but
+ // normally fine because the only non-Apple version we test is
+ // rust-enabled.
if let Some(ref full_version_line) = full_version_line {
if !full_version_line.trim().is_empty() {
.take_while(|c| c.is_digit(10))
.collect::<String>();
if !vers.is_empty() {
- return Some(vers);
+ return (Some(vers), full_version_line.contains("rust-enabled"));
+ }
+ }
+
+ if full_version_line.starts_with("lldb version ") {
+ let vers = full_version_line[13..]
+ .chars()
+ .take_while(|c| c.is_digit(10))
+ .collect::<String>();
+ if !vers.is_empty() {
+ return (Some(vers + "00"), full_version_line.contains("rust-enabled"));
}
}
}
}
- None
+ (None, false)
}
fn is_blacklisted_lldb_version(version: &str) -> bool {
}
}
+ let prefixes = if self.config.lldb_native_rust {
+ static PREFIXES: &'static [&'static str] = &["lldb", "lldbr"];
+ println!("NOTE: compiletest thinks it is using LLDB with native rust support");
+ PREFIXES
+ } else {
+ static PREFIXES: &'static [&'static str] = &["lldb", "lldbg"];
+ println!("NOTE: compiletest thinks it is using LLDB without native rust support");
+ PREFIXES
+ };
+
// Parse debugger commands etc from test files
let DebuggerCommands {
commands,
check_lines,
breakpoint_lines,
..
- } = self.parse_debugger_commands(&["lldb"]);
+ } = self.parse_debugger_commands(prefixes);
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
-Subproject commit e8f6973e2d40ab39e30cdbe0cf8e77a72c867d4f
+Subproject commit cc275c63a90d4bea394e76607b2e10611eb1be36