deploy:
- provider: s3
- edge:
- branch: s3-eager-autoload
bucket: rust-lang-ci2
skip_cleanup: true
local_dir: deploy
# this is the same as the above deployment provider except that it uploads to
# a slightly different directory and has a different trigger
- provider: s3
- edge:
- branch: s3-eager-autoload
bucket: rust-lang-ci2
skip_cleanup: true
local_dir: deploy
# try branch. Travis does not appear to provide a way to use "or" in these
# conditions.
- provider: s3
- edge:
- branch: s3-eager-autoload
bucket: rust-lang-ci2
skip_cleanup: true
local_dir: deploy
condition: $DEPLOY = 1
- provider: s3
- edge:
- branch: s3-eager-autoload
bucket: rust-lang-ci2
skip_cleanup: true
local_dir: deploy
+Version 1.25.0 (2018-03-29)
+==========================
+
+Language
+--------
+- [Stabilised `#[repr(align(x))]`.][47006] [RFC 1358]
+- [You can now use nested groups of imports.][47948]
+ e.g. `use std::{fs::File, io::Read, path::{Path, PathBuf}};`
+- [You can now have `|` at the start of a match arm.][47947] e.g.
+```rust
+enum Foo { A, B, C }
+
+fn main() {
+ let x = Foo::A;
+ match x {
+ | Foo::A
+ | Foo::B => println!("AB"),
+ | Foo::C => println!("C"),
+ }
+}
+```
+
+Compiler
+--------
+- [Upgraded to LLVM 6.][47828]
+- [Added `-C lto=val` option.][47521]
+- [Added `i586-unknown-linux-musl` target][47282]
+
+Libraries
+---------
+- [Impl Send for `process::Command` on Unix.][47760]
+- [Impl PartialEq and Eq for `ParseCharError`.][47790]
+- [`UnsafeCell::into_inner` is now safe.][47204]
+- [Implement libstd for CloudABI.][47268]
+- [`Float::{from_bits, to_bits}` is now available in libcore.][46931]
+- [Implement `AsRef<Path>` for Component][46985]
+- [Implemented `Write` for `Cursor<&mut Vec<T>>`][46830]
+- [Moved `Duration` to libcore.][46666]
+
+Stabilized APIs
+---------------
+- [`Location::column`]
+- [`ptr::NonNull`]
+
+The following functions can now be used in a constant expression.
+eg. `static MINUTE: Duration = Duration::from_secs(60);`
+- [`Duration::new`][47300]
+- [`Duration::from_secs`][47300]
+- [`Duration::from_millis`][47300]
+- [`Duration::from_micros`][47300]
+- [`Duration::from_nanos`][47300]
+
+Cargo
+-----
+- [`cargo new` no longer removes `rust` or `rs` prefixs/suffixs.][cargo/5013]
+- [`cargo new` now defaults to creating a binary crate, instead of a
+ library crate.][cargo/5029]
+
+Misc
+----
+- [Rust by example is now shipped with new releases][46196]
+
+Compatibility Notes
+-------------------
+- [Deprecated `net::lookup_host`.][47510]
+- [`rustdoc` has switched to pulldown as the default markdown renderer.][47398]
+- The borrow checker was sometimes incorrectly permitting overlapping borrows
+ around indexing operations (see [#47349][47349]). This has been fixed (which also
+ enabled some correct code that used to cause errors (e.g. [#33903][33903] and [#46095][46095]).
+- [Removed deprecated unstable attribute `#[simd]`.][47251]
+
+[33903]: https://github.com/rust-lang/rust/pull/33903
+[47947]: https://github.com/rust-lang/rust/pull/47947
+[47948]: https://github.com/rust-lang/rust/pull/47948
+[47760]: https://github.com/rust-lang/rust/pull/47760
+[47790]: https://github.com/rust-lang/rust/pull/47790
+[47828]: https://github.com/rust-lang/rust/pull/47828
+[47398]: https://github.com/rust-lang/rust/pull/47398
+[47510]: https://github.com/rust-lang/rust/pull/47510
+[47521]: https://github.com/rust-lang/rust/pull/47521
+[47204]: https://github.com/rust-lang/rust/pull/47204
+[47251]: https://github.com/rust-lang/rust/pull/47251
+[47268]: https://github.com/rust-lang/rust/pull/47268
+[47282]: https://github.com/rust-lang/rust/pull/47282
+[47300]: https://github.com/rust-lang/rust/pull/47300
+[47349]: https://github.com/rust-lang/rust/pull/47349
+[46931]: https://github.com/rust-lang/rust/pull/46931
+[46985]: https://github.com/rust-lang/rust/pull/46985
+[47006]: https://github.com/rust-lang/rust/pull/47006
+[46830]: https://github.com/rust-lang/rust/pull/46830
+[46095]: https://github.com/rust-lang/rust/pull/46095
+[46666]: https://github.com/rust-lang/rust/pull/46666
+[46196]: https://github.com/rust-lang/rust/pull/46196
+[cargo/5013]: https://github.com/rust-lang/cargo/pull/5013
+[cargo/5029]: https://github.com/rust-lang/cargo/pull/5029
+[RFC 1358]: https://github.com/rust-lang/rfcs/pull/1358
+[`Location::column`]: https://doc.rust-lang.org/std/panic/struct.Location.html#method.column
+[`ptr::NonNull`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html
+
+
Version 1.24.0 (2018-02-15)
==========================
# essentially skipping stage0 as the local compiler is recompiling itself again.
#local-rebuild = false
+# Print out how long each rustbuild step took (mostly intended for CI and
+# tracking over time)
+#print-step-timings = false
+
# =============================================================================
# General install configuration options
# =============================================================================
use std::env;
use std::ffi::OsString;
-use std::str::FromStr;
+use std::io;
use std::path::PathBuf;
-use std::process::{Command, ExitStatus};
+use std::process::Command;
+use std::str::FromStr;
+use std::time::Instant;
fn main() {
let mut args = env::args_os().skip(1).collect::<Vec<_>>();
};
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
- let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
+ let on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
.arg(format!("stage{}", stage))
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
+ let mut maybe_crate = None;
if let Some(target) = target {
// The stage0 compiler has a special sysroot distinct from what we
.find(|a| &*a[0] == "--crate-name")
.unwrap();
let crate_name = &*crate_name[1];
+ maybe_crate = Some(crate_name);
// If we're compiling specifically the `panic_abort` crate then we pass
// the `-C panic=abort` option. Note that we do not do this for any
eprintln!("libdir: {:?}", libdir);
}
- // Actually run the compiler!
- std::process::exit(if let Some(ref mut on_fail) = on_fail {
- match cmd.status() {
- Ok(s) if s.success() => 0,
- _ => {
- println!("\nDid not run successfully:\n{:?}\n-------------", cmd);
- exec_cmd(on_fail).expect("could not run the backup command");
- 1
+ if let Some(mut on_fail) = on_fail {
+ let e = match cmd.status() {
+ Ok(s) if s.success() => std::process::exit(0),
+ e => e,
+ };
+ println!("\nDid not run successfully: {:?}\n{:?}\n-------------", e, cmd);
+ exec_cmd(&mut on_fail).expect("could not run the backup command");
+ std::process::exit(1);
+ }
+
+ if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
+ if let Some(krate) = maybe_crate {
+ let start = Instant::now();
+ let status = cmd
+ .status()
+ .expect(&format!("\n\n failed to run {:?}", cmd));
+ let dur = start.elapsed();
+
+ let is_test = args.iter().any(|a| a == "--test");
+ eprintln!("[RUSTC-TIMING] {} test:{} {}.{:03}",
+ krate.to_string_lossy(),
+ is_test,
+ dur.as_secs(),
+ dur.subsec_nanos() / 1_000_000);
+
+ match status.code() {
+ Some(i) => std::process::exit(i),
+ None => {
+ eprintln!("rustc exited with {}", status);
+ std::process::exit(0xfe);
+ }
}
}
- } else {
- std::process::exit(match exec_cmd(&mut cmd) {
- Ok(s) => s.code().unwrap_or(0xfe),
- Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
- })
- })
+ }
+
+ let code = exec_cmd(&mut cmd).expect(&format!("\n\n failed to run {:?}", cmd));
+ std::process::exit(code);
}
#[cfg(unix)]
-fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
+fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
use std::os::unix::process::CommandExt;
Err(cmd.exec())
}
#[cfg(not(unix))]
-fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
- cmd.status()
+fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
+ cmd.status().map(|status| status.code().unwrap())
}
// except according to those terms.
use std::any::Any;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
use std::collections::BTreeSet;
use std::env;
use std::fmt::Debug;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::process::Command;
+use std::time::{Instant, Duration};
use compile;
use install;
pub kind: Kind,
cache: Cache,
stack: RefCell<Vec<Box<Any>>>,
+ time_spent_on_dependencies: Cell<Duration>,
}
impl<'a> Deref for Builder<'a> {
test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps,
test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty,
test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty,
- test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake,
+ test::RunPassFullDepsPretty, test::RunFailFullDepsPretty,
test::Crate, test::CrateLibrustc, test::CrateRustdoc, test::Linkcheck,
test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample,
test::TheBook, test::UnstableBook,
- test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme),
+ test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme,
+ // Run run-make last, since these won't pass without make on Windows
+ test::RunMake),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
kind,
cache: Cache::new(),
stack: RefCell::new(Vec::new()),
+ time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
};
let builder = &builder;
kind,
cache: Cache::new(),
stack: RefCell::new(Vec::new()),
+ time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
};
if kind == Kind::Dist {
cargo.env("RUSTC_ON_FAIL", on_fail);
}
+ if self.config.print_step_timings {
+ cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
+ }
+
cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
// Throughout the build Cargo can execute a number of build scripts
self.build.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
stack.push(Box::new(step.clone()));
}
- let out = step.clone().run(self);
+
+ let (out, dur) = {
+ let start = Instant::now();
+ let zero = Duration::new(0, 0);
+ let parent = self.time_spent_on_dependencies.replace(zero);
+ let out = step.clone().run(self);
+ let dur = start.elapsed();
+ let deps = self.time_spent_on_dependencies.replace(parent + dur);
+ (out, dur - deps)
+ };
+
+ if self.build.config.print_step_timings && dur > Duration::from_millis(100) {
+ println!("[TIMING] {:?} -- {}.{:03}",
+ step,
+ dur.as_secs(),
+ dur.subsec_nanos() / 1_000_000);
+ }
+
{
let mut stack = self.stack.borrow_mut();
let cur_step = stack.pop().expect("step stack empty");
pub quiet_tests: bool,
pub test_miri: bool,
pub save_toolstates: Option<PathBuf>,
+ pub print_step_timings: bool,
// Fallback musl-root for all targets
pub musl_root: Option<PathBuf>,
openssl_static: Option<bool>,
configure_args: Option<Vec<String>>,
local_rebuild: Option<bool>,
+ print_step_timings: Option<bool>,
}
/// TOML representation of various global install decisions.
set(&mut config.openssl_static, build.openssl_static);
set(&mut config.configure_args, build.configure_args);
set(&mut config.local_rebuild, build.local_rebuild);
+ set(&mut config.print_step_timings, build.print_step_timings);
config.verbose = cmp::max(config.verbose, flags.verbose);
if let Some(ref install) = toml.install {
. "$ci_dir/shared.sh"
travis_fold start init_repo
+travis_time_start
REPO_DIR="$1"
CACHE_DIR="$2"
git fetch origin --unshallow beta master
fi
-travis_fold start update_cache
-travis_time_start
-
-# Update the cache (a pristine copy of the rust source master)
-retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \
- git clone --depth 1 https://github.com/rust-lang/rust.git $cache_src_dir"
-if [ -d $cache_src_dir/src/llvm ]; then
- (cd $cache_src_dir && git rm src/llvm)
-fi
-if [ -d $cache_src_dir/src/llvm-emscripten ]; then
- (cd $cache_src_dir && git rm src/llvm-emscripten)
-fi
-retry sh -c "cd $cache_src_dir && \
- git submodule deinit -f . && git submodule sync && git submodule update --init"
-
-travis_fold end update_cache
-travis_time_finish
+function fetch_submodule {
+ local module=$1
+ local cached="download-${module//\//-}.tar.gz"
+ retry sh -c "rm -f $cached && \
+ curl -sSL -o $cached $2"
+ mkdir $module
+ touch "$module/.git"
+ tar -C $module --strip-components=1 -xf $cached
+ rm $cached
+}
-travis_fold start update_submodules
-travis_time_start
-
-# Update the submodules of the repo we're in, using the pristine repo as
-# a cache for any object files
-# No, `git submodule foreach` won't work:
-# http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository
+included="src/llvm src/llvm-emscripten src/doc/book src/doc/rust-by-example"
modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
-for module in $modules; do
- if [ "$module" = src/llvm ] || [ "$module" = src/llvm-emscripten ]; then
+modules=($modules)
+use_git=""
+urls="$(git config --file .gitmodules --get-regexp '\.url$' | cut -d' ' -f2)"
+urls=($urls)
+for i in ${!modules[@]}; do
+ module=${modules[$i]}
+ if [[ " $included " = *" $module "* ]]; then
commit="$(git ls-tree HEAD $module | awk '{print $3}')"
git rm $module
- retry sh -c "rm -f $commit.tar.gz && \
- curl -sSL -O https://github.com/rust-lang/llvm/archive/$commit.tar.gz"
- tar -C src/ -xf "$commit.tar.gz"
- rm "$commit.tar.gz"
- mv "src/llvm-$commit" $module
- continue
- fi
- if [ ! -e "$cache_src_dir/$module/.git" ]; then
- echo "WARNING: $module not found in pristine repo"
- retry sh -c "git submodule deinit -f $module && \
- git submodule update --init --recursive $module"
+ url=${urls[$i]}
+ url=${url/\.git/}
+ fetch_submodule $module "$url/archive/$commit.tar.gz" &
continue
+ else
+ use_git="$use_git $module"
fi
- retry sh -c "git submodule deinit -f $module && \
- git submodule update --init --recursive --reference $cache_src_dir/$module $module"
done
-
-travis_fold end update_submodules
-travis_time_finish
-
+retry sh -c "git submodule deinit -f $use_git && \
+ git submodule sync && \
+ git submodule update -j 16 --init --recursive $use_git"
+wait
travis_fold end init_repo
+travis_time_finish
if [ "$TRAVIS" == "true" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
+else
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
travis_fold end log-system-info
if [ ! -z "$SCRIPT" ]; then
- # FIXME(#49246): Re-enable these tools after #49246 has been merged and thus fixing the cache.
- if [ "$DEPLOY_ALT" = 1 ]; then
- sh -x -c "$SCRIPT \
- --exclude src/tools/rls \
- --exclude src/tools/rustfmt \
- --exclude src/tools/clippy"
- else
- sh -x -c "$SCRIPT"
- fi
+ sh -x -c "$SCRIPT"
else
do_make() {
travis_fold start "make-$1"
const MAX_LEN: usize = 80;
static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
- // FIXME #5244: AtomicUsize is not Copy.
+ // FIXME(RFC 1109): AtomicUsize is not Copy.
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
#![stable(feature = "rust1", since = "1.0.0")]
-use fmt;
-
-/// A type used as the error type for implementations of fallible conversion
-/// traits in cases where conversions cannot actually fail.
-///
-/// Because `Infallible` has no variants, a value of this type can never exist.
-/// It is used only to satisfy trait signatures that expect an error type, and
-/// signals to both the compiler and the user that the error case is impossible.
-#[unstable(feature = "try_from", issue = "33417")]
-#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub enum Infallible {}
-
-#[unstable(feature = "try_from", issue = "33417")]
-impl fmt::Display for Infallible {
- fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- }
- }
-}
/// A cheap reference-to-reference conversion. Used to convert a value to a
/// reference value within generic code.
///
}
}
-// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
+// FIXME (#45742): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
// fn as_ref(&self) -> &U {
}
}
-// FIXME (#23442): replace the above impl for &mut with the following more general one:
+// FIXME (#45742): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
// fn as_mut(&mut self) -> &mut U {
// with an uninhabited error type.
#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryFrom<U> for T where T: From<U> {
- type Error = Infallible;
+ type Error = !;
fn try_from(value: U) -> Result<Self, Self::Error> {
Ok(T::from(value))
#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
- // FIXME(#6393): merge these when borrow-checking gets better.
+ // FIXME(#43234): merge these when borrow-checking gets better.
if n == 0 {
match self.peeked.take() {
Some(v) => v,
#![stable(feature = "rust1", since = "1.0.0")]
-use convert::{Infallible, TryFrom};
+use convert::TryFrom;
use fmt;
use intrinsics;
use ops;
}
#[unstable(feature = "try_from", issue = "33417")]
-impl From<Infallible> for TryFromIntError {
- fn from(infallible: Infallible) -> TryFromIntError {
- match infallible {
- }
+impl From<!> for TryFromIntError {
+ fn from(never: !) -> TryFromIntError {
+ never
}
}
($source:ty, $($target:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
- type Error = Infallible;
+ type Error = !;
#[inline]
fn try_from(value: $source) -> Result<Self, Self::Error> {
#[cfg(target_pointer_width = "16")]
mod ptr_try_from_impls {
use super::TryFromIntError;
- use convert::{Infallible, TryFrom};
+ use convert::TryFrom;
try_from_upper_bounded!(usize, u8);
try_from_unbounded!(usize, u16, u32, u64, u128);
#[cfg(target_pointer_width = "32")]
mod ptr_try_from_impls {
use super::TryFromIntError;
- use convert::{Infallible, TryFrom};
+ use convert::TryFrom;
try_from_upper_bounded!(usize, u8, u16);
try_from_unbounded!(usize, u32, u64, u128);
#[cfg(target_pointer_width = "64")]
mod ptr_try_from_impls {
use super::TryFromIntError;
- use convert::{Infallible, TryFrom};
+ use convert::TryFrom;
try_from_upper_bounded!(usize, u8, u16, u32);
try_from_unbounded!(usize, u64, u128);
///
/// [`String`]: ../../std/string/struct.String.html#method.from_utf8
/// [`&str`]: ../../std/str/fn.from_utf8.html
+///
+/// # Examples
+///
+/// This error type’s methods can be used to create functionality
+/// similar to `String::from_utf8_lossy` without allocating heap memory:
+///
+/// ```
+/// fn from_utf8_lossy<F>(mut input: &[u8], mut push: F) where F: FnMut(&str) {
+/// loop {
+/// match ::std::str::from_utf8(input) {
+/// Ok(valid) => {
+/// push(valid);
+/// break
+/// }
+/// Err(error) => {
+/// let (valid, after_valid) = input.split_at(error.valid_up_to());
+/// unsafe {
+/// push(::std::str::from_utf8_unchecked(valid))
+/// }
+/// push("\u{FFFD}");
+///
+/// if let Some(invalid_sequence_length) = error.error_len() {
+/// input = &after_valid[invalid_sequence_length..]
+/// } else {
+/// break
+/// }
+/// }
+/// }
+/// }
+/// }
+/// ```
#[derive(Copy, Eq, PartialEq, Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Utf8Error {
$stable_from:meta,
$stable_nand:meta,
$s_int_type:expr, $int_ref:expr,
+ $extra_feature:expr,
$int_type:ident $atomic_type:ident $atomic_init:ident) => {
/// An integer type which can be safely shared between threads.
///
/// ). For more about the differences between atomic types and
/// non-atomic types, please see the [module-level documentation].
///
- /// Please note that examples are shared between atomic variants of
- /// primitive integer types, so it's normal that they are all
- /// demonstrating [`AtomicIsize`].
- ///
/// [module-level documentation]: index.html
- /// [`AtomicIsize`]: struct.AtomicIsize.html
#[$stable]
pub struct $atomic_type {
v: UnsafeCell<$int_type>,
unsafe impl Sync for $atomic_type {}
impl $atomic_type {
- /// Creates a new atomic integer.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::AtomicIsize;
- ///
- /// let atomic_forty_two = AtomicIsize::new(42);
- /// ```
- #[inline]
- #[$stable]
- pub const fn new(v: $int_type) -> Self {
- $atomic_type {v: UnsafeCell::new(v)}
+ doc_comment! {
+ concat!("Creates a new atomic integer.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
+
+let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
+```"),
+ #[inline]
+ #[$stable]
+ pub const fn new(v: $int_type) -> Self {
+ $atomic_type {v: UnsafeCell::new(v)}
+ }
}
- /// Returns a mutable reference to the underlying integer.
- ///
- /// This is safe because the mutable reference guarantees that no other threads are
- /// concurrently accessing the atomic data.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let mut some_isize = AtomicIsize::new(10);
- /// assert_eq!(*some_isize.get_mut(), 10);
- /// *some_isize.get_mut() = 5;
- /// assert_eq!(some_isize.load(Ordering::SeqCst), 5);
- /// ```
- #[inline]
- #[$stable_access]
- pub fn get_mut(&mut self) -> &mut $int_type {
- unsafe { &mut *self.v.get() }
+ doc_comment! {
+ concat!("Returns a mutable reference to the underlying integer.
+
+This is safe because the mutable reference guarantees that no other threads are
+concurrently accessing the atomic data.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let mut some_var = ", stringify!($atomic_type), "::new(10);
+assert_eq!(*some_var.get_mut(), 10);
+*some_var.get_mut() = 5;
+assert_eq!(some_var.load(Ordering::SeqCst), 5);
+```"),
+ #[inline]
+ #[$stable_access]
+ pub fn get_mut(&mut self) -> &mut $int_type {
+ unsafe { &mut *self.v.get() }
+ }
}
- /// Consumes the atomic and returns the contained value.
- ///
- /// This is safe because passing `self` by value guarantees that no other threads are
- /// concurrently accessing the atomic data.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::AtomicIsize;
- ///
- /// let some_isize = AtomicIsize::new(5);
- /// assert_eq!(some_isize.into_inner(), 5);
- /// ```
- #[inline]
- #[$stable_access]
- pub fn into_inner(self) -> $int_type {
- self.v.into_inner()
+ doc_comment! {
+ concat!("Consumes the atomic and returns the contained value.
+
+This is safe because passing `self` by value guarantees that no other threads are
+concurrently accessing the atomic data.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
+
+let some_var = ", stringify!($atomic_type), "::new(5);
+assert_eq!(some_var.into_inner(), 5);
+```"),
+ #[inline]
+ #[$stable_access]
+ pub fn into_inner(self) -> $int_type {
+ self.v.into_inner()
+ }
}
- /// Loads a value from the atomic integer.
- ///
- /// `load` takes an [`Ordering`] argument which describes the memory ordering of this
- /// operation.
- ///
- /// # Panics
- ///
- /// Panics if `order` is [`Release`] or [`AcqRel`].
- ///
- /// [`Ordering`]: enum.Ordering.html
- /// [`Release`]: enum.Ordering.html#variant.Release
- /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let some_isize = AtomicIsize::new(5);
- ///
- /// assert_eq!(some_isize.load(Ordering::Relaxed), 5);
- /// ```
- #[inline]
- #[$stable]
- pub fn load(&self, order: Ordering) -> $int_type {
- unsafe { atomic_load(self.v.get(), order) }
+ doc_comment! {
+ concat!("Loads a value from the atomic integer.
+
+`load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+
+# Panics
+
+Panics if `order` is [`Release`] or [`AcqRel`].
+
+[`Ordering`]: enum.Ordering.html
+[`Release`]: enum.Ordering.html#variant.Release
+[`AcqRel`]: enum.Ordering.html#variant.AcqRel
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let some_var = ", stringify!($atomic_type), "::new(5);
+
+assert_eq!(some_var.load(Ordering::Relaxed), 5);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn load(&self, order: Ordering) -> $int_type {
+ unsafe { atomic_load(self.v.get(), order) }
+ }
}
- /// Stores a value into the atomic integer.
- ///
- /// `store` takes an [`Ordering`] argument which describes the memory ordering of this
- /// operation.
- ///
- /// [`Ordering`]: enum.Ordering.html
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let some_isize = AtomicIsize::new(5);
- ///
- /// some_isize.store(10, Ordering::Relaxed);
- /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
- /// ```
- ///
- /// # Panics
- ///
- /// Panics if `order` is [`Acquire`] or [`AcqRel`].
- ///
- /// [`Acquire`]: enum.Ordering.html#variant.Acquire
- /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
- #[inline]
- #[$stable]
- pub fn store(&self, val: $int_type, order: Ordering) {
- unsafe { atomic_store(self.v.get(), val, order); }
+ doc_comment! {
+ concat!("Stores a value into the atomic integer.
+
+`store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+
+[`Ordering`]: enum.Ordering.html
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let some_var = ", stringify!($atomic_type), "::new(5);
+
+some_var.store(10, Ordering::Relaxed);
+assert_eq!(some_var.load(Ordering::Relaxed), 10);
+```
+
+# Panics
+
+Panics if `order` is [`Acquire`] or [`AcqRel`].
+
+[`Acquire`]: enum.Ordering.html#variant.Acquire
+[`AcqRel`]: enum.Ordering.html#variant.AcqRel"),
+ #[inline]
+ #[$stable]
+ pub fn store(&self, val: $int_type, order: Ordering) {
+ unsafe { atomic_store(self.v.get(), val, order); }
+ }
}
- /// Stores a value into the atomic integer, returning the previous value.
- ///
- /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this
- /// operation.
- ///
- /// [`Ordering`]: enum.Ordering.html
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let some_isize = AtomicIsize::new(5);
- ///
- /// assert_eq!(some_isize.swap(10, Ordering::Relaxed), 5);
- /// ```
- #[inline]
- #[$stable]
- pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_swap(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Stores a value into the atomic integer, returning the previous value.
+
+`swap` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+
+[`Ordering`]: enum.Ordering.html
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let some_var = ", stringify!($atomic_type), "::new(5);
+
+assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_swap(self.v.get(), val, order) }
+ }
}
- /// Stores a value into the atomic integer if the current value is the same as the
- /// `current` value.
- ///
- /// The return value is always the previous value. If it is equal to `current`, then the
- /// value was updated.
- ///
- /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory
- /// ordering of this operation.
- ///
- /// [`Ordering`]: enum.Ordering.html
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let some_isize = AtomicIsize::new(5);
- ///
- /// assert_eq!(some_isize.compare_and_swap(5, 10, Ordering::Relaxed), 5);
- /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
- ///
- /// assert_eq!(some_isize.compare_and_swap(6, 12, Ordering::Relaxed), 10);
- /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
- /// ```
- #[inline]
- #[$stable]
- pub fn compare_and_swap(&self,
- current: $int_type,
- new: $int_type,
- order: Ordering) -> $int_type {
- match self.compare_exchange(current,
- new,
- order,
- strongest_failure_ordering(order)) {
- Ok(x) => x,
- Err(x) => x,
+ doc_comment! {
+ concat!("Stores a value into the atomic integer if the current value is the same as
+the `current` value.
+
+The return value is always the previous value. If it is equal to `current`, then the
+value was updated.
+
+`compare_and_swap` also takes an [`Ordering`] argument which describes the memory
+ordering of this operation.
+
+[`Ordering`]: enum.Ordering.html
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let some_var = ", stringify!($atomic_type), "::new(5);
+
+assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5);
+assert_eq!(some_var.load(Ordering::Relaxed), 10);
+
+assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10);
+assert_eq!(some_var.load(Ordering::Relaxed), 10);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn compare_and_swap(&self,
+ current: $int_type,
+ new: $int_type,
+ order: Ordering) -> $int_type {
+ match self.compare_exchange(current,
+ new,
+ order,
+ strongest_failure_ordering(order)) {
+ Ok(x) => x,
+ Err(x) => x,
+ }
}
}
- /// Stores a value into the atomic integer if the current value is the same as the
- /// `current` value.
- ///
- /// The return value is a result indicating whether the new value was written and
- /// containing the previous value. On success this value is guaranteed to be equal to
- /// `current`.
- ///
- /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
- /// ordering of this operation. The first describes the required ordering if
- /// the operation succeeds while the second describes the required ordering when
- /// the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and
- /// must be equivalent or weaker than the success ordering.
- ///
- /// [`Ordering`]: enum.Ordering.html
- /// [`Release`]: enum.Ordering.html#variant.Release
- /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let some_isize = AtomicIsize::new(5);
- ///
- /// assert_eq!(some_isize.compare_exchange(5, 10,
- /// Ordering::Acquire,
- /// Ordering::Relaxed),
- /// Ok(5));
- /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
- ///
- /// assert_eq!(some_isize.compare_exchange(6, 12,
- /// Ordering::SeqCst,
- /// Ordering::Acquire),
- /// Err(10));
- /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
- /// ```
- #[inline]
- #[$stable_cxchg]
- pub fn compare_exchange(&self,
- current: $int_type,
- new: $int_type,
- success: Ordering,
- failure: Ordering) -> Result<$int_type, $int_type> {
- unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
+ doc_comment! {
+ concat!("Stores a value into the atomic integer if the current value is the same as
+the `current` value.
+
+The return value is a result indicating whether the new value was written and
+containing the previous value. On success this value is guaranteed to be equal to
+`current`.
+
+`compare_exchange` takes two [`Ordering`] arguments to describe the memory
+ordering of this operation. The first describes the required ordering if
+the operation succeeds while the second describes the required ordering when
+the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and
+must be equivalent or weaker than the success ordering.
+
+[`Ordering`]: enum.Ordering.html
+[`Release`]: enum.Ordering.html#variant.Release
+[`AcqRel`]: enum.Ordering.html#variant.AcqRel
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let some_var = ", stringify!($atomic_type), "::new(5);
+
+assert_eq!(some_var.compare_exchange(5, 10,
+ Ordering::Acquire,
+ Ordering::Relaxed),
+ Ok(5));
+assert_eq!(some_var.load(Ordering::Relaxed), 10);
+
+assert_eq!(some_var.compare_exchange(6, 12,
+ Ordering::SeqCst,
+ Ordering::Acquire),
+ Err(10));
+assert_eq!(some_var.load(Ordering::Relaxed), 10);
+```"),
+ #[inline]
+ #[$stable_cxchg]
+ pub fn compare_exchange(&self,
+ current: $int_type,
+ new: $int_type,
+ success: Ordering,
+ failure: Ordering) -> Result<$int_type, $int_type> {
+ unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
+ }
}
- /// Stores a value into the atomic integer if the current value is the same as the
- /// `current` value.
- ///
- /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even
- /// when the comparison succeeds, which can result in more efficient code on some
- /// platforms. The return value is a result indicating whether the new value was
- /// written and containing the previous value.
- ///
- /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
- /// ordering of this operation. The first describes the required ordering if the
- /// operation succeeds while the second describes the required ordering when the
- /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and
- /// must be equivalent or weaker than the success ordering.
- ///
- /// [`compare_exchange`]: #method.compare_exchange
- /// [`Ordering`]: enum.Ordering.html
- /// [`Release`]: enum.Ordering.html#variant.Release
- /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let val = AtomicIsize::new(4);
- ///
- /// let mut old = val.load(Ordering::Relaxed);
- /// loop {
- /// let new = old * 2;
- /// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
- /// Ok(_) => break,
- /// Err(x) => old = x,
- /// }
- /// }
- /// ```
- #[inline]
- #[$stable_cxchg]
- pub fn compare_exchange_weak(&self,
- current: $int_type,
- new: $int_type,
- success: Ordering,
- failure: Ordering) -> Result<$int_type, $int_type> {
- unsafe {
- atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
+ doc_comment! {
+ concat!("Stores a value into the atomic integer if the current value is the same as
+the `current` value.
+
+Unlike [`compare_exchange`], this function is allowed to spuriously fail even
+when the comparison succeeds, which can result in more efficient code on some
+platforms. The return value is a result indicating whether the new value was
+written and containing the previous value.
+
+`compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
+ordering of this operation. The first describes the required ordering if the
+operation succeeds while the second describes the required ordering when the
+operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and
+must be equivalent or weaker than the success ordering.
+
+[`compare_exchange`]: #method.compare_exchange
+[`Ordering`]: enum.Ordering.html
+[`Release`]: enum.Ordering.html#variant.Release
+[`AcqRel`]: enum.Ordering.html#variant.AcqRel
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let val = ", stringify!($atomic_type), "::new(4);
+
+let mut old = val.load(Ordering::Relaxed);
+loop {
+ let new = old * 2;
+ match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
+ Ok(_) => break,
+ Err(x) => old = x,
+ }
+}
+```"),
+ #[inline]
+ #[$stable_cxchg]
+ pub fn compare_exchange_weak(&self,
+ current: $int_type,
+ new: $int_type,
+ success: Ordering,
+ failure: Ordering) -> Result<$int_type, $int_type> {
+ unsafe {
+ atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
+ }
}
}
- /// Adds to the current value, returning the previous value.
- ///
- /// This operation wraps around on overflow.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let foo = AtomicIsize::new(0);
- /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
- /// assert_eq!(foo.load(Ordering::SeqCst), 10);
- /// ```
- #[inline]
- #[$stable]
- pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_add(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Adds to the current value, returning the previous value.
+
+This operation wraps around on overflow.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let foo = ", stringify!($atomic_type), "::new(0);
+assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
+assert_eq!(foo.load(Ordering::SeqCst), 10);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_add(self.v.get(), val, order) }
+ }
}
- /// Subtracts from the current value, returning the previous value.
- ///
- /// This operation wraps around on overflow.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let foo = AtomicIsize::new(0);
- /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 0);
- /// assert_eq!(foo.load(Ordering::SeqCst), -10);
- /// ```
- #[inline]
- #[$stable]
- pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_sub(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Subtracts from the current value, returning the previous value.
+
+This operation wraps around on overflow.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let foo = ", stringify!($atomic_type), "::new(20);
+assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20);
+assert_eq!(foo.load(Ordering::SeqCst), 10);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_sub(self.v.get(), val, order) }
+ }
}
- /// Bitwise "and" with the current value.
- ///
- /// Performs a bitwise "and" operation on the current value and the argument `val`, and
- /// sets the new value to the result.
- ///
- /// Returns the previous value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let foo = AtomicIsize::new(0b101101);
- /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
- /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
- #[inline]
- #[$stable]
- pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_and(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Bitwise \"and\" with the current value.
+
+Performs a bitwise \"and\" operation on the current value and the argument `val`, and
+sets the new value to the result.
+
+Returns the previous value.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let foo = ", stringify!($atomic_type), "::new(0b101101);
+assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
+assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_and(self.v.get(), val, order) }
+ }
}
- /// Bitwise "nand" with the current value.
- ///
- /// Performs a bitwise "nand" operation on the current value and the argument `val`, and
- /// sets the new value to the result.
- ///
- /// Returns the previous value.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(atomic_nand)]
- ///
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let foo = AtomicIsize::new(0xf731);
- /// assert_eq!(foo.fetch_nand(0x137f, Ordering::SeqCst), 0xf731);
- /// assert_eq!(foo.load(Ordering::SeqCst), !(0xf731 & 0x137f));
- #[inline]
- #[$stable_nand]
- pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_nand(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Bitwise \"nand\" with the current value.
+
+Performs a bitwise \"nand\" operation on the current value and the argument `val`, and
+sets the new value to the result.
+
+Returns the previous value.
+
+# Examples
+
+```
+", $extra_feature, "#![feature(atomic_nand)]
+
+use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let foo = ", stringify!($atomic_type), "::new(0x13);
+assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13);
+assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
+```"),
+ #[inline]
+ #[$stable_nand]
+ pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_nand(self.v.get(), val, order) }
+ }
}
- /// Bitwise "or" with the current value.
- ///
- /// Performs a bitwise "or" operation on the current value and the argument `val`, and
- /// sets the new value to the result.
- ///
- /// Returns the previous value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let foo = AtomicIsize::new(0b101101);
- /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
- /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
- #[inline]
- #[$stable]
- pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_or(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Bitwise \"or\" with the current value.
+
+Performs a bitwise \"or\" operation on the current value and the argument `val`, and
+sets the new value to the result.
+
+Returns the previous value.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let foo = ", stringify!($atomic_type), "::new(0b101101);
+assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
+assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_or(self.v.get(), val, order) }
+ }
}
- /// Bitwise "xor" with the current value.
- ///
- /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
- /// sets the new value to the result.
- ///
- /// Returns the previous value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::atomic::{AtomicIsize, Ordering};
- ///
- /// let foo = AtomicIsize::new(0b101101);
- /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
- /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
- #[inline]
- #[$stable]
- pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
- unsafe { atomic_xor(self.v.get(), val, order) }
+ doc_comment! {
+ concat!("Bitwise \"xor\" with the current value.
+
+Performs a bitwise \"xor\" operation on the current value and the argument `val`, and
+sets the new value to the result.
+
+Returns the previous value.
+
+# Examples
+
+```
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let foo = ", stringify!($atomic_type), "::new(0b101101);
+assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
+assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
+```"),
+ #[inline]
+ #[$stable]
+ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
+ unsafe { atomic_xor(self.v.get(), val, order) }
+ }
}
}
}
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"i8", "../../../std/primitive.i8.html",
+ "#![feature(integer_atomics)]\n\n",
i8 AtomicI8 ATOMIC_I8_INIT
}
#[cfg(target_has_atomic = "8")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"u8", "../../../std/primitive.u8.html",
+ "#![feature(integer_atomics)]\n\n",
u8 AtomicU8 ATOMIC_U8_INIT
}
#[cfg(target_has_atomic = "16")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"i16", "../../../std/primitive.i16.html",
+ "#![feature(integer_atomics)]\n\n",
i16 AtomicI16 ATOMIC_I16_INIT
}
#[cfg(target_has_atomic = "16")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"u16", "../../../std/primitive.u16.html",
+ "#![feature(integer_atomics)]\n\n",
u16 AtomicU16 ATOMIC_U16_INIT
}
#[cfg(target_has_atomic = "32")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"i32", "../../../std/primitive.i32.html",
+ "#![feature(integer_atomics)]\n\n",
i32 AtomicI32 ATOMIC_I32_INIT
}
#[cfg(target_has_atomic = "32")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"u32", "../../../std/primitive.u32.html",
+ "#![feature(integer_atomics)]\n\n",
u32 AtomicU32 ATOMIC_U32_INIT
}
#[cfg(target_has_atomic = "64")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"i64", "../../../std/primitive.i64.html",
+ "#![feature(integer_atomics)]\n\n",
i64 AtomicI64 ATOMIC_I64_INIT
}
#[cfg(target_has_atomic = "64")]
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "atomic_nand", issue = "13226"),
"u64", "../../../std/primitive.u64.html",
+ "#![feature(integer_atomics)]\n\n",
u64 AtomicU64 ATOMIC_U64_INIT
}
#[cfg(target_has_atomic = "ptr")]
stable(feature = "atomic_from", since = "1.23.0"),
unstable(feature = "atomic_nand", issue = "13226"),
"isize", "../../../std/primitive.isize.html",
+ "",
isize AtomicIsize ATOMIC_ISIZE_INIT
}
#[cfg(target_has_atomic = "ptr")]
stable(feature = "atomic_from", since = "1.23.0"),
unstable(feature = "atomic_nand", issue = "13226"),
"usize", "../../../std/primitive.usize.html",
+ "",
usize AtomicUsize ATOMIC_USIZE_INIT
}
// except according to those terms.
use core::char::from_u32;
-use std::ascii::AsciiExt;
#[test]
fn test_is_ascii() {
stringify!($what), b);
}
}
- assert!($str.$what());
- assert!($str.as_bytes().$what());
)+
}};
($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+))
[] GetPanicStrategy(CrateNum),
[] IsNoBuiltins(CrateNum),
[] ImplDefaultness(DefId),
+ [] CheckItemWellFormed(DefId),
+ [] CheckTraitItemWellFormed(DefId),
+ [] CheckImplItemWellFormed(DefId),
[] ReachableNonGenerics(CrateNum),
[] NativeLibraries(CrateNum),
[] PluginRegistrarFn(CrateNum),
fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO);
}
- let nodes: IndexVec<_, (DepNode, Fingerprint)> =
- current_dep_graph.nodes.iter_enumerated().map(|(idx, &dep_node)| {
- (dep_node, fingerprints[idx])
- }).collect();
+ let fingerprints = fingerprints.clone().convert_index_type();
+ let nodes = current_dep_graph.nodes.clone().convert_index_type();
let total_edge_count: usize = current_dep_graph.edges.iter()
.map(|v| v.len())
SerializedDepGraph {
nodes,
+ fingerprints,
edge_list_indices,
edge_list_data,
}
pub fn new(data: SerializedDepGraph) -> PreviousDepGraph {
let index: FxHashMap<_, _> = data.nodes
.iter_enumerated()
- .map(|(idx, &(dep_node, _))| (dep_node, idx))
+ .map(|(idx, &dep_node)| (dep_node, idx))
.collect();
PreviousDepGraph { data, index }
}
#[inline]
pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode {
- self.data.nodes[dep_node_index].0
+ self.data.nodes[dep_node_index]
}
#[inline]
pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
self.index
.get(dep_node)
- .map(|&node_index| self.data.nodes[node_index].1)
+ .map(|&node_index| self.data.fingerprints[node_index])
}
#[inline]
pub fn fingerprint_by_index(&self,
dep_node_index: SerializedDepNodeIndex)
-> Fingerprint {
- self.data.nodes[dep_node_index].1
+ self.data.fingerprints[dep_node_index]
}
pub fn node_count(&self) -> usize {
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedDepGraph {
/// The set of all DepNodes in the graph
- pub nodes: IndexVec<SerializedDepNodeIndex, (DepNode, Fingerprint)>,
+ pub nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
+ /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
+ /// the DepNode at the same index in the nodes vector.
+ pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
pub fn new() -> SerializedDepGraph {
SerializedDepGraph {
nodes: IndexVec::new(),
+ fingerprints: IndexVec::new(),
edge_list_indices: IndexVec::new(),
edge_list_data: Vec::new(),
}
transparent wrapper around a float. This can make a difference for the ABI.
"##,
+E0909: r##"
+The `impl Trait` return type captures lifetime parameters that do not
+appear within the `impl Trait` itself.
+
+Erroneous code example:
+
+```compile-fail,E0909
+#![feature(conservative_impl_trait)]
+
+use std::cell::Cell;
+
+trait Trait<'a> { }
+
+impl<'a, 'b> Trait<'b> for Cell<&'a u32> { }
+
+fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
+where 'x: 'y
+{
+ x
+}
+```
+
+Here, the function `foo` returns a value of type `Cell<&'x u32>`,
+which references the lifetime `'x`. However, the return type is
+declared as `impl Trait<'y>` -- this indicates that `foo` returns
+"some type that implements `Trait<'y>`", but it also indicates that
+the return type **only captures data referencing the lifetime `'y`**.
+In this case, though, we are referencing data with lifetime `'x`, so
+this function is in error.
+
+To fix this, you must reference the lifetime `'x` from the return
+type. For example, changing the return type to `impl Trait<'y> + 'x`
+would work:
+
+```
+#![feature(conservative_impl_trait)]
+
+use std::cell::Cell;
+
+trait Trait<'a> { }
+
+impl<'a,'b> Trait<'b> for Cell<&'a u32> { }
+
+fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x
+where 'x: 'y
+{
+ x
+}
+```
+"##,
+
+
}
}
}
- fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
+ fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec<Attribute> {
attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into()
}
span,
pure_wrt_drop: false,
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+ attrs: P::new(),
});
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
.filter(|attr| attr.check_name("rustc_synthetic"))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.nth(0),
+ attrs: self.lower_attrs(&tp.attrs),
}
}
Some(NodeField(ref f)) => Some(&f.attrs[..]),
Some(NodeExpr(ref e)) => Some(&*e.attrs),
Some(NodeStmt(ref s)) => Some(s.node.attrs()),
+ Some(NodeTyParam(tp)) => Some(&tp.attrs[..]),
// unit/tuple structs take the attributes straight from
// the struct definition.
Some(NodeStructCtor(_)) => {
pub span: Span,
pub pure_wrt_drop: bool,
pub synthetic: Option<SyntheticTyParamKind>,
+ pub attrs: HirVec<Attribute>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
default,
span,
pure_wrt_drop,
- synthetic
+ synthetic,
+ attrs
});
impl_stable_hash_for!(enum hir::GenericParam {
use rustc_data_structures::fx::FxHashMap;
use syntax::ast;
use traits::{self, PredicateObligation};
-use ty::{self, Ty};
-use ty::fold::{BottomUpFolder, TypeFoldable};
+use ty::{self, Ty, TyCtxt};
+use ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
use ty::outlives::Component;
-use ty::subst::{Kind, UnpackedKind, Substs};
+use ty::subst::{Kind, Substs, UnpackedKind};
use util::nodemap::DefIdMap;
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
debug!(
"instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})",
- value,
- parent_def_id,
- body_id,
- param_env,
+ value, parent_def_id, body_id, param_env,
);
let mut instantiator = Instantiator {
infcx: self,
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
- let definition_ty = gcx.fold_regions(&instantiated_ty, &mut false, |r, _| {
- match *r {
- // 'static and early-bound regions are valid.
- ty::ReStatic | ty::ReEmpty => r,
-
- // All other regions, we map them appropriately to their adjusted
- // indices, erroring if we find any lifetimes that were not mapped
- // into the new set.
- _ => if let Some(UnpackedKind::Lifetime(r1)) = map.get(&r.into())
- .map(|k| k.unpack()) {
- r1
- } else {
- // No mapping was found. This means that
- // it is either a disallowed lifetime,
- // which will be caught by regionck, or it
- // is a region in a non-upvar closure
- // generic, which is explicitly
- // allowed. If that surprises you, read
- // on.
- //
- // The case of closure is a somewhat
- // subtle (read: hacky) consideration. The
- // problem is that our closure types
- // currently include all the lifetime
- // parameters declared on the enclosing
- // function, even if they are unused by
- // the closure itself. We can't readily
- // filter them out, so here we replace
- // those values with `'empty`. This can't
- // really make a difference to the rest of
- // the compiler; those regions are ignored
- // for the outlives relation, and hence
- // don't affect trait selection or auto
- // traits, and they are erased during
- // trans.
- gcx.types.re_empty
- },
- }
- });
-
+ let definition_ty =
+ instantiated_ty.fold_with(&mut ReverseMapper::new(
+ self.tcx,
+ self.is_tainted_by_errors(),
+ def_id,
+ map,
+ instantiated_ty,
+ ));
debug!(
"infer_anon_definition_from_instantiation: definition_ty={:?}",
definition_ty
);
+ // We can unwrap here because our reverse mapper always
+ // produces things with 'gcx lifetime, though the type folder
+ // obscures that.
+ let definition_ty = gcx.lift(&definition_ty).unwrap();
+
definition_ty
}
}
+struct ReverseMapper<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
+ tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+
+ /// If errors have already been reported in this fn, we suppress
+ /// our own errors because they are sometimes derivative.
+ tainted_by_errors: bool,
+
+ anon_type_def_id: DefId,
+ map: FxHashMap<Kind<'tcx>, Kind<'gcx>>,
+ map_missing_regions_to_empty: bool,
+
+ /// initially `Some`, set to `None` once error has been reported
+ hidden_ty: Option<Ty<'tcx>>,
+}
+
+impl<'cx, 'gcx, 'tcx> ReverseMapper<'cx, 'gcx, 'tcx> {
+ fn new(
+ tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+ tainted_by_errors: bool,
+ anon_type_def_id: DefId,
+ map: FxHashMap<Kind<'tcx>, Kind<'gcx>>,
+ hidden_ty: Ty<'tcx>,
+ ) -> Self {
+ Self {
+ tcx,
+ tainted_by_errors,
+ anon_type_def_id,
+ map,
+ map_missing_regions_to_empty: false,
+ hidden_ty: Some(hidden_ty),
+ }
+ }
+
+ fn fold_kind_mapping_missing_regions_to_empty(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
+ assert!(!self.map_missing_regions_to_empty);
+ self.map_missing_regions_to_empty = true;
+ let kind = kind.fold_with(self);
+ self.map_missing_regions_to_empty = false;
+ kind
+ }
+
+ fn fold_kind_normally(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
+ assert!(!self.map_missing_regions_to_empty);
+ kind.fold_with(self)
+ }
+}
+
+impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
+ self.tcx
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match r {
+ // ignore bound regions that appear in the type (e.g., this
+ // would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
+ ty::ReLateBound(..) => return r,
+
+ // ignore `'static`, as that can appear anywhere
+ ty::ReStatic => return r,
+
+ _ => { }
+ }
+
+ match self.map.get(&r.into()).map(|k| k.unpack()) {
+ Some(UnpackedKind::Lifetime(r1)) => r1,
+ Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
+ None => {
+ if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
+ if let Some(hidden_ty) = self.hidden_ty.take() {
+ let span = self.tcx.def_span(self.anon_type_def_id);
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0909,
+ "hidden type for `impl Trait` captures lifetime that \
+ does not appear in bounds",
+ );
+
+ // Assuming regionck succeeded, then we must
+ // be capturing *some* region from the fn
+ // header, and hence it must be free, so it's
+ // ok to invoke this fn (which doesn't accept
+ // all regions, and would ICE if an
+ // inappropriate region is given). We check
+ // `is_tainted_by_errors` by errors above, so
+ // we don't get in here unless regionck
+ // succeeded. (Note also that if regionck
+ // failed, then the regions we are attempting
+ // to map here may well be giving errors
+ // *because* the constraints were not
+ // satisfiable.)
+ self.tcx.note_and_explain_free_region(
+ &mut err,
+ &format!("hidden type `{}` captures ", hidden_ty),
+ r,
+ ""
+ );
+
+ err.emit();
+ }
+ }
+ self.tcx.types.re_empty
+ },
+ }
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ match ty.sty {
+ ty::TyClosure(def_id, substs) => {
+ // I am a horrible monster and I pray for death. When
+ // we encounter a closure here, it is always a closure
+ // from within the function that we are currently
+ // type-checking -- one that is now being encapsulated
+ // in an existential abstract type. Ideally, we would
+ // go through the types/lifetimes that it references
+ // and treat them just like we would any other type,
+ // which means we would error out if we find any
+ // reference to a type/region that is not in the
+ // "reverse map".
+ //
+ // **However,** in the case of closures, there is a
+ // somewhat subtle (read: hacky) consideration. The
+ // problem is that our closure types currently include
+ // all the lifetime parameters declared on the
+ // enclosing function, even if they are unused by the
+ // closure itself. We can't readily filter them out,
+ // so here we replace those values with `'empty`. This
+ // can't really make a difference to the rest of the
+ // compiler; those regions are ignored for the
+ // outlives relation, and hence don't affect trait
+ // selection or auto traits, and they are erased
+ // during trans.
+
+ let generics = self.tcx.generics_of(def_id);
+ let parent_len = generics.parent_count();
+ let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map(
+ |(index, &kind)| {
+ if index < parent_len {
+ // Accommodate missing regions in the parent kinds...
+ self.fold_kind_mapping_missing_regions_to_empty(kind)
+ } else {
+ // ...but not elsewhere.
+ self.fold_kind_normally(kind)
+ }
+ },
+ ));
+
+ self.tcx.mk_closure(def_id, ty::ClosureSubsts { substs })
+ }
+
+ _ => ty.super_fold_with(self),
+ }
+ }
+}
+
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
parent_def_id: DefId,
return self.fold_anon_ty(ty, def_id, substs);
}
- debug!("instantiate_anon_types_in_map: \
- encountered anon with wrong parent \
- def_id={:?} \
- anon_parent_def_id={:?}",
- def_id,
- anon_parent_def_id);
+ debug!(
+ "instantiate_anon_types_in_map: \
+ encountered anon with wrong parent \
+ def_id={:?} \
+ anon_parent_def_id={:?}",
+ def_id, anon_parent_def_id
+ );
}
}
debug!(
"instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})",
- def_id,
- substs
+ def_id, substs
);
// Use the same type variable if the exact same TyAnon appears more
return anon_defn.concrete_ty;
}
let span = tcx.def_span(def_id);
- let ty_var = infcx.next_ty_var(ty::UniverseIndex::ROOT,
- TypeVariableOrigin::TypeInference(span));
+ let ty_var = infcx.next_ty_var(
+ ty::UniverseIndex::ROOT,
+ TypeVariableOrigin::TypeInference(span),
+ );
let predicates_of = tcx.predicates_of(def_id);
let bounds = predicates_of.instantiate(tcx, substs);
use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags};
use ty::subst::{Kind, UnpackedKind};
use ty::fold::{TypeFoldable, TypeFolder};
+use util::captures::Captures;
use util::common::CellUsizeExt;
use rustc_data_structures::indexed_vec::IndexVec;
param_env: ty::ParamEnv<'tcx>,
unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>,
result_subst: &'a CanonicalVarValues<'tcx>,
- ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
+ ) -> impl Iterator<Item = PredicateObligation<'tcx>> + Captures<'gcx> + 'a {
let QueryRegionConstraints {
region_outlives,
ty_outlives,
pub mod ty;
pub mod util {
+ pub mod captures;
pub mod common;
pub mod ppaux;
pub mod nodemap;
use ty::fast_reject::{self, SimplifiedType};
use rustc_data_structures::sync::Lrc;
use syntax::ast::Name;
+use util::captures::Captures;
use util::nodemap::{DefIdMap, FxHashMap};
/// A per-trait graph of impls in specialization order. At the moment, this
}
/// Iterate over the items defined directly by the given (impl or trait) node.
- #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
- pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
- -> impl Iterator<Item = ty::AssociatedItem> + 'a {
+ pub fn items(
+ &self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ ) -> impl Iterator<Item = ty::AssociatedItem> + 'a {
tcx.associated_items(self.def_id())
}
/// Search the items from the given ancestors, returning each definition
/// with the given name and the given kind.
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
- pub fn defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_item_name: Name,
- trait_item_kind: ty::AssociatedKind, trait_def_id: DefId)
- -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + 'a {
+ pub fn defs(
+ self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ trait_item_name: Name,
+ trait_item_kind: ty::AssociatedKind,
+ trait_def_id: DefId,
+ ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
self.flat_map(move |node| {
node.items(tcx).filter(move |impl_item| {
impl_item.kind == trait_item_kind &&
[] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness,
+ [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (),
+ [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (),
+ [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (),
+
// The DefIds of all non-generic functions and statics in the given crate
// that can be reached from outside the crate.
//
DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); }
DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); }
DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); }
+ DepKind::CheckItemWellFormed => { force!(check_item_well_formed, def_id!()); }
+ DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); }
+ DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); }
DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); }
DepKind::NativeLibraries => { force!(native_libraries, krate!()); }
DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); }
use ty::subst::{Subst, Substs};
use ty::util::{IntTypeExt, Discr};
use ty::walk::TypeWalker;
+use util::captures::Captures;
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use serialize::{self, Encodable, Encoder};
}
#[inline]
- pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
- -> impl Iterator<Item=Discr<'tcx>> + 'a {
+ pub fn discriminants(
+ &'a self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ ) -> impl Iterator<Item=Discr<'tcx>> + Captures<'gcx> + 'a {
let repr_type = self.repr.discr_type();
let initial = repr_type.initial_discriminant(tcx.global_tcx());
let mut prev_discr = None::<Discr<'tcx>>;
/// Returns an iterator of the def-ids for all body-owners in this
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir.krate().body_ids.iter()`.
- pub fn body_owners(self) -> impl Iterator<Item = DefId> + 'a {
+ pub fn body_owners(
+ self,
+ ) -> impl Iterator<Item = DefId> + Captures<'tcx> + Captures<'gcx> + 'a {
self.hir.krate()
.body_ids
.iter()
}
}
- #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
- pub fn associated_items(self, def_id: DefId)
- -> impl Iterator<Item = ty::AssociatedItem> + 'a {
+ pub fn associated_items(
+ self,
+ def_id: DefId,
+ ) -> impl Iterator<Item = ty::AssociatedItem> + 'a {
let def_ids = self.associated_item_def_ids(def_id);
- (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i]))
+ Box::new((0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])))
+ as Box<dyn Iterator<Item = ty::AssociatedItem> + 'a>
}
/// Returns true if the impls are the same polarity and are implementing
use ty::subst::{Substs, Subst, Kind, UnpackedKind};
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
+use util::captures::Captures;
use std::iter;
use std::cmp::Ordering;
/// This returns the types of the MIR locals which had to be stored across suspension points.
/// It is calculated in rustc_mir::transform::generator::StateTransform.
/// All the types here must be in the tuple in GeneratorInterior.
- pub fn state_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
- impl Iterator<Item=Ty<'tcx>> + 'a
- {
+ pub fn state_tys(
+ self,
+ def_id: DefId,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ ) -> impl Iterator<Item=Ty<'tcx>> + Captures<'gcx> + 'a {
let state = tcx.generator_layout(def_id).fields.iter();
state.map(move |d| d.ty.subst(tcx, self.substs))
}
/// This is the types of all the fields stored in a generator.
/// It includes the upvars, state types and the state discriminant which is u32.
pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
- impl Iterator<Item=Ty<'tcx>> + 'a
+ impl Iterator<Item=Ty<'tcx>> + Captures<'gcx> + 'a
{
self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx))
}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// "Signaling" trait used in impl trait to tag lifetimes that you may
+/// need to capture but don't really need for other reasons.
+/// Basically a workaround; see [this comment] for details.
+///
+/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
+pub trait Captures<'a> { }
+
+impl<'a, T: ?Sized> Captures<'a> for T { }
(c1, c2)
}
}
+
+ pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
+ IndexVec {
+ raw: self.raw,
+ _marker: PhantomData,
+ }
+ }
}
impl<I: Idx, T: Clone> IndexVec<I, T> {
let mut counts: FxHashMap<_, Stat> = FxHashMap();
- for (i, &(node, _)) in serialized_graph.nodes.iter_enumerated() {
+ for (i, &node) in serialized_graph.nodes.iter_enumerated() {
let stat = counts.entry(node.kind).or_insert(Stat {
kind: node.kind,
node_counter: 0,
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::codec::TyDecoder;
use rustc::mir::Mir;
+use rustc::util::captures::Captures;
use rustc::util::nodemap::FxHashMap;
use std::collections::BTreeMap;
}
impl<'a, 'tcx: 'a, T: Decodable> LazySeq<T> {
- pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> impl Iterator<Item = T> + 'a {
+ pub fn decode<M: Metadata<'a, 'tcx>>(
+ self,
+ meta: M,
+ ) -> impl Iterator<Item = T> + Captures<'tcx> + 'a {
let mut dcx = meta.decoder(self.position);
dcx.lazy_state = LazyState::NodeStart(self.position);
(0..self.len).map(move |_| T::decode(&mut dcx).unwrap())
// Evaluate the initializer, if present.
if let Some(init) = initializer {
unpack!(block = this.in_opt_scope(
- opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
+ opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
let scope = (init_scope, source_info);
- this.in_scope(scope, lint_level, block, move |this| {
- // FIXME #30046 ^~~~
+ this.in_scope(scope, lint_level, block, |this| {
this.expr_into_pattern(block, pattern, init)
})
}));
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId> {
+ let alloc = ecx
+ .tcx
+ .interpret_interner
+ .get_cached(cid.instance.def_id());
+ // Don't evaluate when already cached to prevent cycles
+ if let Some(alloc) = alloc {
+ return Ok(alloc)
+ }
// ensure the static is computed
ecx.const_eval(cid)?;
Ok(ecx
},
Static(ref static_) => {
- let alloc = self
- .tcx
- .interpret_interner
- .get_cached(static_.def_id);
let layout = self.layout_of(self.place_ty(mir_place))?;
- if let Some(alloc) = alloc {
- Place::Ptr {
- ptr: MemoryPointer::new(alloc, 0).into(),
- align: layout.align,
- extra: PlaceExtra::None,
- }
- } else {
- let instance = ty::Instance::mono(*self.tcx, static_.def_id);
- let cid = GlobalId {
- instance,
- promoted: None
- };
- let alloc = Machine::init_static(self, cid)?;
- Place::Ptr {
- ptr: MemoryPointer::new(alloc, 0).into(),
- align: layout.align,
- extra: PlaceExtra::None,
- }
+ let instance = ty::Instance::mono(*self.tcx, static_.def_id);
+ let cid = GlobalId {
+ instance,
+ promoted: None
+ };
+ let alloc = Machine::init_static(self, cid)?;
+ Place::Ptr {
+ ptr: MemoryPointer::new(alloc, 0).into(),
+ align: layout.align,
+ extra: PlaceExtra::None,
}
}
});
}
DropStyle::Conditional => {
- let unwind = self.unwind; // FIXME(#6393)
+ let unwind = self.unwind; // FIXME(#43234)
let succ = self.succ;
let drop_bb = self.complete_drop(Some(DropFlagMode::Deep), succ, unwind);
self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto {
// Clear the "master" drop flag at the end. This is needed
// because the "master" drop protects the ADT's discriminant,
// which is invalidated after the ADT is dropped.
- let (succ, unwind) = (self.succ, self.unwind); // FIXME(#6393)
+ let (succ, unwind) = (self.succ, self.unwind); // FIXME(#43234)
(
self.drop_flag_reset_block(DropFlagMode::Shallow, succ, unwind),
unwind.map(|unwind| {
let interior = self.place.clone().deref();
let interior_path = self.elaborator.deref_subpath(self.path);
- let succ = self.succ; // FIXME(#6393)
+ let succ = self.succ; // FIXME(#43234)
let unwind = self.unwind;
let succ = self.box_free_block(ty, succ, unwind);
let unwind_succ = self.unwind.map(|unwind| {
ptr_based)
});
- let succ = self.succ; // FIXME(#6393)
+ let succ = self.succ; // FIXME(#43234)
let loop_block = self.drop_loop(
succ,
cur,
self.open_drop_for_adt(def, substs)
}
ty::TyDynamic(..) => {
- let unwind = self.unwind; // FIXME(#6393)
+ let unwind = self.unwind; // FIXME(#43234)
let succ = self.succ;
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
}
fn elaborated_drop_block<'a>(&mut self) -> BasicBlock {
debug!("elaborated_drop_block({:?})", self);
- let unwind = self.unwind; // FIXME(#6393)
+ let unwind = self.unwind; // FIXME(#43234)
let succ = self.succ;
let blk = self.drop_block(succ, unwind);
self.elaborate_drop(blk);
args: vec![Operand::Move(self.place.clone())],
destination: Some((unit_temp, target)),
cleanup: None
- }; // FIXME(#6393)
+ }; // FIXME(#43234)
let free_block = self.new_block(unwind, call);
let block_start = Location { block: free_block, statement_index: 0 };
}
}
hir::ExprMethodCall(..) => {
- let def_id = v.tables.type_dependent_defs()[e.hir_id].def_id();
- match v.tcx.associated_item(def_id).container {
- ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty),
- ty::TraitContainer(_) => v.promotable = false
+ if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
+ let def_id = def.def_id();
+ match v.tcx.associated_item(def_id).container {
+ ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty),
+ ty::TraitContainer(_) => v.promotable = false
+ }
+ } else {
+ v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call");
}
}
hir::ExprStruct(..) => {
if names.is_empty() {
import_directive_subclass_to_string(subclass)
} else {
- // FIXME: Remove this entire logic after #48116 is fixed.
- //
- // Note that this code looks a little wonky, it's currently here to
- // hopefully help debug #48116, but otherwise isn't intended to
- // cause any problems.
- let x = format!(
- "{}::{}",
- names_to_string(names),
- import_directive_subclass_to_string(subclass),
- );
- if names.is_empty() || x.starts_with("::") {
- span_bug!(
- span,
- "invalid name `{}` at {:?}; global = {}, names = {:?}, subclass = {:?}",
- x,
- span,
- global,
- names,
- subclass
- );
- }
- return x
+ format!("{}::{}",
+ names_to_string(names),
+ import_directive_subclass_to_string(subclass))
}
}
}
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::ty::{self, TyCtxt};
+use rustc::ty::subst::Substs;
use rustc::traits::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom};
use syntax::ast;
use rustc_data_structures::sync::Lrc;
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let item = tcx.hir.expect_item(node_id);
match item.node {
+ hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
// FIXME: other constructions e.g. traits, associated types...
}
}
+fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> Lrc<Vec<Clause<'tcx>>>
+{
+ // Rule Implemented-From-Env (see rustc guide)
+ //
+ // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
+ //
+ // ```
+ // forall<Self, P1..Pn> {
+ // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
+ // }
+ // ```
+
+ // `Self: Trait<P1..Pn>`
+ let trait_pred = ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id,
+ substs: Substs::identity_for_item(tcx, def_id)
+ }
+ };
+ // `FromEnv(Self: Trait<P1..Pn>)`
+ let from_env = Goal::DomainGoal(DomainGoal::FromEnv(trait_pred.lower()));
+ // `Implemented(Self: Trait<P1..Pn>)`
+ let impl_trait = DomainGoal::Holds(WhereClauseAtom::Implemented(trait_pred));
+
+ // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
+ let clause = Clause::Implies(vec![from_env], impl_trait);
+ Lrc::new(vec![clause])
+}
+
fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Lrc<Vec<Clause<'tcx>>>
{
return Lrc::new(vec![]);
}
- // Rule Implemented-From-Impl
+ // Rule Implemented-From-Impl (see rustc guide)
+ //
+ // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
//
- // (see rustc guide)
+ // ```
+ // forall<P0..Pn> {
+ // Implemented(A0: Trait<A1..An>) :- WC
+ // }
+ // ```
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
- let trait_ref = ty::TraitPredicate { trait_ref }.lower();
+ // `Implemented(A0: Trait<A1..An>)`
+ let trait_pred = ty::TraitPredicate { trait_ref }.lower();
+ // `WC`
let where_clauses = tcx.predicates_of(def_id).predicates.lower();
- let clause = Clause::Implies(where_clauses, trait_ref);
+ // `Implemented(A0: Trait<A1..An>) :- WC`
+ let clause = Clause::Implies(where_clauses, trait_pred);
Lrc::new(vec![clause])
}
pub fn provide(providers: &mut Providers) {
providers.target_features_whitelist = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
- Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
- .iter()
- .map(|c| c.to_string())
- .collect())
+ if tcx.sess.opts.actually_rustdoc {
+ // rustdoc needs to be able to document functions that use all the features, so
+ // whitelist them all
+ Lrc::new(llvm_util::all_known_features()
+ .map(|c| c.to_string())
+ .collect())
+ } else {
+ Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
+ .iter()
+ .map(|c| c.to_string())
+ .collect())
+ }
};
}
pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmin");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, true);
+ let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false);
if instr.is_null() {
bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
}
pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmax");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, true);
+ let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false);
if instr.is_null() {
bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
}
pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmin_fast");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, false);
+ let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true);
if instr.is_null() {
bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
}
pub fn vector_reduce_fmax_fast(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmax_fast");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, false);
+ let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true);
if instr.is_null() {
bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
}
const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"];
+/// When rustdoc is running, provide a list of all known features so that all their respective
+/// primtives may be documented.
+///
+/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
+/// iterator!
+pub fn all_known_features() -> impl Iterator<Item=&'static str> {
+ ARM_WHITELIST.iter().cloned()
+ .chain(AARCH64_WHITELIST.iter().cloned())
+ .chain(X86_WHITELIST.iter().cloned())
+ .chain(HEXAGON_WHITELIST.iter().cloned())
+ .chain(POWERPC_WHITELIST.iter().cloned())
+ .chain(MIPS_WHITELIST.iter().cloned())
+}
+
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
let arch = if sess.target.target.arch == "x86_64" {
"x86"
//! paths etc in all kinds of annoying scenarios.
use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::ty::TyCtxt;
use syntax::ast;
tcx.dep_graph.with_ignore(|| {
let mut visitor = SymbolNamesTest { tcx: tcx };
- // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
- tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+ tcx.hir.krate().visit_all_item_likes(&mut visitor);
})
}
}
}
-impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
- fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::None
- }
-
+impl<'a, 'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.process_attrs(item.id);
- intravisit::walk_item(self, item);
}
- fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
- self.process_attrs(ti.id);
- intravisit::walk_trait_item(self, ti)
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.process_attrs(trait_item.id);
}
- fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
- self.process_attrs(ii.id);
- intravisit::walk_impl_item(self, ii)
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+ self.process_attrs(impl_item.id);
}
}
})?)
}
+fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+ wfcheck::check_item_well_formed(tcx, def_id);
+}
+
+fn check_trait_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+ wfcheck::check_trait_item(tcx, def_id);
+}
+
+fn check_impl_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+ wfcheck::check_impl_item(tcx, def_id);
+}
+
pub fn provide(providers: &mut Providers) {
*providers = Providers {
typeck_item_bodies,
has_typeck_tables,
adt_destructor,
used_trait_imports,
+ check_item_well_formed,
+ check_trait_item_well_formed,
+ check_impl_item_well_formed,
..*providers
};
}
let origin = self.misc(call_span);
let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
- // FIXME(#15760) can't use try! here, FromError doesn't default
+ // FIXME(#27336) can't use ? here, Try::from_error doesn't default
// to identity so the resulting type is not constrained.
match ures {
Ok(ok) => {
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
- let result = self.save_and_restore_in_snapshot_flag(|_| {
+ self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = FulfillmentContext::new();
- let ok = ok; // FIXME(#30046)
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
- });
-
- match result {
- Ok(()) => { }
- Err(_) => return Err(()),
- }
+ }).map_err(|_| ())?;
}
Err(_) => return Err(()),
}
.upvar_tys(closure_def_id, self.tcx)
.zip(final_upvar_tys)
{
- self.demand_eqtype(span, final_upvar_ty, upvar_ty);
+ self.demand_suptype(span, upvar_ty, final_upvar_ty);
}
// If we are also inferred the closure kind here,
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir;
-pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- code: ObligationCauseCode<'tcx>,
-}
-
/// Helper type of a temporary returned by .for_item(...).
/// Necessary because we can't write the following bound:
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>).
struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
- code: ObligationCauseCode<'gcx>,
id: ast::NodeId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
fn with_fcx<F>(&'tcx mut self, f: F) where
F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>,
- &mut CheckTypeWellFormedVisitor<'b, 'gcx>) -> Vec<Ty<'tcx>>
+ TyCtxt<'b, 'gcx, 'gcx>) -> Vec<Ty<'tcx>>
{
- let code = self.code.clone();
let id = self.id;
let span = self.span;
let param_env = self.param_env;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, param_env, id);
- let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
- tcx: fcx.tcx.global_tcx(),
- code,
- });
+ let wf_tys = f(&fcx, fcx.tcx.global_tcx());
fcx.select_all_obligations_or_error();
fcx.regionck_item(id, span, &wf_tys);
});
}
}
-impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
- pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
- -> CheckTypeWellFormedVisitor<'a, 'gcx> {
- CheckTypeWellFormedVisitor {
- tcx,
- code: ObligationCauseCode::MiscObligation
- }
- }
-
- /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
- /// well-formed, meaning that they do not require any constraints not declared in the struct
- /// definition itself. For example, this definition would be illegal:
- ///
- /// struct Ref<'a, T> { x: &'a T }
- ///
- /// because the type did not declare that `T:'a`.
- ///
- /// We do this check as a pre-pass before checking fn bodies because if these constraints are
- /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
- /// the types first.
- fn check_item_well_formed(&mut self, item: &hir::Item) {
- let tcx = self.tcx;
- debug!("check_item_well_formed(it.id={}, it.name={})",
- item.id,
- tcx.item_path_str(tcx.hir.local_def_id(item.id)));
-
- match item.node {
- // Right now we check that every default trait implementation
- // has an implementation of itself. Basically, a case like:
- //
- // `impl Trait for T {}`
- //
- // has a requirement of `T: Trait` which was required for default
- // method implementations. Although this could be improved now that
- // there's a better infrastructure in place for this, it's being left
- // for a follow-up work.
- //
- // Since there's such a requirement, we need to check *just* positive
- // implementations, otherwise things like:
- //
- // impl !Send for T {}
- //
- // won't be allowed unless there's an *explicit* implementation of `Send`
- // for `T`
- hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => {
- let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id))
- .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
- if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
- tcx.sess.span_err(item.span, "impls of auto traits cannot be default");
- }
- if polarity == hir::ImplPolarity::Positive {
- self.check_impl(item, self_ty, trait_ref);
- } else {
- // FIXME(#27579) what amount of WF checking do we need for neg impls?
- if trait_ref.is_some() && !is_auto {
- span_err!(tcx.sess, item.span, E0192,
- "negative impls are only allowed for \
- auto traits (e.g., `Send` and `Sync`)")
- }
- }
- }
- hir::ItemFn(..) => {
- self.check_item_fn(item);
- }
- hir::ItemStatic(..) => {
- self.check_item_type(item);
+/// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
+/// well-formed, meaning that they do not require any constraints not declared in the struct
+/// definition itself. For example, this definition would be illegal:
+///
+/// struct Ref<'a, T> { x: &'a T }
+///
+/// because the type did not declare that `T:'a`.
+///
+/// We do this check as a pre-pass before checking fn bodies because if these constraints are
+/// not included it frequently leads to confusing errors in fn bodies. So it's better to check
+/// the types first.
+pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let item = tcx.hir.expect_item(node_id);
+
+ debug!("check_item_well_formed(it.id={}, it.name={})",
+ item.id,
+ tcx.item_path_str(def_id));
+
+ match item.node {
+ // Right now we check that every default trait implementation
+ // has an implementation of itself. Basically, a case like:
+ //
+ // `impl Trait for T {}`
+ //
+ // has a requirement of `T: Trait` which was required for default
+ // method implementations. Although this could be improved now that
+ // there's a better infrastructure in place for this, it's being left
+ // for a follow-up work.
+ //
+ // Since there's such a requirement, we need to check *just* positive
+ // implementations, otherwise things like:
+ //
+ // impl !Send for T {}
+ //
+ // won't be allowed unless there's an *explicit* implementation of `Send`
+ // for `T`
+ hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => {
+ let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id))
+ .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+ if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
+ tcx.sess.span_err(item.span, "impls of auto traits cannot be default");
}
- hir::ItemConst(..) => {
- self.check_item_type(item);
+ if polarity == hir::ImplPolarity::Positive {
+ check_impl(tcx, item, self_ty, trait_ref);
+ } else {
+ // FIXME(#27579) what amount of WF checking do we need for neg impls?
+ if trait_ref.is_some() && !is_auto {
+ span_err!(tcx.sess, item.span, E0192,
+ "negative impls are only allowed for \
+ auto traits (e.g., `Send` and `Sync`)")
+ }
}
- hir::ItemStruct(ref struct_def, ref ast_generics) => {
- self.check_type_defn(item, false, |fcx| {
- vec![fcx.non_enum_variant(struct_def)]
- });
+ }
+ hir::ItemFn(..) => {
+ check_item_fn(tcx, item);
+ }
+ hir::ItemStatic(..) => {
+ check_item_type(tcx, item);
+ }
+ hir::ItemConst(..) => {
+ check_item_type(tcx, item);
+ }
+ hir::ItemStruct(ref struct_def, ref ast_generics) => {
+ check_type_defn(tcx, item, false, |fcx| {
+ vec![fcx.non_enum_variant(struct_def)]
+ });
- self.check_variances_for_type_defn(item, ast_generics);
- }
- hir::ItemUnion(ref struct_def, ref ast_generics) => {
- self.check_type_defn(item, true, |fcx| {
- vec![fcx.non_enum_variant(struct_def)]
- });
+ check_variances_for_type_defn(tcx, item, ast_generics);
+ }
+ hir::ItemUnion(ref struct_def, ref ast_generics) => {
+ check_type_defn(tcx, item, true, |fcx| {
+ vec![fcx.non_enum_variant(struct_def)]
+ });
- self.check_variances_for_type_defn(item, ast_generics);
- }
- hir::ItemEnum(ref enum_def, ref ast_generics) => {
- self.check_type_defn(item, true, |fcx| {
- fcx.enum_variants(enum_def)
- });
+ check_variances_for_type_defn(tcx, item, ast_generics);
+ }
+ hir::ItemEnum(ref enum_def, ref ast_generics) => {
+ check_type_defn(tcx, item, true, |fcx| {
+ fcx.enum_variants(enum_def)
+ });
- self.check_variances_for_type_defn(item, ast_generics);
- }
- hir::ItemTrait(..) => {
- self.check_trait(item);
- }
- _ => {}
+ check_variances_for_type_defn(tcx, item, ast_generics);
}
+ hir::ItemTrait(..) => {
+ check_trait(tcx, item);
+ }
+ _ => {}
}
+}
- fn check_associated_item(&mut self,
- item_id: ast::NodeId,
- span: Span,
- sig_if_method: Option<&hir::MethodSig>) {
- let code = self.code.clone();
- self.for_id(item_id, span).with_fcx(|fcx, this| {
- let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
-
- let (mut implied_bounds, self_ty) = match item.container {
- ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
- ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
- fcx.tcx.type_of(def_id))
- };
+pub fn check_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let trait_item = tcx.hir.expect_trait_item(node_id);
+
+ let method_sig = match trait_item.node {
+ hir::TraitItemKind::Method(ref sig, _) => Some(sig),
+ _ => None
+ };
+ check_associated_item(tcx, trait_item.id, trait_item.span, method_sig);
+}
+
+pub fn check_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let impl_item = tcx.hir.expect_impl_item(node_id);
+
+ let method_sig = match impl_item.node {
+ hir::ImplItemKind::Method(ref sig, _) => Some(sig),
+ _ => None
+ };
+ check_associated_item(tcx, impl_item.id, impl_item.span, method_sig);
+}
+
+fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item_id: ast::NodeId,
+ span: Span,
+ sig_if_method: Option<&hir::MethodSig>) {
+ let code = ObligationCauseCode::MiscObligation;
+ for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
+ let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
+
+ let (mut implied_bounds, self_ty) = match item.container {
+ ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
+ ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
+ fcx.tcx.type_of(def_id))
+ };
- match item.kind {
- ty::AssociatedKind::Const => {
+ match item.kind {
+ ty::AssociatedKind::Const => {
+ let ty = fcx.tcx.type_of(item.def_id);
+ let ty = fcx.normalize_associated_types_in(span, &ty);
+ fcx.register_wf_obligation(ty, span, code.clone());
+ }
+ ty::AssociatedKind::Method => {
+ reject_shadowing_type_parameters(fcx.tcx, item.def_id);
+ let sig = fcx.tcx.fn_sig(item.def_id);
+ let sig = fcx.normalize_associated_types_in(span, &sig);
+ check_fn_or_method(tcx, fcx, span, sig,
+ item.def_id, &mut implied_bounds);
+ let sig_if_method = sig_if_method.expect("bad signature for method");
+ check_method_receiver(fcx, sig_if_method, &item, self_ty);
+ }
+ ty::AssociatedKind::Type => {
+ if item.defaultness.has_value() {
let ty = fcx.tcx.type_of(item.def_id);
let ty = fcx.normalize_associated_types_in(span, &ty);
fcx.register_wf_obligation(ty, span, code.clone());
}
- ty::AssociatedKind::Method => {
- reject_shadowing_type_parameters(fcx.tcx, item.def_id);
- let sig = fcx.tcx.fn_sig(item.def_id);
- let sig = fcx.normalize_associated_types_in(span, &sig);
- this.check_fn_or_method(fcx, span, sig,
- item.def_id, &mut implied_bounds);
- let sig_if_method = sig_if_method.expect("bad signature for method");
- this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
- }
- ty::AssociatedKind::Type => {
- if item.defaultness.has_value() {
- let ty = fcx.tcx.type_of(item.def_id);
- let ty = fcx.normalize_associated_types_in(span, &ty);
- fcx.register_wf_obligation(ty, span, code.clone());
- }
- }
}
+ }
- implied_bounds
- })
- }
-
- fn for_item<'tcx>(&self, item: &hir::Item)
- -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
- self.for_id(item.id, item.span)
- }
+ implied_bounds
+ })
+}
- fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
+fn for_item<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, item: &hir::Item)
-> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
- let def_id = self.tcx.hir.local_def_id(id);
- CheckWfFcxBuilder {
- inherited: Inherited::build(self.tcx, def_id),
- code: self.code.clone(),
- id,
- span,
- param_env: self.tcx.param_env(def_id),
- }
+ for_id(tcx, item.id, item.span)
+}
+
+fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId, span: Span)
+ -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
+ let def_id = tcx.hir.local_def_id(id);
+ CheckWfFcxBuilder {
+ inherited: Inherited::build(tcx, def_id),
+ id,
+ span,
+ param_env: tcx.param_env(def_id),
}
+}
- /// In a type definition, we check that to ensure that the types of the fields are well-formed.
- fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F)
- where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec<AdtVariant<'tcx>>
- {
- self.for_item(item).with_fcx(|fcx, this| {
- let variants = lookup_fields(fcx);
- let def_id = fcx.tcx.hir.local_def_id(item.id);
- let packed = fcx.tcx.adt_def(def_id).repr.packed();
-
- for variant in &variants {
- // For DST, or when drop needs to copy things around, all
- // intermediate types must be sized.
- let needs_drop_copy = || {
- packed && {
- let ty = variant.fields.last().unwrap().ty;
- let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(this.tcx)
- .unwrap_or_else(|| {
- span_bug!(item.span, "inference variables in {:?}", ty)
- });
- ty.needs_drop(this.tcx, this.tcx.param_env(def_id))
- }
- };
- let unsized_len = if
- all_sized ||
- variant.fields.is_empty() ||
- needs_drop_copy()
- {
- 0
- } else {
- 1
- };
- for field in &variant.fields[..variant.fields.len() - unsized_len] {
- fcx.register_bound(
- field.ty,
- fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
- traits::ObligationCause::new(field.span,
- fcx.body_id,
- traits::FieldSized(match item.node.adt_kind() {
- Some(i) => i,
- None => bug!(),
- })));
+/// In a type definition, we check that to ensure that the types of the fields are well-formed.
+fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item: &hir::Item, all_sized: bool, mut lookup_fields: F)
+ where F: for<'fcx, 'gcx, 'tcx2> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx2>) -> Vec<AdtVariant<'tcx2>>
+{
+ for_item(tcx, item).with_fcx(|fcx, fcx_tcx| {
+ let variants = lookup_fields(fcx);
+ let def_id = fcx.tcx.hir.local_def_id(item.id);
+ let packed = fcx.tcx.adt_def(def_id).repr.packed();
+
+ for variant in &variants {
+ // For DST, or when drop needs to copy things around, all
+ // intermediate types must be sized.
+ let needs_drop_copy = || {
+ packed && {
+ let ty = variant.fields.last().unwrap().ty;
+ let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(fcx_tcx)
+ .unwrap_or_else(|| {
+ span_bug!(item.span, "inference variables in {:?}", ty)
+ });
+ ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id))
}
+ };
+ let unsized_len = if
+ all_sized ||
+ variant.fields.is_empty() ||
+ needs_drop_copy()
+ {
+ 0
+ } else {
+ 1
+ };
+ for field in &variant.fields[..variant.fields.len() - unsized_len] {
+ fcx.register_bound(
+ field.ty,
+ fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
+ traits::ObligationCause::new(field.span,
+ fcx.body_id,
+ traits::FieldSized(match item.node.adt_kind() {
+ Some(i) => i,
+ None => bug!(),
+ })));
+ }
- // All field types must be well-formed.
- for field in &variant.fields {
- fcx.register_wf_obligation(field.ty, field.span, this.code.clone())
- }
+ // All field types must be well-formed.
+ for field in &variant.fields {
+ fcx.register_wf_obligation(field.ty, field.span,
+ ObligationCauseCode::MiscObligation)
}
+ }
- self.check_where_clauses(fcx, item.span, def_id);
+ check_where_clauses(tcx, fcx, item.span, def_id);
- vec![] // no implied bounds in a struct def'n
- });
- }
+ vec![] // no implied bounds in a struct def'n
+ });
+}
- fn check_trait(&mut self, item: &hir::Item) {
- let trait_def_id = self.tcx.hir.local_def_id(item.id);
- self.for_item(item).with_fcx(|fcx, _| {
- self.check_where_clauses(fcx, item.span, trait_def_id);
- vec![]
- });
- }
+fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
+ let trait_def_id = tcx.hir.local_def_id(item.id);
+ for_item(tcx, item).with_fcx(|fcx, _| {
+ check_where_clauses(tcx, fcx, item.span, trait_def_id);
+ vec![]
+ });
+}
- fn check_item_fn(&mut self, item: &hir::Item) {
- self.for_item(item).with_fcx(|fcx, this| {
- let def_id = fcx.tcx.hir.local_def_id(item.id);
- let sig = fcx.tcx.fn_sig(def_id);
- let sig = fcx.normalize_associated_types_in(item.span, &sig);
- let mut implied_bounds = vec![];
- this.check_fn_or_method(fcx, item.span, sig,
- def_id, &mut implied_bounds);
- implied_bounds
- })
- }
+fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
+ for_item(tcx, item).with_fcx(|fcx, tcx| {
+ let def_id = fcx.tcx.hir.local_def_id(item.id);
+ let sig = fcx.tcx.fn_sig(def_id);
+ let sig = fcx.normalize_associated_types_in(item.span, &sig);
+ let mut implied_bounds = vec![];
+ check_fn_or_method(tcx, fcx, item.span, sig,
+ def_id, &mut implied_bounds);
+ implied_bounds
+ })
+}
- fn check_item_type(&mut self,
- item: &hir::Item)
- {
- debug!("check_item_type: {:?}", item);
+fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item: &hir::Item)
+{
+ debug!("check_item_type: {:?}", item);
- self.for_item(item).with_fcx(|fcx, this| {
- let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
- let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
+ for_item(tcx, item).with_fcx(|fcx, _this| {
+ let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
+ let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
- fcx.register_wf_obligation(item_ty, item.span, this.code.clone());
+ fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation);
- vec![] // no implied bounds in a const etc
- });
- }
+ vec![] // no implied bounds in a const etc
+ });
+}
- fn check_impl(&mut self,
- item: &hir::Item,
- ast_self_ty: &hir::Ty,
- ast_trait_ref: &Option<hir::TraitRef>)
- {
- debug!("check_impl: {:?}", item);
-
- self.for_item(item).with_fcx(|fcx, this| {
- let item_def_id = fcx.tcx.hir.local_def_id(item.id);
-
- match *ast_trait_ref {
- Some(ref ast_trait_ref) => {
- let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
- let trait_ref =
- fcx.normalize_associated_types_in(
- ast_trait_ref.path.span, &trait_ref);
- let obligations =
- ty::wf::trait_obligations(fcx,
- fcx.param_env,
- fcx.body_id,
- &trait_ref,
- ast_trait_ref.path.span);
- for obligation in obligations {
- fcx.register_predicate(obligation);
- }
- }
- None => {
- let self_ty = fcx.tcx.type_of(item_def_id);
- let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
- fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
+fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item: &hir::Item,
+ ast_self_ty: &hir::Ty,
+ ast_trait_ref: &Option<hir::TraitRef>)
+{
+ debug!("check_impl: {:?}", item);
+
+ for_item(tcx, item).with_fcx(|fcx, tcx| {
+ let item_def_id = fcx.tcx.hir.local_def_id(item.id);
+
+ match *ast_trait_ref {
+ Some(ref ast_trait_ref) => {
+ let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
+ let trait_ref =
+ fcx.normalize_associated_types_in(
+ ast_trait_ref.path.span, &trait_ref);
+ let obligations =
+ ty::wf::trait_obligations(fcx,
+ fcx.param_env,
+ fcx.body_id,
+ &trait_ref,
+ ast_trait_ref.path.span);
+ for obligation in obligations {
+ fcx.register_predicate(obligation);
}
}
+ None => {
+ let self_ty = fcx.tcx.type_of(item_def_id);
+ let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
+ fcx.register_wf_obligation(self_ty, ast_self_ty.span,
+ ObligationCauseCode::MiscObligation);
+ }
+ }
- this.check_where_clauses(fcx, item.span, item_def_id);
+ check_where_clauses(tcx, fcx, item.span, item_def_id);
- fcx.impl_implied_bounds(item_def_id, item.span)
- });
- }
+ fcx.impl_implied_bounds(item_def_id, item.span)
+ });
+}
- /// Checks where clauses and inline bounds that are declared on def_id.
- fn check_where_clauses<'fcx, 'tcx>(&mut self,
- fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- span: Span,
- def_id: DefId) {
- use ty::subst::Subst;
- use rustc::ty::TypeFoldable;
-
- let mut predicates = fcx.tcx.predicates_of(def_id);
- let mut substituted_predicates = Vec::new();
-
- let generics = self.tcx.generics_of(def_id);
- let is_our_default = |def: &ty::TypeParameterDef|
- def.has_default && def.index >= generics.parent_count() as u32;
-
- // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
- // For example this forbids the declaration:
- // struct Foo<T = Vec<[u32]>> { .. }
- // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
- for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
- let ty = fcx.tcx.type_of(d);
- // ignore dependent defaults -- that is, where the default of one type
- // parameter includes another (e.g., <T, U = T>). In those cases, we can't
- // be sure if it will error or not as user might always specify the other.
- if !ty.needs_subst() {
- fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone());
- }
+/// Checks where clauses and inline bounds that are declared on def_id.
+fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+ fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+ span: Span,
+ def_id: DefId) {
+ use ty::subst::Subst;
+ use rustc::ty::TypeFoldable;
+
+ let mut predicates = fcx.tcx.predicates_of(def_id);
+ let mut substituted_predicates = Vec::new();
+
+ let generics = tcx.generics_of(def_id);
+ let is_our_default = |def: &ty::TypeParameterDef|
+ def.has_default && def.index >= generics.parent_count() as u32;
+
+ // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
+ // For example this forbids the declaration:
+ // struct Foo<T = Vec<[u32]>> { .. }
+ // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
+ for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
+ let ty = fcx.tcx.type_of(d);
+ // ignore dependent defaults -- that is, where the default of one type
+ // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+ // be sure if it will error or not as user might always specify the other.
+ if !ty.needs_subst() {
+ fcx.register_wf_obligation(ty, fcx.tcx.def_span(d),
+ ObligationCauseCode::MiscObligation);
}
+ }
- // Check that trait predicates are WF when params are substituted by their defaults.
- // We don't want to overly constrain the predicates that may be written but we want to
- // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
- // Therefore we check if a predicate which contains a single type param
- // with a concrete default is WF with that default substituted.
- // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
- //
- // First we build the defaulted substitution.
- let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
- // All regions are identity.
- fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
- }, |def, _| {
- // If the param has a default,
- if is_our_default(def) {
- let default_ty = fcx.tcx.type_of(def.def_id);
- // and it's not a dependent default
- if !default_ty.needs_subst() {
- // then substitute with the default.
- return default_ty;
- }
+ // Check that trait predicates are WF when params are substituted by their defaults.
+ // We don't want to overly constrain the predicates that may be written but we want to
+ // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
+ // Therefore we check if a predicate which contains a single type param
+ // with a concrete default is WF with that default substituted.
+ // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
+ //
+ // First we build the defaulted substitution.
+ let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
+ // All regions are identity.
+ fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
+ }, |def, _| {
+ // If the param has a default,
+ if is_our_default(def) {
+ let default_ty = fcx.tcx.type_of(def.def_id);
+ // and it's not a dependent default
+ if !default_ty.needs_subst() {
+ // then substitute with the default.
+ return default_ty;
}
- // Mark unwanted params as err.
- fcx.tcx.types.err
- });
- // Now we build the substituted predicates.
- for &pred in predicates.predicates.iter() {
- struct CountParams { params: FxHashSet<u32> }
- impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
- fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
- match t.sty {
- ty::TyParam(p) => {
- self.params.insert(p.idx);
- t.super_visit_with(self)
- }
- _ => t.super_visit_with(self)
+ }
+ // Mark unwanted params as err.
+ fcx.tcx.types.err
+ });
+ // Now we build the substituted predicates.
+ for &pred in predicates.predicates.iter() {
+ struct CountParams { params: FxHashSet<u32> }
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+ match t.sty {
+ ty::TyParam(p) => {
+ self.params.insert(p.idx);
+ t.super_visit_with(self)
}
+ _ => t.super_visit_with(self)
}
}
- let mut param_count = CountParams { params: FxHashSet() };
- pred.visit_with(&mut param_count);
- let substituted_pred = pred.subst(fcx.tcx, substs);
- // Don't check non-defaulted params, dependent defaults or preds with multiple params.
- if substituted_pred.references_error() || param_count.params.len() > 1 {
- continue;
- }
- // Avoid duplication of predicates that contain no parameters, for example.
- if !predicates.predicates.contains(&substituted_pred) {
- substituted_predicates.push(substituted_pred);
- }
}
-
- predicates.predicates.extend(substituted_predicates);
- let predicates = predicates.instantiate_identity(fcx.tcx);
- let predicates = fcx.normalize_associated_types_in(span, &predicates);
-
- let obligations =
- predicates.predicates
- .iter()
- .flat_map(|p| ty::wf::predicate_obligations(fcx,
- fcx.param_env,
- fcx.body_id,
- p,
- span));
-
- for obligation in obligations {
- fcx.register_predicate(obligation);
+ let mut param_count = CountParams { params: FxHashSet() };
+ pred.visit_with(&mut param_count);
+ let substituted_pred = pred.subst(fcx.tcx, substs);
+ // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+ if substituted_pred.references_error() || param_count.params.len() > 1 {
+ continue;
+ }
+ // Avoid duplication of predicates that contain no parameters, for example.
+ if !predicates.predicates.contains(&substituted_pred) {
+ substituted_predicates.push(substituted_pred);
}
}
- fn check_fn_or_method<'fcx, 'tcx>(&mut self,
- fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- span: Span,
- sig: ty::PolyFnSig<'tcx>,
- def_id: DefId,
- implied_bounds: &mut Vec<Ty<'tcx>>)
- {
- let sig = fcx.normalize_associated_types_in(span, &sig);
- let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
-
- for input_ty in sig.inputs() {
- fcx.register_wf_obligation(&input_ty, span, self.code.clone());
- }
- implied_bounds.extend(sig.inputs());
+ predicates.predicates.extend(substituted_predicates);
+ let predicates = predicates.instantiate_identity(fcx.tcx);
+ let predicates = fcx.normalize_associated_types_in(span, &predicates);
+
+ let obligations =
+ predicates.predicates
+ .iter()
+ .flat_map(|p| ty::wf::predicate_obligations(fcx,
+ fcx.param_env,
+ fcx.body_id,
+ p,
+ span));
+
+ for obligation in obligations {
+ fcx.register_predicate(obligation);
+ }
+}
- fcx.register_wf_obligation(sig.output(), span, self.code.clone());
+fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+ fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+ span: Span,
+ sig: ty::PolyFnSig<'tcx>,
+ def_id: DefId,
+ implied_bounds: &mut Vec<Ty<'tcx>>)
+{
+ let sig = fcx.normalize_associated_types_in(span, &sig);
+ let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
+
+ for input_ty in sig.inputs() {
+ fcx.register_wf_obligation(&input_ty, span, ObligationCauseCode::MiscObligation);
+ }
+ implied_bounds.extend(sig.inputs());
- // FIXME(#25759) return types should not be implied bounds
- implied_bounds.push(sig.output());
+ fcx.register_wf_obligation(sig.output(), span, ObligationCauseCode::MiscObligation);
- self.check_where_clauses(fcx, span, def_id);
- }
+ // FIXME(#25759) return types should not be implied bounds
+ implied_bounds.push(sig.output());
- fn check_method_receiver<'fcx, 'tcx>(&mut self,
- fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- method_sig: &hir::MethodSig,
- method: &ty::AssociatedItem,
- self_ty: Ty<'tcx>)
- {
- // check that the method has a valid receiver type, given the type `Self`
- debug!("check_method_receiver({:?}, self_ty={:?})",
- method, self_ty);
+ check_where_clauses(tcx, fcx, span, def_id);
+}
- if !method.method_has_self_argument {
- return;
- }
+fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+ method_sig: &hir::MethodSig,
+ method: &ty::AssociatedItem,
+ self_ty: Ty<'tcx>)
+{
+ // check that the method has a valid receiver type, given the type `Self`
+ debug!("check_method_receiver({:?}, self_ty={:?})",
+ method, self_ty);
+
+ if !method.method_has_self_argument {
+ return;
+ }
- let span = method_sig.decl.inputs[0].span;
+ let span = method_sig.decl.inputs[0].span;
- let sig = fcx.tcx.fn_sig(method.def_id);
- let sig = fcx.normalize_associated_types_in(span, &sig);
- let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig);
+ let sig = fcx.tcx.fn_sig(method.def_id);
+ let sig = fcx.normalize_associated_types_in(span, &sig);
+ let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig);
- debug!("check_method_receiver: sig={:?}", sig);
+ debug!("check_method_receiver: sig={:?}", sig);
- let self_ty = fcx.normalize_associated_types_in(span, &self_ty);
- let self_ty = fcx.tcx.liberate_late_bound_regions(
- method.def_id,
- &ty::Binder(self_ty)
- );
+ let self_ty = fcx.normalize_associated_types_in(span, &self_ty);
+ let self_ty = fcx.tcx.liberate_late_bound_regions(
+ method.def_id,
+ &ty::Binder(self_ty)
+ );
- let self_arg_ty = sig.inputs()[0];
+ let self_arg_ty = sig.inputs()[0];
- let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
- let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
- let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
- method.def_id,
- &ty::Binder(self_arg_ty)
- );
+ let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
+ let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
+ let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
+ method.def_id,
+ &ty::Binder(self_arg_ty)
+ );
- let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
+ let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
- loop {
- if let Some((potential_self_ty, _)) = autoderef.next() {
- debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
- potential_self_ty, self_ty);
+ loop {
+ if let Some((potential_self_ty, _)) = autoderef.next() {
+ debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
+ potential_self_ty, self_ty);
- if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
- autoderef.finalize();
- if let Some(mut err) = fcx.demand_eqtype_with_origin(
- &cause, self_ty, potential_self_ty) {
- err.emit();
- }
- break
+ if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
+ autoderef.finalize();
+ if let Some(mut err) = fcx.demand_eqtype_with_origin(
+ &cause, self_ty, potential_self_ty) {
+ err.emit();
}
- } else {
- fcx.tcx.sess.diagnostic().mut_span_err(
- span, &format!("invalid `self` type: {:?}", self_arg_ty))
- .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
- .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
- .code(DiagnosticId::Error("E0307".into()))
- .emit();
- return
+ break
}
+ } else {
+ fcx.tcx.sess.diagnostic().mut_span_err(
+ span, &format!("invalid `self` type: {:?}", self_arg_ty))
+ .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
+ .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+ .code(DiagnosticId::Error("E0307".into()))
+ .emit();
+ return
}
+ }
- let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
- let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
-
- if !fcx.tcx.features().arbitrary_self_types {
- match self_kind {
- ExplicitSelf::ByValue |
- ExplicitSelf::ByReference(_, _) |
- ExplicitSelf::ByBox => (),
-
- ExplicitSelf::ByRawPointer(_) => {
- feature_gate::feature_err(
- &fcx.tcx.sess.parse_sess,
- "arbitrary_self_types",
- span,
- GateIssue::Language,
- "raw pointer `self` is unstable")
- .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
- .emit();
- }
+ let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
+ let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
+
+ if !fcx.tcx.features().arbitrary_self_types {
+ match self_kind {
+ ExplicitSelf::ByValue |
+ ExplicitSelf::ByReference(_, _) |
+ ExplicitSelf::ByBox => (),
+
+ ExplicitSelf::ByRawPointer(_) => {
+ feature_gate::feature_err(
+ &fcx.tcx.sess.parse_sess,
+ "arbitrary_self_types",
+ span,
+ GateIssue::Language,
+ "raw pointer `self` is unstable")
+ .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+ .emit();
+ }
- ExplicitSelf::Other => {
- feature_gate::feature_err(
- &fcx.tcx.sess.parse_sess,
- "arbitrary_self_types",
- span,
- GateIssue::Language,"arbitrary `self` types are unstable")
- .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
- .emit();
- }
+ ExplicitSelf::Other => {
+ feature_gate::feature_err(
+ &fcx.tcx.sess.parse_sess,
+ "arbitrary_self_types",
+ span,
+ GateIssue::Language,"arbitrary `self` types are unstable")
+ .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+ .emit();
}
}
}
+}
- fn check_variances_for_type_defn(&self,
- item: &hir::Item,
- ast_generics: &hir::Generics)
- {
- let item_def_id = self.tcx.hir.local_def_id(item.id);
- let ty = self.tcx.type_of(item_def_id);
- if self.tcx.has_error_field(ty) {
- return;
- }
-
- let ty_predicates = self.tcx.predicates_of(item_def_id);
- assert_eq!(ty_predicates.parent, None);
- let variances = self.tcx.variances_of(item_def_id);
+fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item: &hir::Item,
+ ast_generics: &hir::Generics)
+{
+ let item_def_id = tcx.hir.local_def_id(item.id);
+ let ty = tcx.type_of(item_def_id);
+ if tcx.has_error_field(ty) {
+ return;
+ }
- let mut constrained_parameters: FxHashSet<_> =
- variances.iter().enumerate()
- .filter(|&(_, &variance)| variance != ty::Bivariant)
- .map(|(index, _)| Parameter(index as u32))
- .collect();
+ let ty_predicates = tcx.predicates_of(item_def_id);
+ assert_eq!(ty_predicates.parent, None);
+ let variances = tcx.variances_of(item_def_id);
- identify_constrained_type_params(self.tcx,
- ty_predicates.predicates.as_slice(),
- None,
- &mut constrained_parameters);
+ let mut constrained_parameters: FxHashSet<_> =
+ variances.iter().enumerate()
+ .filter(|&(_, &variance)| variance != ty::Bivariant)
+ .map(|(index, _)| Parameter(index as u32))
+ .collect();
- for (index, _) in variances.iter().enumerate() {
- if constrained_parameters.contains(&Parameter(index as u32)) {
- continue;
- }
+ identify_constrained_type_params(tcx,
+ ty_predicates.predicates.as_slice(),
+ None,
+ &mut constrained_parameters);
- let (span, name) = match ast_generics.params[index] {
- hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()),
- hir::GenericParam::Type(ref tp) => (tp.span, tp.name),
- };
- self.report_bivariance(span, name);
+ for (index, _) in variances.iter().enumerate() {
+ if constrained_parameters.contains(&Parameter(index as u32)) {
+ continue;
}
+
+ let (span, name) = match ast_generics.params[index] {
+ hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()),
+ hir::GenericParam::Type(ref tp) => (tp.span, tp.name),
+ };
+ report_bivariance(tcx, span, name);
}
+}
- fn report_bivariance(&self,
- span: Span,
- param_name: ast::Name)
- {
- let mut err = error_392(self.tcx, span, param_name);
-
- let suggested_marker_id = self.tcx.lang_items().phantom_data();
- match suggested_marker_id {
- Some(def_id) => {
- err.help(
- &format!("consider removing `{}` or using a marker such as `{}`",
- param_name,
- self.tcx.item_path_str(def_id)));
- }
- None => {
- // no lang items, no help!
- }
+fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ span: Span,
+ param_name: ast::Name)
+{
+ let mut err = error_392(tcx, span, param_name);
+
+ let suggested_marker_id = tcx.lang_items().phantom_data();
+ match suggested_marker_id {
+ Some(def_id) => {
+ err.help(
+ &format!("consider removing `{}` or using a marker such as `{}`",
+ param_name,
+ tcx.item_path_str(def_id)));
+ }
+ None => {
+ // no lang items, no help!
}
- err.emit();
}
+ err.emit();
}
fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
}
}
+pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
+ pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
+ -> CheckTypeWellFormedVisitor<'a, 'gcx> {
+ CheckTypeWellFormedVisitor {
+ tcx,
+ }
+ }
+}
+
impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::None
fn visit_item(&mut self, i: &hir::Item) {
debug!("visit_item: {:?}", i);
- self.check_item_well_formed(i);
+ let def_id = self.tcx.hir.local_def_id(i.id);
+ ty::maps::queries::check_item_well_formed::ensure(self.tcx, def_id);
intravisit::walk_item(self, i);
}
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
debug!("visit_trait_item: {:?}", trait_item);
- let method_sig = match trait_item.node {
- hir::TraitItemKind::Method(ref sig, _) => Some(sig),
- _ => None
- };
- self.check_associated_item(trait_item.id, trait_item.span, method_sig);
+ let def_id = self.tcx.hir.local_def_id(trait_item.id);
+ ty::maps::queries::check_trait_item_well_formed::ensure(self.tcx, def_id);
intravisit::walk_trait_item(self, trait_item)
}
fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
debug!("visit_impl_item: {:?}", impl_item);
- let method_sig = match impl_item.node {
- hir::ImplItemKind::Method(ref sig, _) => Some(sig),
- _ => None
- };
- self.check_associated_item(impl_item.id, impl_item.span, method_sig);
+ let def_id = self.tcx.hir.local_def_id(impl_item.id);
+ ty::maps::queries::check_impl_item_well_formed::ensure(self.tcx, def_id);
intravisit::walk_impl_item(self, impl_item)
}
}
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt;
-use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::ty::util::Discr;
+use rustc::util::captures::Captures;
+use rustc::util::nodemap::{FxHashSet, FxHashMap};
use syntax::{abi, ast};
use syntax::ast::MetaItemKind;
fn early_bound_lifetimes_from_generics<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ast_generics: &'a hir::Generics)
- -> impl Iterator<Item=&'a hir::LifetimeDef>
+ -> impl Iterator<Item=&'a hir::LifetimeDef> + Captures<'tcx>
{
ast_generics
.lifetimes()
/// Renders the configuration for human display, as a short HTML description.
pub(crate) fn render_short_html(&self) -> String {
- let mut msg = Html(self).to_string();
+ let mut msg = ShortHtml(self).to_string();
if self.should_capitalize_first_letter() {
if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) {
msg[i .. i+1].make_ascii_uppercase();
/// Renders the configuration for long display, as a long HTML description.
pub(crate) fn render_long_html(&self) -> String {
- let mut msg = format!("This is supported on <strong>{}</strong>", Html(self));
+ let on = if self.should_use_with_in_description() {
+ "with"
+ } else {
+ "on"
+ };
+
+ let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self));
if self.should_append_only_to_description() {
msg.push_str(" only");
}
}
}
}
+
+ fn should_use_with_in_description(&self) -> bool {
+ match *self {
+ Cfg::Cfg(ref name, _) if name == &"target_feature" => true,
+ _ => false,
+ }
+ }
}
impl ops::Not for Cfg {
},
("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian),
("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits),
+ ("target_feature", Some(feat)) =>
+ return write!(fmt, "target feature <code>{}</code>", feat),
_ => "",
};
if !human_readable.is_empty() {
}
}
+struct ShortHtml<'a>(&'a Cfg);
+
+impl<'a> fmt::Display for ShortHtml<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self.0 {
+ Cfg::Cfg(ref name, Some(ref vendor)) if name == &"target_feature" => {
+ write!(fmt, "<code>{}</code>", vendor)
+ },
+ ref cfg => write!(fmt, "{}", Html(cfg)),
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use super::Cfg;
).render_short_html(),
"(Debug-assertions enabled or Windows) and Unix"
);
+ assert_eq!(
+ name_value_cfg("target_feature", "sse2").render_short_html(),
+ "<code>sse2</code>"
+ );
})
}
"This is supported on <strong>(debug-assertions enabled or Windows) and Unix\
</strong> only."
);
+ assert_eq!(
+ name_value_cfg("target_feature", "sse2").render_long_html(),
+ "This is supported with <strong>target feature <code>sse2</code></strong> only."
+ );
})
}
}
})
}).collect();
+ // treat #[target_feature(enable = "feat")] attributes as if they were
+ // #[doc(cfg(target_feature = "feat"))] attributes as well
+ for attr in attrs.lists("target_feature") {
+ if attr.check_name("enable") {
+ if let Some(feat) = attr.value_str() {
+ let meta = attr::mk_name_value_item_str("target_feature".into(), feat);
+ if let Ok(feat_cfg) = Cfg::parse(&meta) {
+ cfg &= feat_cfg;
+ }
+ }
+ }
+ }
+
Attributes {
doc_strings,
other_attrs,
select the {}",
disambig1, kind1, disambig2,
kind2))
- .emit();
+ .emit();
}
/// Given an enum variant's def, return the def of its enum and the associated fragment
}
}
+#[derive(Debug)]
enum PathKind {
/// can be either value or type, not a macro
Unknown,
/// values, functions, consts, statics, everything in the value namespace
Value,
/// types, traits, everything in the type namespace
- Type
+ Type,
}
impl Clean<Attributes> for [ast::Attribute] {
if UnstableFeatures::from_environment().is_nightly_build() {
let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
- for link in markdown_links(&dox) {
+ for ori_link in markdown_links(&dox) {
// bail early for real links
- if link.contains('/') {
+ if ori_link.contains('/') {
continue;
}
- let (def, fragment) = {
+ let link = ori_link.replace("`", "");
+ let (def, fragment) = {
let mut kind = PathKind::Unknown;
let path_str = if let Some(prefix) =
["struct@", "enum@", "type@",
continue;
}
-
match kind {
PathKind::Value => {
if let Ok(def) = resolve(cx, path_str, true) {
}
};
-
let id = register_def(cx, def);
- attrs.links.push((link, id, fragment));
+ attrs.links.push((ori_link, id, fragment));
}
cx.sess().abort_if_errors();
#![allow(non_camel_case_types)]
+use rustc::session;
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::default::Default;
/// Make headings links with anchor ids and build up TOC.
struct LinkReplacer<'a, 'b, I: Iterator<Item = Event<'a>>> {
inner: I,
- links: &'b [(String, String)]
+ links: &'b [(String, String)],
}
impl<'a, 'b, I: Iterator<Item = Event<'a>>> LinkReplacer<'a, 'b, I> {
fn new(iter: I, links: &'b [(String, String)]) -> Self {
LinkReplacer {
inner: iter,
- links
+ links,
}
}
}
}
}
-pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
+pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span,
+ sess: Option<&session::Session>) {
tests.set_position(position);
let mut parser = Parser::new(doc);
line, filename, block_info.allow_fail);
prev_offset = offset;
} else {
+ if let Some(ref sess) = sess {
+ sess.span_warn(position, "invalid start of a new code block");
+ }
break;
}
}
true, opts, maybe_sysroot, None,
Some(PathBuf::from(input)),
linker);
- find_testable_code(&input_str, &mut collector, DUMMY_SP);
+ find_testable_code(&input_str, &mut collector, DUMMY_SP, None);
test_args.insert(0, "rustdoctest".to_string());
testing::test_main(&test_args, collector.tests,
testing::Options::new().display_output(display_warnings));
let trimline = line.trim();
let header = trimline.is_whitespace() ||
trimline.starts_with("#![") ||
+ trimline.starts_with("#[macro_use] extern crate") ||
trimline.starts_with("extern crate");
if !header || after_header {
after_header = true;
// the collapse-docs pass won't combine sugared/raw doc attributes, or included files with
// anything else, this will combine them for us
if let Some(doc) = attrs.collapsed_doc_value() {
- markdown::find_testable_code(&doc, self.collector,
- attrs.span.unwrap_or(DUMMY_SP));
+ markdown::find_testable_code(&doc,
+ self.collector,
+ attrs.span.unwrap_or(DUMMY_SP),
+ Some(self.sess));
}
nested(self);
assert_eq!(output, (expected, 2));
}
+ #[test]
+ fn make_test_manual_extern_crate_with_macro_use() {
+ let opts = TestOptions::default();
+ let input =
+"#[macro_use] extern crate asdf;
+use asdf::qwop;
+assert_eq!(2+2, 4);";
+ let expected =
+"#![allow(unused)]
+#[macro_use] extern crate asdf;
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+ let output = make_test(input, Some("asdf"), false, &opts);
+ assert_eq!(output, (expected, 2));
+ }
+
#[test]
fn make_test_opts_attrs() {
//if you supplied some doctest attributes with #![doc(test(attr(...)))], it will use those
///
/// [combining character]: https://en.wikipedia.org/wiki/Combining_character
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
pub trait AsciiExt {
/// Container type for copied ASCII characters.
#[stable(feature = "rust1", since = "1.0.0")]
/// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase
/// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase
#[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(deprecated)]
fn to_ascii_uppercase(&self) -> Self::Owned;
/// Makes a copy of the value in its ASCII lower case equivalent.
/// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase
/// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase
#[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(deprecated)]
fn to_ascii_lowercase(&self) -> Self::Owned;
/// Checks that two values are an ASCII case-insensitive match.
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII uppercase character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_uppercase(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII lowercase character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_lowercase(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII alphanumeric character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII decimal digit:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_digit(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII hexadecimal digit:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII punctuation character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII graphic character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_graphic(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII whitespace character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_whitespace(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII control character:
/// This method will be deprecated in favor of the identically-named
/// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
fn is_ascii_control(&self) -> bool { unimplemented!(); }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl AsciiExt for u8 {
type Owned = u8;
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl AsciiExt for char {
type Owned = char;
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl AsciiExt for [u8] {
type Owned = Vec<u8>;
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl AsciiExt for str {
type Owned = String;
use borrow::Cow;
use cell;
use char;
-use convert;
use core::array;
use fmt::{self, Debug, Display};
use mem::transmute;
}
}
-#[unstable(feature = "try_from", issue = "33417")]
-impl Error for convert::Infallible {
- fn description(&self) -> &str {
- match *self {
- }
- }
-}
-
// copied from any.rs
impl Error + 'static {
/// Returns true if the boxed type is the same as `T`
macro_rules! test_checked_next_power_of_two {
($test_name:ident, $T:ident) => (
- #[cfg_attr(target_os = "emscripten", ignore)] // FIXME(#39119)
fn $test_name() {
#![test]
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
#![unstable(feature = "process_internals", issue = "0")]
-use ascii::AsciiExt;
use collections::BTreeMap;
use env::split_paths;
use env;
use core::str::next_code_point;
-use ascii::*;
use borrow::Cow;
use char;
use fmt;
}
}
-impl AsciiExt for Wtf8 {
- type Owned = Wtf8Buf;
-
- fn is_ascii(&self) -> bool {
+impl Wtf8 {
+ pub fn is_ascii(&self) -> bool {
self.bytes.is_ascii()
}
- fn to_ascii_uppercase(&self) -> Wtf8Buf {
+ pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() }
}
- fn to_ascii_lowercase(&self) -> Wtf8Buf {
+ pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() }
}
- fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
+ pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
self.bytes.eq_ignore_ascii_case(&other.bytes)
}
- fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
- fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
+ pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
+ pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
}
#[cfg(test)]
debug!("parse_str_lit: given {}", escape_default(lit));
let mut res = String::with_capacity(lit.len());
- // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
let error = |i| format!("lexer should have rejected {} at {}", lit, i);
/// Eat everything up to a non-whitespace
pub fn byte_str_lit(lit: &str) -> Lrc<Vec<u8>> {
let mut res = Vec::with_capacity(lit.len());
- // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
let error = |i| format!("lexer should have rejected {} at {}", lit, i);
/// Eat everything up to a non-whitespace
}
fn path_name_i(idents: &[Ident]) -> String {
- // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
- idents.iter().map(|i| i.to_string()).collect::<Vec<String>>().join("::")
+ let mut path_name = "".to_string();
+ let mut idents_iter = idents.iter().peekable();
+ while let Some(ident) = idents_iter.next() {
+ path_name.push_str(&ident.name.as_str());
+ if let Some(_) = idents_iter.peek() {
+ path_name.push_str("::")
+ }
+ }
+ path_name
}
fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
// gensym information.
let span = ignored_span(cx, test.span);
- let path = test.path.clone();
let ecx = &cx.ext_cx;
let self_id = ecx.ident_of("self");
let test_id = ecx.ident_of("test");
// creates $name: $expr
let field = |name, expr| ecx.field_imm(span, ecx.ident_of(name), expr);
- debug!("encoding {}", path_name_i(&path[..]));
-
// path to the #[test] function: "foo::bar::baz"
- let path_string = path_name_i(&path[..]);
+ let path_string = path_name_i(&test.path[..]);
+
+ debug!("encoding {}", path_string);
+
let name_expr = ecx.expr_str(span, Symbol::intern(&path_string));
// self::test::StaticTestName($name_expr)
diag.bug("expected to find top-level re-export name, but found None");
}
};
- visible_path.extend(path);
+ visible_path.extend_from_slice(&test.path[..]);
// Rather than directly give the test function to the test
// harness, we create a wrapper like one of the following:
-Subproject commit ab9356f2af650815d339d77306f0d09c44d531ad
+Subproject commit bcb720e55861c38db47f2ebdf26b7198338cb39d
// ignore-mips
// ignore-mips64
// ignore-powerpc
+// ignore-powerpc64
// ignore-s390x
// ignore-sparc
// ignore-wasm32
// ignore-mips
// ignore-mips64
// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
// ignore-powerpc
// ignore-r600
// ignore-amdgcn
// ignore-mips
// ignore-mips64
// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
// ignore-powerpc
// ignore-r600
// ignore-amdgcn
// ignore-mips
// ignore-mips64
// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
// ignore-powerpc
// ignore-r600
// ignore-amdgcn
// ignore-mips
// ignore-mips64
// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
// ignore-powerpc
// ignore-r600
// ignore-amdgcn
// ignore-mips
// ignore-mips64
// ignore-powerpc
+// ignore-powerpc64
// See repr-transparent.rs
#![crate_type="lib"]
// let _2: &'21_1rs D;
// ...
// let mut _3: ();
-// let mut _4: [closure@NodeId(22) r:&'21_1rs D];
+// let mut _4: [closure@NodeId(22) r:&'19s D];
// let mut _5: &'21_1rs D;
// bb0: {
// StorageLive(_1);
// resume;
// }
// bb2: {
+// EndRegion('19s);
// StorageDead(_4);
// _0 = ();
// EndRegion('21_1rs);
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
+// EndRegion('19s);
// EndRegion('21_1rs);
// drop(_1) -> bb1;
// }
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'21_1rs D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 {
// let mut _0: i32;
// let mut _2: i32;
//
BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)'
BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)'
RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS)
-RUSTDOC := $(BARE_RUSTDOC)
+RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR)
ifdef RUSTC_LINKER
RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER)
RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options
// pretty-expanded FIXME #23616
-use std::ascii::AsciiExt;
-
static NAME: &'static str = "hello world";
fn main() {
// Test that a field can have the same name in different variants
// of an enum
-// FIXME #27889
pub enum Foo {
X { foo: u32 },
f32: [T; 32],
}
-// FIXME(#7622): merge with `Array` once `[T; N]: Clone` where `T: Clone`
+// FIXME(#44580): merge with `Array` once `[T; N]: Clone` where `T: Clone`
#[derive(Clone, Copy)]
struct CopyArray<T: Copy> {
f00: [T; 00],
--- /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.
+
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+// @has foo/struct.Bar.html '//a[@href="../foo/struct.Foo.html"]' 'Foo'
+
+/// Code-styled reference to [`Foo`].
+pub struct Bar;
// except according to those terms.
#![feature(doc_cfg)]
+#![feature(target_feature, cfg_target_feature)]
// @has doc_cfg/struct.Portable.html
// @!has - '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' ''
fn unix_and_arm_only_function() {}
}
}
+
+// tagging a function with `#[target_feature]` creates a doc(cfg(target_feature)) node for that
+// item as well
+
+// the portability header is different on the module view versus the full view
+// @has doc_cfg/index.html
+// @matches - '//*[@class=" module-item"]//*[@class="stab portability"]' '\Aavx\Z'
+
+// @has doc_cfg/fn.uses_target_feature.html
+// @has - '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
+// 'This is supported with target feature avx only.'
+#[target_feature(enable = "avx")]
+pub unsafe fn uses_target_feature() {
+ content::should::be::irrelevant();
+}
+
+// @has doc_cfg/fn.uses_cfg_target_feature.html
+// @has - '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
+// 'This is supported with target feature avx only.'
+#[doc(cfg(target_feature = "avx"))]
+pub fn uses_cfg_target_feature() {
+ uses_target_feature();
+}
--- /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(rustc_attrs)]
+
+#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
+trait Foo<S, T, U> {
+ fn s(S) -> S;
+ fn t(T) -> T;
+ fn u(U) -> U;
+}
+
+fn main() {
+ println!("hello");
+}
--- /dev/null
+error: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
+ --> $DIR/lower_trait.rs:13:1
+ |
+LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
-error[E0277]: the trait bound `No: Foo` is not satisfied in `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&'static OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`
+error[E0277]: the trait bound `No: Foo` is not satisfied in `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`
--> $DIR/auto-trait-regions.rs:40:5
|
LL | assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied
- | ^^^^^^^^^^ within `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&'static OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`, the trait `Foo` is not implemented for `No`
+ | ^^^^^^^^^^ within `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`, the trait `Foo` is not implemented for `No`
|
= help: the following implementations were found:
<No as Foo>
= note: required because it appears within the type `OnlyFooIfStaticRef`
= note: required because it appears within the type `&OnlyFooIfStaticRef`
= note: required because it appears within the type `for<'r> {&'r OnlyFooIfStaticRef, ()}`
- = note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&'static OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`
+ = note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`
note: required by `assert_foo`
--> $DIR/auto-trait-regions.rs:30:1
|
--- /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.
+
+// In contrast to `region-escape-via-bound-invariant`, in this case we
+// *can* return a value of type `&'x u32`, even though `'x` does not
+// appear in the bounds. This is because `&` is contravariant, and so
+// we are *actually* returning a `&'y u32`.
+//
+// See https://github.com/rust-lang/rust/issues/46541 for more details.
+
+// run-pass
+
+#![allow(dead_code)]
+#![feature(conservative_impl_trait)]
+#![feature(in_band_lifetimes)]
+#![feature(nll)]
+
+fn foo(x: &'x u32) -> impl Fn() -> &'y u32
+where 'x: 'y
+{
+ move || x
+}
+
+fn main() { }
--- /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.
+
+// In contrast to `region-escape-via-bound-invariant`, in this case we
+// *can* return a value of type `&'x u32`, even though `'x` does not
+// appear in the bounds. This is because `&` is contravariant, and so
+// we are *actually* returning a `&'y u32`.
+//
+// See https://github.com/rust-lang/rust/issues/46541 for more details.
+
+// run-pass
+
+#![allow(dead_code)]
+#![feature(conservative_impl_trait)]
+#![feature(in_band_lifetimes)]
+#![feature(nll)]
+
+trait Trait<'a> { }
+
+impl Trait<'b> for &'a u32 { }
+
+fn foo(x: &'x u32) -> impl Trait<'y>
+where 'x: 'y
+{
+ x
+}
+
+fn main() { }
--- /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.
+
+// Test that we do not allow the region `'x` to escape in the impl
+// trait **even though** `'y` escapes, which outlives `'x`.
+//
+// See https://github.com/rust-lang/rust/issues/46541 for more details.
+
+#![allow(dead_code)]
+#![feature(conservative_impl_trait)]
+#![feature(in_band_lifetimes)]
+#![feature(nll)]
+
+use std::cell::Cell;
+
+trait Trait<'a> { }
+
+impl Trait<'b> for Cell<&'a u32> { }
+
+fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
+ //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909]
+where 'x: 'y
+{
+ x
+}
+
+fn main() { }
--- /dev/null
+error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/region-escape-via-bound.rs:27:29
+ |
+LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
+ | ^^^^^^^^^^^^^^
+ |
+note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 27:1
+ --> $DIR/region-escape-via-bound.rs:27:1
+ |
+LL | / fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
+LL | | //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909]
+LL | | where 'x: 'y
+LL | | {
+LL | | x
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0909`.
--- /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.
+
+fn main() {
+ let v = vec![0];
+ const l: usize = v.count(); //~ ERROR can't capture dynamic environment in a fn item
+ let s: [u32; l] = v.into_iter().collect(); //~ ERROR constant evaluation error
+}
--- /dev/null
+error[E0434]: can't capture dynamic environment in a fn item
+ --> $DIR/type-dependent-def-issue-49241.rs:13:22
+ |
+LL | const l: usize = v.count(); //~ ERROR can't capture dynamic environment in a fn item
+ | ^
+ |
+ = help: use the `|| { ... }` closure form instead
+
+error[E0080]: constant evaluation error
+ --> $DIR/type-dependent-def-issue-49241.rs:14:18
+ |
+LL | let s: [u32; l] = v.into_iter().collect(); //~ ERROR constant evaluation error
+ | ^ encountered constants with type errors, stopping evaluation
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0080, E0434.
+For more information about an error, try `rustc --explain E0080`.
let mut rustdoc = Command::new(rustdoc_path);
rustdoc
+ .arg("-L")
+ .arg(self.config.run_lib_path.to_str().unwrap())
.arg("-L")
.arg(aux_dir)
.arg("-o")
}
fn run_rmake_test(&self) {
- // FIXME(#11094): we should fix these tests
- if self.config.host != self.config.target {
- return;
- }
-
let cwd = env::current_dir().unwrap();
let src_root = self.config
.src_base
/// Conversion table from triple OS name to Rust SYSNAME
const OS_TABLE: &'static [(&'static str, &'static str)] = &[
("android", "android"),
+ ("androideabi", "android"),
("bitrig", "bitrig"),
("cloudabi", "cloudabi"),
("darwin", "macos"),
("dragonfly", "dragonfly"),
+ ("emscripten", "emscripten"),
("freebsd", "freebsd"),
+ ("fuchsia", "fuchsia"),
("haiku", "haiku"),
("ios", "ios"),
+ ("l4re", "l4re"),
("linux", "linux"),
("mingw32", "windows"),
("netbsd", "netbsd"),
("openbsd", "openbsd"),
+ ("redox", "redox"),
+ ("solaris", "solaris"),
("win32", "windows"),
("windows", "windows"),
- ("solaris", "solaris"),
- ("emscripten", "emscripten"),
];
const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
("amd64", "x86_64"),
("arm", "arm"),
("arm64", "aarch64"),
+ ("armv4t", "arm"),
+ ("armv5te", "arm"),
+ ("armv7", "arm"),
+ ("armv7s", "arm"),
+ ("asmjs", "asmjs"),
("hexagon", "hexagon"),
("i386", "x86"),
("i586", "x86"),
("i686", "x86"),
- ("mips64", "mips64"),
("mips", "mips"),
+ ("mips64", "mips64"),
+ ("mips64el", "mips64"),
+ ("mipsel", "mips"),
("msp430", "msp430"),
("powerpc", "powerpc"),
+ ("powerpc64", "powerpc64"),
+ ("powerpc64le", "powerpc64"),
("s390x", "s390x"),
("sparc", "sparc"),
+ ("sparc64", "sparc64"),
+ ("sparcv9", "sparc64"),
+ ("thumbv6m", "thumb"),
+ ("thumbv7em", "thumb"),
+ ("thumbv7m", "thumb"),
+ ("wasm32", "wasm32"),
("x86_64", "x86_64"),
("xcore", "xcore"),
- ("asmjs", "asmjs"),
- ("wasm32", "wasm32"),
];
pub fn matches_os(triple: &str, name: &str) -> bool {
if triple == "wasm32-unknown-unknown" {
return name == "emscripten" || name == "wasm32-bare"
}
+ let triple: Vec<_> = triple.split('-').collect();
for &(triple_os, os) in OS_TABLE {
- if triple.contains(triple_os) {
+ if triple.contains(&triple_os) {
return os == name;
}
}
panic!("Cannot determine OS from triple");
}
pub fn get_arch(triple: &str) -> &'static str {
+ let triple: Vec<_> = triple.split('-').collect();
for &(triple_arch, arch) in ARCH_TABLE {
- if triple.contains(triple_arch) {
+ if triple.contains(&triple_arch) {
return arch;
}
}