path = src/llvm
url = https://github.com/rust-lang/llvm.git
branch = master
-[submodule "src/jemalloc"]
- path = src/jemalloc
- url = https://github.com/rust-lang/jemalloc.git
[submodule "src/rust-installer"]
path = src/tools/rust-installer
url = https://github.com/rust-lang/rust-installer.git
path = src/tools/clang
url = https://github.com/rust-lang-nursery/clang.git
branch = rust-release-80-v1
-
\ No newline at end of file
+
- env: >
RUST_CHECK_TARGET=dist
- RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --enable-lldb"
+ RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --enable-lldb --set rust.jemalloc"
SRC=.
DEPLOY_ALT=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
# version that we're using, 8.2, cannot compile LLVM for OSX 10.7.
- env: >
RUST_CHECK_TARGET=check
- RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler"
+ RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
SRC=.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
MACOSX_DEPLOYMENT_TARGET=10.8
- env: >
RUST_CHECK_TARGET=check
- RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
+ RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --set rust.jemalloc"
SRC=.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
MACOSX_DEPLOYMENT_TARGET=10.8
# OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7.
- env: >
RUST_CHECK_TARGET=dist
- RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb"
+ RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb --set rust.jemalloc"
SRC=.
DEPLOY=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
- env: >
RUST_CHECK_TARGET=dist
- RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb"
+ RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc"
SRC=.
DEPLOY=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
# Adding debuginfo makes them several times larger.
#debuginfo-tools = false
-# Whether or not jemalloc is built and enabled
-#use-jemalloc = true
-
-# Whether or not jemalloc is built with its debug option set
-#debug-jemalloc = false
-
# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
#backtrace = true
# generally only set for releases
#remap-debuginfo = false
+# Link the compiler against `jemalloc`, where on Linux and OSX it should
+# override the default allocator for rustc and LLVM.
+#jemalloc = false
+
# =============================================================================
# Options for specific targets
#
# not, you can specify an explicit file name for it.
#llvm-filecheck = "/path/to/FileCheck"
-# Path to the custom jemalloc static library to link into the standard library
-# by default. This is only used if jemalloc is still enabled above
-#jemalloc = "/path/to/jemalloc/libjemalloc_pic.a"
-
# If this target is for Android, this option will be required to specify where
# the NDK for the target lives. This is used to find the C compiler to link and
# build native code.
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "alloc_jemalloc"
-version = "0.0.0"
-dependencies = [
- "build_helper 0.1.0",
- "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "compiler_builtins 0.0.0",
- "core 0.0.0",
- "libc 0.0.0",
-]
-
[[package]]
name = "alloc_system"
version = "0.0.0"
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "fs_extra"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "fst"
version = "0.3.0"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "jemalloc-sys"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "jobserver"
version = "0.1.11"
"arena 0.0.0",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
+ "jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "alloc_jemalloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
"checksum fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d94485a00b1827b861dd9d1a2cc9764f9044d4c535514c0760a5a2012ef3399f"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
+"checksum jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc62c8e50e381768ce8ee0428ee53741929f7ebd73e4d83f669bcf7693e00ae"
"checksum jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "60af5f849e1981434e4a31d3d782c4774ae9b434ce55b101a96ecfd09147e8be"
"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
"checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c"
backends = self.get_toml('codegen-backends')
if backends is None or not 'emscripten' in backends:
continue
- if module.endswith("jemalloc"):
- if self.get_toml('use-jemalloc') == 'false':
- continue
- if self.get_toml('jemalloc'):
- continue
if module.endswith("lld"):
config = self.get_toml('lld')
if config is None or config == 'false':
.arg("--manifest-path")
.arg(builder.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
} else {
- let mut features = builder.std_features();
-
- // When doing a local rebuild we tell cargo that we're stage1 rather than
- // stage0. This works fine if the local rust and being-built rust have the
- // same view of what the default allocator is, but fails otherwise. Since
- // we don't have a way to express an allocator preference yet, work
- // around the issue in the case of a local rebuild with jemalloc disabled.
- if compiler.stage == 0 && builder.local_rebuild && !builder.config.use_jemalloc {
- features.push_str(" force_alloc_system");
- }
+ let features = builder.std_features();
if compiler.stage != 0 && builder.config.sanitizers {
// This variable is used by the sanitizer runtime crates, e.g.
.arg("--manifest-path")
.arg(builder.src.join("src/libstd/Cargo.toml"));
- if let Some(target) = builder.config.target_config.get(&target) {
- if let Some(ref jemalloc) = target.jemalloc {
- cargo.env("JEMALLOC_OVERRIDE", jemalloc);
- }
- }
if target.contains("musl") {
if let Some(p) = builder.musl_root(target) {
cargo.env("MUSL_ROOT", p);
pub hosts: Vec<Interned<String>>,
pub targets: Vec<Interned<String>>,
pub local_rebuild: bool,
+ pub jemalloc: bool,
// dist misc
pub dist_sign_folder: Option<PathBuf>,
pub dist_gpg_password_file: Option<PathBuf>,
// libstd features
- pub debug_jemalloc: bool,
- pub use_jemalloc: bool,
pub backtrace: bool, // support for RUST_BACKTRACE
pub wasm_syscall: bool,
pub llvm_config: Option<PathBuf>,
/// Some(path to FileCheck) if one was specified.
pub llvm_filecheck: Option<PathBuf>,
- pub jemalloc: Option<PathBuf>,
pub cc: Option<PathBuf>,
pub cxx: Option<PathBuf>,
pub ar: Option<PathBuf>,
link_jobs: Option<u32>,
link_shared: Option<bool>,
version_suffix: Option<String>,
- clang_cl: Option<String>
+ clang_cl: Option<String>,
}
#[derive(Deserialize, Default, Clone)]
debuginfo_only_std: Option<bool>,
debuginfo_tools: Option<bool>,
experimental_parallel_queries: Option<bool>,
- debug_jemalloc: Option<bool>,
- use_jemalloc: Option<bool>,
backtrace: Option<bool>,
default_linker: Option<String>,
channel: Option<String>,
backtrace_on_ice: Option<bool>,
verify_llvm_ir: Option<bool>,
remap_debuginfo: Option<bool>,
+ jemalloc: Option<bool>,
}
/// TOML representation of how each build target is configured.
struct TomlTarget {
llvm_config: Option<String>,
llvm_filecheck: Option<String>,
- jemalloc: Option<String>,
cc: Option<String>,
cxx: Option<String>,
ar: Option<String>,
config.llvm_enabled = true;
config.llvm_optimize = true;
config.llvm_version_check = true;
- config.use_jemalloc = true;
config.backtrace = true;
config.rust_optimize = true;
config.rust_optimize_tests = true;
let mut debuginfo_only_std = None;
let mut debuginfo_tools = None;
let mut debug = None;
- let mut debug_jemalloc = None;
let mut debuginfo = None;
let mut debug_assertions = None;
let mut optimize = None;
debuginfo_tools = rust.debuginfo_tools;
optimize = rust.optimize;
ignore_git = rust.ignore_git;
- debug_jemalloc = rust.debug_jemalloc;
set(&mut config.rust_optimize_tests, rust.optimize_tests);
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
set(&mut config.codegen_tests, rust.codegen_tests);
set(&mut config.rust_rpath, rust.rpath);
- set(&mut config.use_jemalloc, rust.use_jemalloc);
+ set(&mut config.jemalloc, rust.jemalloc);
set(&mut config.backtrace, rust.backtrace);
set(&mut config.channel, rust.channel.clone());
set(&mut config.rust_dist_src, rust.dist_src);
if let Some(ref s) = cfg.llvm_filecheck {
target.llvm_filecheck = Some(config.src.join(s));
}
- if let Some(ref s) = cfg.jemalloc {
- target.jemalloc = Some(config.src.join(s));
- }
if let Some(ref s) = cfg.android_ndk {
target.ndk = Some(config.src.join(s));
}
config.rust_debuginfo_tools = debuginfo_tools.unwrap_or(false);
let default = debug == Some(true);
- config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
config.rust_debuginfo = debuginfo.unwrap_or(default);
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
o("debuginfo-tools", "rust.debuginfo-tools", "build extended tools with debugging information")
-o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill")
v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
v("prefix", "install.prefix", "set installation prefix")
v("llvm-config", None, "set path to llvm-config")
v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
v("python", "build.python", "set path to python")
-v("jemalloc-root", None, "set directory where libjemalloc_pic.a is located")
v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
"Android NDK standalone path (deprecated)")
v("i686-linux-android-ndk", "target.i686-linux-android.android-ndk",
# Many of these are saved below during the "writing configuration" step
# (others are conditionally saved).
o("manage-submodules", "build.submodules", "let the build manage the git submodules")
-o("jemalloc", "rust.use-jemalloc", "build liballoc with jemalloc")
o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two")
o("extended", "build.extended", "build an extended rust tool set")
set('target.{}.llvm-config'.format(build()), value)
elif option.name == 'llvm-filecheck':
set('target.{}.llvm-filecheck'.format(build()), value)
- elif option.name == 'jemalloc-root':
- set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
elif option.name == 'tools':
set('build.tools', value.split(','))
elif option.name == 'host':
"src/build_helper",
"src/dlmalloc",
"src/liballoc",
- "src/liballoc_jemalloc",
"src/liballoc_system",
"src/libbacktrace",
"src/libcompiler_builtins",
"src/rustc/dlmalloc_shim",
"src/libtest",
"src/libterm",
- "src/jemalloc",
"src/libprofiler_builtins",
"src/stdsimd",
"src/libproc_macro",
];
let std_src_dirs_exclude = [
"src/libcompiler_builtins/compiler-rt/test",
- "src/jemalloc/test/unit",
];
copy_src_dirs(builder, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
}
}
-const CARGO_VENDOR_VERSION: &str = "0.1.4";
+const CARGO_VENDOR_VERSION: &str = "0.1.19";
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
pub struct PlainSourceTarball;
fn std_features(&self) -> String {
let mut features = "panic-unwind".to_string();
- if self.config.debug_jemalloc {
- features.push_str(" debug-jemalloc");
- }
- if self.config.use_jemalloc {
- features.push_str(" jemalloc");
- }
if self.config.backtrace {
features.push_str(" backtrace");
}
/// Get the space-separated set of activated features for the compiler.
fn rustc_features(&self) -> String {
let mut features = String::new();
- if self.config.use_jemalloc {
- features.push_str(" jemalloc");
+ if self.config.jemalloc {
+ features.push_str("jemalloc");
}
features
}
// If we're compiling on macOS then we add a few unconditional flags
// indicating that we want libc++ (more filled out than libstdc++) and
// we want to compile for 10.7. This way we can ensure that
- // LLVM/jemalloc/etc are all properly compiled.
+ // LLVM/etc are all properly compiled.
if target.contains("apple-darwin") {
base.push("-stdlib=libc++".into());
}
if !build.config.dry_run {
cmd_finder.must_have(build.cxx(*host).unwrap());
}
-
- // The msvc hosts don't use jemalloc, turn it off globally to
- // avoid packaging the dummy liballoc_jemalloc on that platform.
- if host.contains("msvc") {
- build.config.use_jemalloc = false;
- }
}
// Externally configured LLVM requires FileCheck to exist
type Output = ();
fn should_run(run: ShouldRun) -> ShouldRun {
- run.path("src/liballoc_jemalloc")
- .path("src/librustc_asan")
+ run.path("src/librustc_asan")
.path("src/librustc_lsan")
.path("src/librustc_msan")
.path("src/librustc_tsan")
target: run.target,
test_kind,
krate: match run.path {
- _ if run.path.ends_with("src/liballoc_jemalloc") => "alloc_jemalloc",
_ if run.path.ends_with("src/librustc_asan") => "rustc_asan",
_ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan",
_ if run.path.ends_with("src/librustc_msan") => "rustc_msan",
run = run.krate("test");
for krate in run.builder.in_tree_crates("std") {
if krate.is_local(&run.builder)
- && !krate.name.contains("jemalloc")
&& !(krate.name.starts_with("rustc_") && krate.name.ends_with("san"))
&& krate.name != "dlmalloc"
{
--enable-sanitizers \
--enable-profiler \
--set target.i686-unknown-linux-gnu.linker=clang \
- --build=i686-unknown-linux-gnu
+ --build=i686-unknown-linux-gnu \
+ --set rust.jemalloc
ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS
ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang
--set target.x86_64-unknown-linux-gnu.linker=clang \
--set target.x86_64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \
--set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
- --set llvm.thin-lto=true
+ --set llvm.thin-lto=true \
+ --set rust.jemalloc
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
+++ /dev/null
-Subproject commit 1f5a28755e301ac581e2048011e4e0ff3da482ef
use core::marker::{Unpin, Unsize};
use core::mem;
use core::pin::Pin;
-use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
+use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState};
use core::ptr::{self, NonNull, Unique};
use core::task::{LocalWaker, Poll};
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
+
#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl<T: Clone> Clone for Box<[T]> {
fn clone(&self) -> Self {
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
+#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
use core::marker::{Unpin, Unsize, PhantomData};
use core::mem::{self, align_of_val, forget, size_of_val};
use core::ops::Deref;
-use core::ops::CoerceUnsized;
+use core::ops::{CoerceUnsized, DispatchFromDyn};
use core::pin::Pin;
use core::ptr::{self, NonNull};
use core::convert::From;
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
+
impl<T> Rc<T> {
/// Constructs a new `Rc<T>`.
///
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
+
impl<T> Weak<T> {
/// Constructs a new `Weak<T>`, without allocating any memory.
/// Calling [`upgrade`][Weak::upgrade] on the return value always gives [`None`].
use core::intrinsics::abort;
use core::mem::{self, align_of_val, size_of_val};
use core::ops::Deref;
-use core::ops::CoerceUnsized;
+use core::ops::{CoerceUnsized, DispatchFromDyn};
use core::pin::Pin;
use core::ptr::{self, NonNull};
use core::marker::{Unpin, Unsize, PhantomData};
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Arc<U>> for Arc<T> {}
+
/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the
/// managed value. The value is accessed by calling [`upgrade`] on the `Weak`
/// pointer, which returns an [`Option`]`<`[`Arc`]`<T>>`.
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
use std::alloc::{Global, Alloc, Layout};
/// https://github.com/rust-lang/rust/issues/45955
-///
-/// Note that `#[global_allocator]` is not used,
-/// so `liballoc_jemalloc` is linked (on some platforms).
#[test]
fn alloc_system_overaligned_request() {
check_overalign_requests(System)
+++ /dev/null
-[package]
-authors = ["The Rust Project Developers"]
-name = "alloc_jemalloc"
-version = "0.0.0"
-build = "build.rs"
-links = "jemalloc"
-
-[lib]
-name = "alloc_jemalloc"
-path = "lib.rs"
-test = false
-doc = false
-
-[dependencies]
-core = { path = "../libcore" }
-libc = { path = "../rustc/libc_shim" }
-compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
-
-[build-dependencies]
-build_helper = { path = "../build_helper" }
-cc = "1.0.1"
-
-[features]
-debug = []
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![deny(warnings)]
-
-extern crate build_helper;
-extern crate cc;
-
-use std::env;
-use std::path::PathBuf;
-use std::process::Command;
-use build_helper::{run, native_lib_boilerplate};
-
-fn main() {
- // FIXME: This is a hack to support building targets that don't
- // support jemalloc alongside hosts that do. The jemalloc build is
- // controlled by a feature of the std crate, and if that feature
- // changes between targets, it invalidates the fingerprint of
- // std's build script (this is a cargo bug); so we must ensure
- // that the feature set used by std is the same across all
- // targets, which means we have to build the alloc_jemalloc crate
- // for targets like emscripten, even if we don't use it.
- let target = env::var("TARGET").expect("TARGET was not set");
- let host = env::var("HOST").expect("HOST was not set");
- if target.contains("bitrig") || target.contains("emscripten") || target.contains("fuchsia") ||
- target.contains("msvc") || target.contains("openbsd") || target.contains("redox") ||
- target.contains("rumprun") || target.contains("wasm32") {
- println!("cargo:rustc-cfg=dummy_jemalloc");
- return;
- }
-
- // CloudABI ships with a copy of jemalloc that has been patched to
- // work well with sandboxing. Don't attempt to build our own copy,
- // as it won't build.
- if target.contains("cloudabi") {
- return;
- }
-
- if target.contains("android") {
- println!("cargo:rustc-link-lib=gcc");
- } else if !target.contains("windows") && !target.contains("musl") {
- println!("cargo:rustc-link-lib=pthread");
- }
-
- if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
- let jemalloc = PathBuf::from(jemalloc);
- println!("cargo:rustc-link-search=native={}",
- jemalloc.parent().unwrap().display());
- let stem = jemalloc.file_stem().unwrap().to_str().unwrap();
- let name = jemalloc.file_name().unwrap().to_str().unwrap();
- let kind = if name.ends_with(".a") {
- "static"
- } else {
- "dylib"
- };
- println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]);
- return;
- }
-
- let link_name = if target.contains("windows") { "jemalloc" } else { "jemalloc_pic" };
- let native = match native_lib_boilerplate("jemalloc", "jemalloc", link_name, "lib") {
- Ok(native) => native,
- _ => return,
- };
-
- let mut cmd = Command::new("sh");
- cmd.arg(native.src_dir.join("configure")
- .to_str()
- .unwrap()
- .replace("C:\\", "/c/")
- .replace("\\", "/"))
- .current_dir(&native.out_dir)
- // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
- // that GCC will run the preprocessor, and only the preprocessor, over
- // jemalloc's source files. If we don't specify CPPFLAGS, then at least
- // on ARM that step fails with a "Missing implementation for 32-bit
- // atomic operations" error. This is because no "-march" flag will be
- // passed to GCC, and then GCC won't define the
- // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
- // select an atomic operation implementation.
- .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default());
-
- if target.contains("ios") {
- cmd.arg("--disable-tls");
- } else if target.contains("android") {
- // We force android to have prefixed symbols because apparently
- // replacement of the libc allocator doesn't quite work. When this was
- // tested (unprefixed symbols), it was found that the `realpath`
- // function in libc would allocate with libc malloc (not jemalloc
- // malloc), and then the standard library would free with jemalloc free,
- // causing a segfault.
- //
- // If the test suite passes, however, without symbol prefixes then we
- // should be good to go!
- cmd.arg("--with-jemalloc-prefix=je_");
- cmd.arg("--disable-tls");
- } else if target.contains("dragonfly") || target.contains("musl") {
- cmd.arg("--with-jemalloc-prefix=je_");
- }
-
- if cfg!(feature = "debug") {
- // Enable jemalloc assertions.
- cmd.arg("--enable-debug");
- }
-
- cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
- cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));
-
- // for some reason, jemalloc configure doesn't detect this value
- // automatically for this target
- if target == "sparc64-unknown-linux-gnu" {
- cmd.arg("--with-lg-quantum=4");
- }
-
- run(&mut cmd);
-
- let mut make = Command::new(build_helper::make(&host));
- make.current_dir(&native.out_dir)
- .arg("build_lib_static");
-
- // These are intended for mingw32-make which we don't use
- if cfg!(windows) {
- make.env_remove("MAKEFLAGS").env_remove("MFLAGS");
- }
-
- // mingw make seems... buggy? unclear...
- if !host.contains("windows") {
- make.arg("-j")
- .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"));
- }
-
- run(&mut make);
-
- // The pthread_atfork symbols is used by jemalloc on android but the really
- // old android we're building on doesn't have them defined, so just make
- // sure the symbols are available.
- if target.contains("androideabi") {
- println!("cargo:rerun-if-changed=pthread_atfork_dummy.c");
- cc::Build::new()
- .flag("-fvisibility=hidden")
- .file("pthread_atfork_dummy.c")
- .compile("pthread_atfork_dummy");
- }
-}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![no_std]
-#![allow(unused_attributes)]
-#![unstable(feature = "alloc_jemalloc",
- reason = "implementation detail of std, does not provide any public API",
- issue = "0")]
-#![feature(core_intrinsics)]
-#![feature(libc)]
-#![feature(linkage)]
-#![feature(nll)]
-#![feature(staged_api)]
-#![feature(rustc_attrs)]
-#![cfg_attr(dummy_jemalloc, allow(dead_code, unused_extern_crates))]
-#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
-#![rustc_alloc_kind = "exe"]
-
-extern crate libc;
-
-#[cfg(not(dummy_jemalloc))]
-pub use contents::*;
-#[cfg(not(dummy_jemalloc))]
-mod contents {
- use libc::{c_int, c_void, size_t};
-
- // Note that the symbols here are prefixed by default on macOS and Windows (we
- // don't explicitly request it), and on Android and DragonFly we explicitly
- // request it as unprefixing cause segfaults (mismatches in allocators).
- extern "C" {
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows", target_env = "musl"),
- link_name = "je_mallocx")]
- fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows", target_env = "musl"),
- link_name = "je_calloc")]
- fn calloc(size: size_t, flags: c_int) -> *mut c_void;
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows", target_env = "musl"),
- link_name = "je_rallocx")]
- fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
- #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
- target_os = "dragonfly", target_os = "windows", target_env = "musl"),
- link_name = "je_sdallocx")]
- fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
- }
-
- const MALLOCX_ZERO: c_int = 0x40;
-
- // The minimum alignment guaranteed by the architecture. This value is used to
- // add fast paths for low alignment values.
- #[cfg(all(any(target_arch = "arm",
- target_arch = "mips",
- target_arch = "powerpc")))]
- const MIN_ALIGN: usize = 8;
- #[cfg(all(any(target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "aarch64",
- target_arch = "powerpc64",
- target_arch = "mips64",
- target_arch = "s390x",
- target_arch = "sparc64")))]
- const MIN_ALIGN: usize = 16;
-
- // MALLOCX_ALIGN(a) macro
- fn mallocx_align(a: usize) -> c_int {
- a.trailing_zeros() as c_int
- }
-
- fn align_to_flags(align: usize, size: usize) -> c_int {
- if align <= MIN_ALIGN && align <= size {
- 0
- } else {
- mallocx_align(align)
- }
- }
-
- // for symbol names src/librustc/middle/allocator.rs
- // for signatures src/librustc_allocator/lib.rs
-
- // linkage directives are provided as part of the current compiler allocator
- // ABI
-
- #[rustc_std_internal_symbol]
- pub unsafe extern fn __rde_alloc(size: usize, align: usize) -> *mut u8 {
- let flags = align_to_flags(align, size);
- let ptr = mallocx(size as size_t, flags) as *mut u8;
- ptr
- }
-
- #[rustc_std_internal_symbol]
- pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
- size: usize,
- align: usize) {
- let flags = align_to_flags(align, size);
- sdallocx(ptr as *mut c_void, size, flags);
- }
-
- #[rustc_std_internal_symbol]
- pub unsafe extern fn __rde_realloc(ptr: *mut u8,
- _old_size: usize,
- align: usize,
- new_size: usize) -> *mut u8 {
- let flags = align_to_flags(align, new_size);
- let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
- ptr
- }
-
- #[rustc_std_internal_symbol]
- pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
- let ptr = if align <= MIN_ALIGN && align <= size {
- calloc(size as size_t, 1) as *mut u8
- } else {
- let flags = align_to_flags(align, size) | MALLOCX_ZERO;
- mallocx(size as size_t, flags) as *mut u8
- };
- ptr
- }
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// See comments in build.rs for why this exists
-int pthread_atfork(void* prefork,
- void* postfork_parent,
- void* postfork_child) {
- return 0;
-}
//! Exposes the NonZero lang item which provides optimization hints.
-use ops::CoerceUnsized;
+use ops::{CoerceUnsized, DispatchFromDyn};
/// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations.
pub(crate) struct NonZero<T>(pub(crate) T);
impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
+
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
pub use self::unsize::CoerceUnsized;
+
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+pub use self::unsize::DispatchFromDyn;
/// [nomicon-coerce]: ../../nomicon/coercions.html
#[unstable(feature = "coerce_unsized", issue = "27732")]
#[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T> {
+pub trait CoerceUnsized<T: ?Sized> {
// Empty.
}
// *const T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+
+
+/// This is used for object safety, to check that a method's receiver type can be dispatched on.
+///
+/// example impl:
+///
+/// ```
+/// # #![feature(dispatch_from_dyn, unsize)]
+/// # use std::{ops::DispatchFromDyn, marker::Unsize};
+/// # struct Rc<T: ?Sized>(::std::rc::Rc<T>);
+/// impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T>
+/// where
+/// T: Unsize<U>,
+/// {}
+/// ```
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+#[cfg_attr(not(stage0), lang = "dispatch_from_dyn")]
+pub trait DispatchFromDyn<T> {
+ // Empty.
+}
+
+// &T -> &U
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+// &mut T -> &mut U
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+// *const T -> *const U
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+// *mut T -> *mut U
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+
use fmt;
use marker::Sized;
-use ops::{Deref, DerefMut, CoerceUnsized};
+use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn};
#[doc(inline)]
pub use marker::Unpin;
P: CoerceUnsized<U>,
{}
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, P, U> DispatchFromDyn<Pin<U>> for Pin<P>
+where
+ P: DispatchFromDyn<U>,
+{}
+
#[unstable(feature = "pin", issue = "49150")]
impl<P> Unpin for Pin<P> {}
use convert::From;
use intrinsics;
-use ops::CoerceUnsized;
+use ops::{CoerceUnsized, DispatchFromDyn};
use fmt;
use hash;
use marker::{PhantomData, Unsize};
#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { }
+#[unstable(feature = "ptr_internals", issue = "0")]
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> { }
+
#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> fmt::Pointer for Unique<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
+#[unstable(feature = "dispatch_from_dyn", issue = "0")]
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
+
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> fmt::Debug for NonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::ReEmpty => {
// No variant fields to hash for these ...
}
- ty::ReCanonical(c) => {
- c.hash_stable(hcx, hasher);
- }
ty::ReLateBound(db, ty::BrAnon(i)) => {
db.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
}
}
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundTyIndex {
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundVar {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
Param(param_ty) => {
param_ty.hash_stable(hcx, hasher);
}
+ Bound(bound_ty) => {
+ bound_ty.hash_stable(hcx, hasher);
+ }
Foreign(def_id) => {
def_id.hash_stable(hcx, hasher);
}
FreshTy(a),
FreshIntTy(a),
FreshFloatTy(a),
- BoundTy(a),
});
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
use std::sync::atomic::Ordering;
use ty::fold::{TypeFoldable, TypeFolder};
use ty::subst::Kind;
-use ty::{self, BoundTy, BoundTyIndex, Lift, List, Ty, TyCtxt, TypeFlags};
+use ty::{self, BoundTy, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
query_state: &'cx mut OriginalQueryValues<'tcx>,
// Note that indices is only used once `var_values` is big enough to be
// heap-allocated.
- indices: FxHashMap<Kind<'tcx>, BoundTyIndex>,
+ indices: FxHashMap<Kind<'tcx>, BoundVar>,
canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
needs_canonical_flags: TypeFlags,
+
+ binder_index: ty::DebruijnIndex,
}
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> {
self.tcx
}
+ fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+ where T: TypeFoldable<'tcx>
+ {
+ self.binder_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.binder_index.shift_out(1);
+ t
+ }
+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReLateBound(..) => {
- // leave bound regions alone
- r
+ ty::ReLateBound(index, ..) => {
+ if index >= self.binder_index {
+ bug!("escaping late bound region during canonicalization")
+ } else {
+ r
+ }
}
ty::ReVar(vid) => {
| ty::ReErased => self.canonicalize_region_mode
.canonicalize_free_region(self, r),
- ty::ReClosureBound(..) | ty::ReCanonical(_) => {
- bug!("canonical region encountered during canonicalization")
+ ty::ReClosureBound(..) => {
+ bug!("closure bound region encountered during canonicalization")
}
}
}
bug!("encountered a fresh type during canonicalization")
}
- ty::Infer(ty::BoundTy(_)) => {
- bug!("encountered a canonical type during canonicalization")
+ ty::Bound(bound_ty) => {
+ if bound_ty.index >= self.binder_index {
+ bug!("escaping bound type during canonicalization")
+ } else {
+ t
+ }
}
ty::Closure(..)
where
V: TypeFoldable<'tcx> + Lift<'gcx>,
{
- debug_assert!(
- !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS),
- "canonicalizing a canonical value: {:?}",
- value,
- );
-
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
} else {
variables: SmallVec::new(),
query_state,
indices: FxHashMap::default(),
+ binder_index: ty::INNERMOST,
};
let out_value = value.fold_with(&mut canonicalizer);
/// or returns an existing variable if `kind` has already been
/// seen. `kind` is expected to be an unbound variable (or
/// potentially a free region).
- fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundTy {
+ fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundVar {
let Canonicalizer {
variables,
query_state,
// direct linear search of `var_values`.
if let Some(idx) = var_values.iter().position(|&k| k == kind) {
// `kind` is already present in `var_values`.
- BoundTyIndex::new(idx)
+ BoundVar::new(idx)
} else {
// `kind` isn't present in `var_values`. Append it. Likewise
// for `info` and `variables`.
*indices = var_values
.iter()
.enumerate()
- .map(|(i, &kind)| (kind, BoundTyIndex::new(i)))
+ .map(|(i, &kind)| (kind, BoundVar::new(i)))
.collect();
}
// The cv is the index of the appended element.
- BoundTyIndex::new(var_values.len() - 1)
+ BoundVar::new(var_values.len() - 1)
}
} else {
// `var_values` is large. Do a hashmap search via `indices`.
variables.push(info);
var_values.push(kind);
assert_eq!(variables.len(), var_values.len());
- BoundTyIndex::new(variables.len() - 1)
+ BoundVar::new(variables.len() - 1)
})
};
- BoundTy {
- level: ty::INNERMOST,
- var,
- }
+ var
}
/// Shorthand helper that creates a canonical region variable for
info: CanonicalVarInfo,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
- let b = self.canonical_var(info, r.into());
- debug_assert_eq!(ty::INNERMOST, b.level);
- self.tcx().mk_region(ty::ReCanonical(b.var))
+ let var = self.canonical_var(info, r.into());
+ let region = ty::ReLateBound(
+ self.binder_index,
+ ty::BoundRegion::BrAnon(var.as_u32())
+ );
+ self.tcx().mk_region(region)
}
/// Given a type variable `ty_var` of the given kind, first check
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Ty(ty_kind),
};
- let b = self.canonical_var(info, ty_var.into());
- debug_assert_eq!(ty::INNERMOST, b.level);
- self.tcx().mk_infer(ty::InferTy::BoundTy(b))
+ let var = self.canonical_var(info, ty_var.into());
+ self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var)))
}
}
}
//! - a map M (of type `CanonicalVarValues`) from those canonical
//! variables back to the original.
//!
-//! We can then do queries using T2. These will give back constriants
+//! We can then do queries using T2. These will give back constraints
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
use syntax::source_map::Span;
use ty::fold::TypeFoldable;
use ty::subst::Kind;
-use ty::{self, BoundTyIndex, Lift, List, Region, TyCtxt};
+use ty::{self, BoundVar, Lift, List, Region, TyCtxt};
mod canonicalizer;
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarValues<'tcx> {
- pub var_values: IndexVec<BoundTyIndex, Kind<'tcx>>,
+ pub var_values: IndexVec<BoundVar, Kind<'tcx>>,
}
/// When we canonicalize a value to form a query, we wind up replacing
variables: &List<CanonicalVarInfo>,
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
) -> CanonicalVarValues<'tcx> {
- let var_values: IndexVec<BoundTyIndex, Kind<'tcx>> = variables
+ let var_values: IndexVec<BoundVar, Kind<'tcx>> = variables
.iter()
.map(|info| self.instantiate_canonical_var(span, *info, &universe_map))
.collect();
} where R: Lift<'tcx>
}
-impl<'tcx> Index<BoundTyIndex> for CanonicalVarValues<'tcx> {
+impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = Kind<'tcx>;
- fn index(&self, value: BoundTyIndex) -> &Kind<'tcx> {
+ fn index(&self, value: BoundVar) -> &Kind<'tcx> {
&self.var_values[value]
}
}
use traits::{Obligation, ObligationCause, PredicateObligation};
use ty::fold::TypeFoldable;
use ty::subst::{Kind, UnpackedKind};
-use ty::{self, BoundTyIndex, Lift, Ty, TyCtxt};
+use ty::{self, BoundVar, Lift, Ty, TyCtxt};
impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
/// The "main method" for a canonicalized trait query. Given the
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
- &v.var_values[BoundTyIndex::new(index)]
+ &v.var_values[BoundVar::new(index)]
});
match (original_value.unpack(), result_value.unpack()) {
(UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => {
// ...also include the other query region constraints from the query.
output_query_region_constraints.extend(
query_response.value.region_constraints.iter().filter_map(|r_c| {
- let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below
- let k1 = substitute_value(self.tcx, &result_subst, &k1);
- let r2 = substitute_value(self.tcx, &result_subst, &r2);
+ let r_c = substitute_value(self.tcx, &result_subst, r_c);
+
+ // Screen out `'a: 'a` cases -- we skip the binder here but
+ // only care the inner values to one another, so they are still at
+ // consistent binding levels.
+ let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
if k1 != r2.into() {
- Some(ty::Binder::bind(ty::OutlivesPredicate(k1, r2)))
+ Some(r_c)
} else {
None
}
// is directly equal to one of the canonical variables in the
// result, then we can type the corresponding value from the
// input. See the example above.
- let mut opt_values: IndexVec<BoundTyIndex, Option<Kind<'tcx>>> =
+ let mut opt_values: IndexVec<BoundVar, Option<Kind<'tcx>>> =
IndexVec::from_elem_n(None, query_response.variables.len());
// In terms of our example above, we are iterating over pairs like:
match result_value.unpack() {
UnpackedKind::Type(result_value) => {
// e.g., here `result_value` might be `?0` in the example above...
- if let ty::Infer(ty::InferTy::BoundTy(b)) = result_value.sty {
- // in which case we would set `canonical_vars[0]` to `Some(?U)`.
+ if let ty::Bound(b) = result_value.sty {
+ // ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
+
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(b.index, ty::INNERMOST);
opt_values[b.var] = Some(*original_value);
}
}
UnpackedKind::Lifetime(result_value) => {
// e.g., here `result_value` might be `'?1` in the example above...
- if let &ty::RegionKind::ReCanonical(index) = result_value {
- // in which case we would set `canonical_vars[0]` to `Some('static)`.
- opt_values[index] = Some(*original_value);
+ if let &ty::RegionKind::ReLateBound(index, br) = result_value {
+ // ... in which case we would set `canonical_vars[0]` to `Some('static)`.
+
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(index, ty::INNERMOST);
+ opt_values[br.assert_bound_var()] = Some(*original_value);
}
}
}
.enumerate()
.map(|(index, info)| {
if info.is_existential() {
- match opt_values[BoundTyIndex::new(index)] {
+ match opt_values[BoundVar::new(index)] {
Some(k) => k,
None => self.instantiate_canonical_var(cause.span, *info, |u| {
universe_map[u.as_usize()]
// canonical variable; this is taken from
// `query_response.var_values` after applying the substitution
// `result_subst`.
- let substituted_query_response = |index: BoundTyIndex| -> Kind<'tcx> {
+ let substituted_query_response = |index: BoundVar| -> Kind<'tcx> {
query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
};
unsubstituted_region_constraints
.iter()
.map(move |constraint| {
- let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
- let k1 = substitute_value(self.tcx, result_subst, k1);
- let r2 = substitute_value(self.tcx, result_subst, r2);
+ let constraint = substitute_value(self.tcx, result_subst, constraint);
+ let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
Obligation::new(
cause.clone(),
param_env,
match k1.unpack() {
UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
- ty::Binder::dummy(
+ ty::Binder::bind(
ty::OutlivesPredicate(r1, r2)
- )),
+ )
+ ),
UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives(
- ty::Binder::dummy(ty::OutlivesPredicate(
- t1, r2
- )))
+ ty::Binder::bind(
+ ty::OutlivesPredicate(t1, r2)
+ )
+ ),
}
)
})
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
variables1: &OriginalQueryValues<'tcx>,
- variables2: impl Fn(BoundTyIndex) -> Kind<'tcx>,
+ variables2: impl Fn(BoundVar) -> Kind<'tcx>,
) -> InferResult<'tcx, ()> {
self.commit_if_ok(|_| {
let mut obligations = vec![];
for (index, value1) in variables1.var_values.iter().enumerate() {
- let value2 = variables2(BoundTyIndex::new(index));
+ let value2 = variables2(BoundVar::new(index));
match (value1.unpack(), value2.unpack()) {
(UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
}
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
})
- .map(ty::Binder::dummy) // no bound regions in the code above
+ .map(ty::Binder::dummy) // no bound vars in the code above
.chain(
outlives_obligations
.map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
- .map(ty::Binder::dummy), // no bound regions in the code above
+ .map(ty::Binder::dummy) // no bound vars in the code above
)
.collect();
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
use infer::canonical::{Canonical, CanonicalVarValues};
-use ty::fold::{TypeFoldable, TypeFolder};
+use ty::fold::TypeFoldable;
use ty::subst::UnpackedKind;
-use ty::{self, Ty, TyCtxt, TypeFlags};
+use ty::{self, TyCtxt};
impl<'tcx, V> Canonical<'tcx, V> {
/// Instantiate the wrapped value, replacing each canonical value
T: TypeFoldable<'tcx>,
{
if var_values.var_values.is_empty() {
- debug_assert!(!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS));
- value.clone()
- } else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) {
value.clone()
} else {
- value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values })
- }
-}
-
-struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
- tcx: TyCtxt<'cx, 'gcx, 'tcx>,
- var_values: &'cx CanonicalVarValues<'tcx>,
-}
-
-impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> {
- fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
- self.tcx
- }
-
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match t.sty {
- ty::Infer(ty::InferTy::BoundTy(b)) => {
- debug_assert_eq!(ty::INNERMOST, b.level);
- match self.var_values.var_values[b.var].unpack() {
- UnpackedKind::Type(ty) => ty,
- r => bug!("{:?} is a type but value is {:?}", b, r),
- }
+ let fld_r = |br: ty::BoundRegion| {
+ match var_values.var_values[br.assert_bound_var()].unpack() {
+ UnpackedKind::Lifetime(l) => l,
+ r => bug!("{:?} is a region but value is {:?}", br, r),
}
- _ => {
- if !t.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) {
- t
- } else {
- t.super_fold_with(self)
- }
+ };
+
+ let fld_t = |bound_ty: ty::BoundTy| {
+ match var_values.var_values[bound_ty.var].unpack() {
+ UnpackedKind::Type(ty) => ty,
+ r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
}
- }
- }
+ };
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match r {
- ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() {
- UnpackedKind::Lifetime(l) => l,
- r => bug!("{:?} is a region but value is {:?}", c, r),
- },
- _ => r.super_fold_with(self),
- }
+ tcx.replace_escaping_bound_vars(value, fld_r, fld_t)
}
}
}
}
- ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
span_bug!(
self.span,
}
// We shouldn't encounter an error message with ReClosureBound.
- ty::ReCanonical(..) | ty::ReClosureBound(..) => {
+ ty::ReClosureBound(..) => {
bug!("encountered unexpected ReClosureBound: {:?}", region,);
}
};
self.tcx().types.re_erased
}
- ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
bug!(
"encountered unexpected region: {:?}",
t
}
- ty::Infer(ty::BoundTy(..)) =>
- bug!("encountered canonical ty during freshening"),
+ ty::Bound(..) =>
+ bug!("encountered bound ty during freshening"),
ty::Generator(..) |
ty::Bool |
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let tcx = self.tcx();
match (a, b) {
- (&ty::ReCanonical(..), _)
- | (_, &ty::ReCanonical(..))
- | (&ty::ReClosureBound(..), _)
+ (&ty::ReClosureBound(..), _)
| (_, &ty::ReClosureBound(..))
| (&ReLateBound(..), _)
| (_, &ReLateBound(..))
ty, region, origin
);
- assert!(!ty.has_escaping_regions());
+ assert!(!ty.has_escaping_bound_vars());
let components = self.tcx.outlives_components(ty);
self.components_must_outlive(origin, components, region);
predicates
.into_iter()
.filter_map(|p| p.as_ref().to_opt_type_outlives())
- .filter_map(|p| p.no_late_bound_regions())
+ .filter_map(|p| p.no_bound_vars())
.filter(move |p| compare_ty(p.0))
}
}
ty::RePlaceholder(placeholder) => placeholder.universe,
ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
- ty::ReCanonical(..) => bug!(
- "region_universe(): encountered canonical region {:?}",
- region
- ),
}
}
// Shouldn't have any LBR here, so we can safely put
// this under a binder below without fear of accidental
// capture.
- assert!(!a.has_escaping_regions());
- assert!(!b.has_escaping_regions());
+ assert!(!a.has_escaping_bound_vars());
+ assert!(!b.has_escaping_bound_vars());
// can't make progress on `A <: B` if both A and B are
// type variables, so record an obligation. We also
DropTraitLangItem, "drop", drop_trait, Target::Trait;
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait;
+ DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait;
AddTraitLangItem, "add", add_trait, Target::Trait;
SubTraitLangItem, "sub", sub_trait, Target::Trait;
}
&ty::Predicate::TypeOutlives(ref binder) => {
match (
- binder.no_late_bound_regions(),
- binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(),
+ binder.no_bound_vars(),
+ binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
) {
(None, Some(t_a)) => {
select.infcx().register_region_obligation_with_cause(
false
}
- ty::Infer(..) => match in_crate {
+ ty::Bound(..) | ty::Infer(..) => match in_crate {
InCrate::Local => false,
// The inference variable might be unified with a local
// type in that remote crate.
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
- ty::Infer(..) | ty::Error => None,
+ ty::Bound(..) | ty::Infer(..) | ty::Error => None,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
}
ty::Predicate::ObjectSafe(trait_def_id) => {
- let violations = self.tcx.object_safety_violations(trait_def_id);
+ let violations = self.tcx.global_tcx()
+ .object_safety_violations(trait_def_id);
self.tcx.report_object_safety_error(span,
trait_def_id,
violations)
}
TraitNotObjectSafe(did) => {
- let violations = self.tcx.object_safety_violations(did);
+ let violations = self.tcx.global_tcx().object_safety_violations(did);
self.tcx.report_object_safety_error(span, did, violations)
}
debug!("normalize_projection_type(projection_ty={:?})",
projection_ty);
- debug_assert!(!projection_ty.has_escaping_regions());
+ debug_assert!(!projection_ty.has_escaping_bound_vars());
// FIXME(#20304) -- cache
}
ty::Predicate::TypeOutlives(ref binder) => {
- // Check if there are higher-ranked regions.
- match binder.no_late_bound_regions() {
+ // Check if there are higher-ranked vars.
+ match binder.no_bound_vars() {
// If there are, inspect the underlying type further.
None => {
// Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`.
let binder = binder.map_bound_ref(|pred| pred.0);
- // Check if the type has any bound regions.
- match binder.no_late_bound_regions() {
+ // Check if the type has any bound vars.
+ match binder.no_bound_vars() {
// If so, this obligation is an error (for now). Eventually we should be
// able to support additional cases here, like `for<'a> &'a str: 'a`.
// NOTE: this is duplicate-implemented between here and fulfillment.
domain_goal: PolyDomainGoal<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
) -> GoalKind<'tcx> {
- match domain_goal.no_late_bound_regions() {
+ match domain_goal.no_bound_vars() {
Some(p) => p.into_goal(),
None => GoalKind::Quantified(
QuantifierKind::Universal,
//! object if all of their methods meet certain criteria. In particular,
//! they must:
//!
-//! - have a suitable receiver from which we can extract a vtable;
+//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version
+//! that doesn't contain the vtable;
//! - not reference the erased type `Self` except for in this receiver;
//! - not have generic type parameters
use hir::def_id::DefId;
use lint;
-use traits;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
-use ty::util::ExplicitSelf;
+use traits::{self, Obligation, ObligationCause};
+use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate};
+use ty::subst::{Subst, Substs};
use std::borrow::Cow;
-use syntax::ast;
+use std::iter::{self};
+use syntax::ast::{self, Name};
use syntax_pos::Span;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
format!("method `{}` references the `Self` type in where clauses", name).into(),
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
format!("method `{}` has generic type parameters", name).into(),
- ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
- format!("method `{}` has a non-standard `self` type", name).into(),
+ ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver) =>
+ format!("method `{}`'s receiver cannot be dispatched on", name).into(),
ObjectSafetyViolation::AssociatedConst(name) =>
format!("the trait cannot contain associated consts like `{}`", name).into(),
}
/// e.g., `fn foo<A>()`
Generic,
- /// arbitrary `self` type, e.g. `self: Rc<Self>`
- NonStandardSelfType,
+ /// the method's receiver (`self` argument) can't be dispatched on
+ UndispatchableReceiver,
}
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// Returns the object safety violations that affect
/// astconv - currently, Self in supertraits. This is needed
pub fn object_safety_violations(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation>
{
+ debug!("object_safety_violations: {:?}", trait_def_id);
+
traits::supertrait_def_ids(self, trait_def_id)
.flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
.collect()
method: &ty::AssociatedItem)
-> Option<MethodViolationCode>
{
- // The method's first parameter must be something that derefs (or
- // autorefs) to `&self`. For now, we only accept `self`, `&self`
- // and `Box<Self>`.
+ // The method's first parameter must be named `self`
if !method.method_has_self_argument {
return Some(MethodViolationCode::StaticMethod);
}
let sig = self.fn_sig(method.def_id);
- let self_ty = self.mk_self_type();
- let self_arg_ty = sig.skip_binder().inputs()[0];
- if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
- return Some(MethodViolationCode::NonStandardSelfType);
- }
-
- // The `Self` type is erased, so it should not appear in list of
- // arguments or return type apart from the receiver.
for input_ty in &sig.skip_binder().inputs()[1..] {
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
return Some(MethodViolationCode::WhereClauseReferencesSelf(span));
}
+ let receiver_ty = self.liberate_late_bound_regions(
+ method.def_id,
+ &sig.map_bound(|sig| sig.inputs()[0]),
+ );
+
+ // until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
+ // However, this is already considered object-safe. We allow it as a special case here.
+ // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
+ // `Receiver: Unsize<Receiver[Self => dyn Trait]>`
+ if receiver_ty != self.mk_self_type() {
+ if !self.receiver_is_dispatchable(method, receiver_ty) {
+ return Some(MethodViolationCode::UndispatchableReceiver);
+ } else {
+ // sanity check to make sure the receiver actually has the layout of a pointer
+
+ use ty::layout::Abi;
+
+ let param_env = self.param_env(method.def_id);
+
+ let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
+ match self.layout_of(param_env.and(ty)) {
+ Ok(layout) => &layout.abi,
+ Err(err) => bug!(
+ "Error: {}\n while computing layout for type {:?}", err, ty
+ )
+ }
+ };
+
+ // e.g. Rc<()>
+ let unit_receiver_ty = self.receiver_for_self_ty(
+ receiver_ty, self.mk_unit(), method.def_id
+ );
+
+ match abi_of_ty(unit_receiver_ty) {
+ &Abi::Scalar(..) => (),
+ abi => bug!("Receiver when Self = () should have a Scalar ABI, found {:?}", abi)
+ }
+
+ let trait_object_ty = self.object_ty_for_trait(
+ trait_def_id, self.mk_region(ty::ReStatic)
+ );
+
+ // e.g. Rc<dyn Trait>
+ let trait_object_receiver = self.receiver_for_self_ty(
+ receiver_ty, trait_object_ty, method.def_id
+ );
+
+ match abi_of_ty(trait_object_receiver) {
+ &Abi::ScalarPair(..) => (),
+ abi => bug!(
+ "Receiver when Self = {} should have a ScalarPair ABI, found {:?}",
+ trait_object_ty, abi
+ )
+ }
+ }
+ }
+
None
}
+ /// performs a type substitution to produce the version of receiver_ty when `Self = self_ty`
+ /// e.g. for receiver_ty = `Rc<Self>` and self_ty = `Foo`, returns `Rc<Foo>`
+ fn receiver_for_self_ty(
+ self, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId
+ ) -> Ty<'tcx> {
+ let substs = Substs::for_item(self, method_def_id, |param, _| {
+ if param.index == 0 {
+ self_ty.into()
+ } else {
+ self.mk_param_from_def(param)
+ }
+ });
+
+ receiver_ty.subst(self, substs)
+ }
+
+ /// creates the object type for the current trait. For example,
+ /// if the current trait is `Deref`, then this will be
+ /// `dyn Deref<Target=Self::Target> + 'static`
+ fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> {
+ debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
+
+ let trait_ref = ty::TraitRef::identity(self, trait_def_id);
+
+ let trait_predicate = ty::ExistentialPredicate::Trait(
+ ty::ExistentialTraitRef::erase_self_ty(self, trait_ref)
+ );
+
+ let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref))
+ .flat_map(|trait_ref| self.associated_items(trait_ref.def_id()))
+ .filter(|item| item.kind == ty::AssociatedKind::Type)
+ .collect::<Vec<_>>();
+
+ // existential predicates need to be in a specific order
+ associated_types.sort_by_key(|item| self.def_path_hash(item.def_id));
+
+ let projection_predicates = associated_types.into_iter().map(|item| {
+ ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+ ty: self.mk_projection(item.def_id, trait_ref.substs),
+ item_def_id: item.def_id,
+ substs: trait_ref.substs,
+ })
+ });
+
+ let existential_predicates = self.mk_existential_predicates(
+ iter::once(trait_predicate).chain(projection_predicates)
+ );
+
+ let object_ty = self.mk_dynamic(
+ ty::Binder::dummy(existential_predicates),
+ lifetime,
+ );
+
+ debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
+
+ object_ty
+ }
+
+ /// checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
+ /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
+ /// in the following way:
+ /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`
+ /// - require the following bound:
+ ///
+ /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
+ ///
+ /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
+ /// (substitution notation).
+ ///
+ /// some examples of receiver types and their required obligation
+ /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`
+ /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`
+ /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`
+ ///
+ /// The only case where the receiver is not dispatchable, but is still a valid receiver
+ /// type (just not object-safe), is when there is more than one level of pointer indirection.
+ /// e.g. `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
+ /// is no way, or at least no inexpensive way, to coerce the receiver from the version where
+ /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
+ /// contained by the trait object, because the object that needs to be coerced is behind
+ /// a pointer.
+ ///
+ /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
+ /// in a new check that `Trait` is object safe, creating a cycle. So instead, we fudge a little
+ /// by introducing a new type parameter `U` such that `Self: Unsize<U>` and `U: Trait + ?Sized`,
+ /// and use `U` in place of `dyn Trait`. Written as a chalk-style query:
+ ///
+ /// forall (U: Trait + ?Sized) {
+ /// if (Self: Unsize<U>) {
+ /// Receiver: DispatchFromDyn<Receiver[Self => U]>
+ /// }
+ /// }
+ ///
+ /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
+ /// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
+ /// for `self: Pin<Box<Self>>, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
+ //
+ // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
+ // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
+ // `self: Wrapper<Self>`.
+ #[allow(dead_code)]
+ fn receiver_is_dispatchable(
+ self,
+ method: &ty::AssociatedItem,
+ receiver_ty: Ty<'tcx>,
+ ) -> bool {
+ debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
+
+ let traits = (self.lang_items().unsize_trait(),
+ self.lang_items().dispatch_from_dyn_trait());
+ let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
+ (u, cu)
+ } else {
+ debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
+ return false;
+ };
+
+ // the type `U` in the query
+ // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
+ // FIXME(mikeyhew) this is a total hack, and we should replace it when real forall queries
+ // are implemented
+ let unsized_self_ty: Ty<'tcx> = self.mk_ty_param(
+ ::std::u32::MAX,
+ Name::intern("RustaceansAreAwesome").as_interned_str(),
+ );
+
+ // `Receiver[Self => U]`
+ let unsized_receiver_ty = self.receiver_for_self_ty(
+ receiver_ty, unsized_self_ty, method.def_id
+ );
+
+ // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
+ // `U: ?Sized` is already implied here
+ let param_env = {
+ let mut param_env = self.param_env(method.def_id);
+
+ // Self: Unsize<U>
+ let unsize_predicate = ty::TraitRef {
+ def_id: unsize_did,
+ substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]),
+ }.to_predicate();
+
+ // U: Trait<Arg1, ..., ArgN>
+ let trait_predicate = {
+ let substs = Substs::for_item(self, method.container.assert_trait(), |param, _| {
+ if param.index == 0 {
+ unsized_self_ty.into()
+ } else {
+ self.mk_param_from_def(param)
+ }
+ });
+
+ ty::TraitRef {
+ def_id: unsize_did,
+ substs,
+ }.to_predicate()
+ };
+
+ let caller_bounds: Vec<Predicate<'tcx>> = param_env.caller_bounds.iter().cloned()
+ .chain(iter::once(unsize_predicate))
+ .chain(iter::once(trait_predicate))
+ .collect();
+
+ param_env.caller_bounds = self.intern_predicates(&caller_bounds);
+
+ param_env
+ };
+
+ // Receiver: DispatchFromDyn<Receiver[Self => U]>
+ let obligation = {
+ let predicate = ty::TraitRef {
+ def_id: dispatch_from_dyn_did,
+ substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
+ }.to_predicate();
+
+ Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ predicate,
+ )
+ };
+
+ self.infer_ctxt().enter(|ref infcx| {
+ // the receiver is dispatchable iff the obligation holds
+ infcx.predicate_must_hold(&obligation)
+ })
+ }
+
fn contains_illegal_self_type_reference(self,
trait_def_id: DefId,
ty: Ty<'tcx>)
let ty = ty.super_fold_with(self);
match ty.sty {
- ty::Opaque(def_id, substs) if !substs.has_escaping_regions() => { // (*)
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // (*)
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal {
Reveal::UserFacing => ty,
}
}
- ty::Projection(ref data) if !data.has_escaping_regions() => { // (*)
+ ty::Projection(ref data) if !data.has_escaping_bound_vars() => { // (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
let infcx = selcx.infcx();
// We don't do cross-snapshot caching of obligations with escaping regions,
// so there's no cache key to use
- predicate.no_late_bound_regions()
+ predicate.no_bound_vars()
.map(|predicate| ProjectionCacheKey {
// We don't attempt to match up with a specific type-variable state
// from a specific call to `opt_normalize_projection_type` - if
| ty::Param(_)
| ty::Opaque(..)
| ty::Infer(_)
+ | ty::Bound(..)
| ty::Generator(..) => false,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let ty = ty.super_fold_with(self);
match ty.sty {
- ty::Opaque(def_id, substs) if !substs.has_escaping_regions() => {
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// (*)
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal {
}
}
- ty::Projection(ref data) if !data.has_escaping_regions() => {
+ ty::Projection(ref data) if !data.has_escaping_bound_vars() => {
// (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) |
ty::Predicate::ConstEvaluatable(..) => None,
- ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map(
+ ty::Predicate::RegionOutlives(ref data) => data.no_bound_vars().map(
|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a),
),
})
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
debug!("select({:?})", obligation);
- debug_assert!(!obligation.predicate.has_escaping_regions());
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
match obligation.predicate {
ty::Predicate::Trait(ref t) => {
- debug_assert!(!t.has_escaping_regions());
+ debug_assert!(!t.has_escaping_bound_vars());
let obligation = obligation.with(t.clone());
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
}
},
ty::Predicate::TypeOutlives(ref binder) => {
- assert!(!binder.has_escaping_regions());
- // Check if the type has higher-ranked regions.
- if binder.skip_binder().0.has_escaping_regions() {
+ assert!(!binder.has_escaping_bound_vars());
+ // Check if the type has higher-ranked vars.
+ if binder.skip_binder().0.has_escaping_bound_vars() {
// If so, this obligation is an error (for now). Eventually we should be
// able to support additional cases here, like `for<'a> &'a str: 'a`.
Ok(EvaluatedToErr)
}
} else {
- // If the type has no late bound regions, then if we assign all
+ // If the type has no late bound vars, then if we assign all
// the inference variables in it to be 'static, then the type
// will be 'static itself.
//
"candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
cache_fresh_trait_pred, stack
);
- debug_assert!(!stack.obligation.predicate.has_escaping_regions());
+ debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
if let Some(c) =
self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred)
placeholder_map: &infer::PlaceholderMap<'tcx>,
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
) -> bool {
- debug_assert!(!skol_trait_ref.has_escaping_regions());
+ debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
if self.infcx
.at(&obligation.cause, obligation.param_env)
.sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
obligation.self_ty().skip_binder()
);
- // Object-safety candidates are only applicable to object-safe
- // traits. Including this check is useful because it helps
- // inference in cases of traits like `BorrowFrom`, which are
- // not object-safe, and which rely on being able to infer the
- // self-type from one of the other inputs. Without this check,
- // these cases wind up being considered ambiguous due to a
- // (spurious) ambiguity introduced here.
- let predicate_trait_ref = obligation.predicate.to_poly_trait_ref();
- if !self.tcx().is_object_safe(predicate_trait_ref.def_id()) {
- return;
- }
-
self.probe(|this, _snapshot| {
// the code below doesn't care about regions, and the
// self-ty here doesn't escape this probe, so just erase
// T: Trait
// so it seems ok if we (conservatively) fail to accept that `Unsize`
// obligation above. Should be possible to extend this in the future.
- let source = match obligation.self_ty().no_late_bound_regions() {
+ let source = match obligation.self_ty().no_bound_vars() {
Some(t) => t,
None => {
// Don't add any candidates if there are bound regions.
ty::Infer(ty::TyVar(_)) => Ambiguous,
ty::UnnormalizedProjection(..)
- | ty::Infer(ty::BoundTy(_))
+ | ty::Bound(_)
| ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_)) => {
}
ty::UnnormalizedProjection(..)
- | ty::Infer(ty::BoundTy(_))
+ | ty::Bound(_)
| ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_)) => {
| ty::Param(..)
| ty::Foreign(..)
| ty::Projection(..)
- | ty::Infer(ty::BoundTy(_))
+ | ty::Bound(_)
| ty::Infer(ty::TyVar(_))
| ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
// assemble_candidates_for_unsizing should ensure there are no late bound
// regions here. See the comment there for more details.
let source = self.infcx
- .shallow_resolve(obligation.self_ty().no_late_bound_regions().unwrap());
+ .shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
let target = obligation
.predicate
.skip_binder()
sty_debug_print!(
self,
Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr,
- Generator, GeneratorWitness, Dynamic, Closure, Tuple,
+ Generator, GeneratorWitness, Dynamic, Closure, Tuple, Bound,
Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
ty::Infer(ty::IntVar(_)) => "integral variable".into(),
ty::Infer(ty::FloatVar(_)) => "floating-point variable".into(),
- ty::Infer(ty::BoundTy(_)) |
+ ty::Bound(_) |
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
ty::Foreign(def_id) => {
Some(ForeignSimplifiedType(def_id))
}
- ty::Infer(_) | ty::Error => None,
+ ty::Bound(..) | ty::Infer(_) | ty::Error => None,
}
}
self.add_substs(&substs.substs);
}
+ &ty::Bound(bound_ty) => {
+ self.add_binder(bound_ty.index);
+ }
+
&ty::Infer(infer) => {
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
self.add_flags(TypeFlags::HAS_TY_INFER);
match infer {
ty::FreshTy(_) |
ty::FreshIntTy(_) |
- ty::FreshFloatTy(_) |
- ty::BoundTy(_) => {
- self.add_flags(TypeFlags::HAS_CANONICAL_VARS);
+ ty::FreshFloatTy(_) => {
}
ty::TyVar(_) |
&ty::Projection(ref data) => {
// currently we can't normalize projections that
// include bound regions, so track those separately.
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
}
self.add_flags(TypeFlags::HAS_PROJECTION);
/// bound by `binder` or bound by some binder outside of `binder`.
/// If `binder` is `ty::INNERMOST`, this indicates whether
/// there are any late-bound regions that appear free.
- fn has_regions_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
- self.visit_with(&mut HasEscapingRegionsVisitor { outer_index: binder })
+ fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+ self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder })
}
/// True if this `self` has any regions that escape `binder` (and
/// hence are not bound by it).
- fn has_regions_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
- self.has_regions_bound_at_or_above(binder.shifted_in(1))
+ fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
+ self.has_vars_bound_at_or_above(binder.shifted_in(1))
}
- fn has_escaping_regions(&self) -> bool {
- self.has_regions_bound_at_or_above(ty::INNERMOST)
+ fn has_escaping_bound_vars(&self) -> bool {
+ self.has_vars_bound_at_or_above(ty::INNERMOST)
}
fn has_type_flags(&self, flags: TypeFlags) -> bool {
}
///////////////////////////////////////////////////////////////////////////
-// Late-bound region replacer
+// Bound vars replacer
-// Replaces the escaping regions in a type.
-
-struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+/// Replaces the escaping bound vars (late bound regions or bound types) in a type.
+struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
/// As with `RegionFolder`, represents the index of a binder *just outside*
current_index: ty::DebruijnIndex,
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
- map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>
+ fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> ty::Ty<'tcx> + 'a),
+}
+
+impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> {
+ fn new<F, G>(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ fld_r: &'a mut F,
+ fld_t: &'a mut G
+ ) -> Self
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>
+ {
+ BoundVarReplacer {
+ tcx,
+ current_index: ty::INNERMOST,
+ fld_r,
+ fld_t,
+ }
+ }
+}
+
+impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
+ self.current_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.current_index.shift_out(1);
+ t
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ match t.sty {
+ ty::Bound(bound_ty) => {
+ if bound_ty.index == self.current_index {
+ let fld_t = &mut self.fld_t;
+ let ty = fld_t(bound_ty);
+ ty::fold::shift_vars(
+ self.tcx,
+ &ty,
+ self.current_index.as_u32()
+ )
+ } else {
+ t
+ }
+ }
+ _ => {
+ if !t.has_vars_bound_at_or_above(self.current_index) {
+ // Nothing more to substitute.
+ t
+ } else {
+ t.super_fold_with(self)
+ }
+ }
+ }
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
+ ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
+ let fld_r = &mut self.fld_r;
+ let region = fld_r(br);
+ if let ty::ReLateBound(debruijn1, br) = *region {
+ // If the callback returns a late-bound region,
+ // that region should always use the INNERMOST
+ // debruijn index. Then we adjust it to the
+ // correct depth.
+ assert_eq!(debruijn1, ty::INNERMOST);
+ self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+ } else {
+ region
+ }
+ }
+ _ => r
+ }
+ }
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// same `BoundRegion` will reuse the previous result. A map is
/// returned at the end with each bound region and the free region
/// that replaced it.
- pub fn replace_late_bound_regions<T,F>(self,
+ ///
+ /// This method only replaces late bound regions and the result may still
+ /// contain escaping bound types.
+ pub fn replace_late_bound_regions<T, F>(
+ self,
value: &Binder<T>,
- mut f: F)
- -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
- where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
- T : TypeFoldable<'tcx>,
+ mut fld_r: F
+ ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ T: TypeFoldable<'tcx>
{
- let mut replacer = RegionReplacer::new(self, &mut f);
+ let mut map = BTreeMap::new();
+ let mut real_fldr = |br| {
+ *map.entry(br).or_insert_with(|| fld_r(br))
+ };
+
+ // identity for bound types
+ let mut fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty));
+
+ let mut replacer = BoundVarReplacer::new(self, &mut real_fldr, &mut fld_t);
let result = value.skip_binder().fold_with(&mut replacer);
- (result, replacer.map)
+ (result, map)
+ }
+
+ /// Replace all escaping bound vars. The `fld_r` closure replaces escaping
+ /// bound regions while the `fld_t` closure replaces escaping bound types.
+ pub fn replace_escaping_bound_vars<T, F, G>(
+ self,
+ value: &T,
+ mut fld_r: F,
+ mut fld_t: G
+ ) -> T
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
+ T: TypeFoldable<'tcx>
+ {
+ if !value.has_escaping_bound_vars() {
+ value.clone()
+ } else {
+ let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t);
+ let result = value.fold_with(&mut replacer);
+ result
+ }
+ }
+
+ /// Replace all types or regions bound by the given `Binder`. The `fld_r`
+ /// closure replaces bound regions while the `fld_t` closure replaces bound
+ /// types.
+ pub fn replace_bound_vars<T, F, G>(
+ self,
+ value: &Binder<T>,
+ fld_r: F,
+ fld_t: G
+ ) -> T
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
+ T: TypeFoldable<'tcx>
+ {
+ self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t)
}
/// Replace any late-bound regions bound in `value` with
}
}
-impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
- fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
- -> RegionReplacer<'a, 'gcx, 'tcx>
- where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>
- {
- RegionReplacer {
+///////////////////////////////////////////////////////////////////////////
+// Shifter
+//
+// Shifts the De Bruijn indices on all escaping bound vars by a
+// fixed amount. Useful in substitution or when otherwise introducing
+// a binding level that is not intended to capture the existing bound
+// vars. See comment on `shift_vars_through_binders` method in
+// `subst.rs` for more details.
+
+struct Shifter<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+
+ current_index: ty::DebruijnIndex,
+ amount: u32,
+}
+
+impl Shifter<'a, 'gcx, 'tcx> {
+ pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32) -> Self {
+ Shifter {
tcx,
current_index: ty::INNERMOST,
- fld_r,
- map: BTreeMap::default()
+ amount,
}
}
}
-impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.has_regions_bound_at_or_above(self.current_index) {
- return t;
- }
-
- t.super_fold_with(self)
- }
-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
- let fld_r = &mut self.fld_r;
- let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
- if let ty::ReLateBound(debruijn1, br) = *region {
- // If the callback returns a late-bound region,
- // that region should always use the INNERMOST
- // debruijn index. Then we adjust it to the
- // correct depth.
- assert_eq!(debruijn1, ty::INNERMOST);
- self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+ ty::ReLateBound(debruijn, br) => {
+ if self.amount == 0 || debruijn < self.current_index {
+ r
} else {
- region
+ let shifted = ty::ReLateBound(debruijn.shifted_in(self.amount), br);
+ self.tcx.mk_region(shifted)
}
}
_ => r
}
}
-}
-///////////////////////////////////////////////////////////////////////////
-// Region shifter
-//
-// Shifts the De Bruijn indices on all escaping bound regions by a
-// fixed amount. Useful in substitution or when otherwise introducing
-// a binding level that is not intended to capture the existing bound
-// regions. See comment on `shift_regions_through_binders` method in
-// `subst.rs` for more details.
+ fn fold_ty(&mut self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> {
+ match ty.sty {
+ ty::Bound(bound_ty) => {
+ if self.amount == 0 || bound_ty.index < self.current_index {
+ ty
+ } else {
+ let shifted = ty::BoundTy {
+ index: bound_ty.index.shifted_in(self.amount),
+ var: bound_ty.var,
+ kind: bound_ty.kind,
+ };
+ self.tcx.mk_ty(ty::Bound(shifted))
+ }
+ }
-pub fn shift_region(region: ty::RegionKind, amount: u32) -> ty::RegionKind {
- match region {
- ty::ReLateBound(debruijn, br) => {
- ty::ReLateBound(debruijn.shifted_in(amount), br)
- }
- _ => {
- region
+ _ => ty.super_fold_with(self),
}
}
}
-pub fn shift_region_ref<'a, 'gcx, 'tcx>(
+pub fn shift_region<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
region: ty::Region<'tcx>,
- amount: u32)
- -> ty::Region<'tcx>
-{
+ amount: u32
+) -> ty::Region<'tcx> {
match region {
- &ty::ReLateBound(debruijn, br) if amount > 0 => {
- tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br))
+ ty::ReLateBound(debruijn, br) if amount > 0 => {
+ tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br))
}
_ => {
region
}
}
-pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- amount: u32,
- value: &T) -> T
- where T: TypeFoldable<'tcx>
-{
- debug!("shift_regions(value={:?}, amount={})",
+pub fn shift_vars<'a, 'gcx, 'tcx, T>(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ value: &T,
+ amount: u32
+) -> T where T: TypeFoldable<'tcx> {
+ debug!("shift_vars(value={:?}, amount={})",
value, amount);
- value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
- shift_region_ref(tcx, region, amount)
- }))
+ value.fold_with(&mut Shifter::new(tcx, amount))
}
-/// An "escaping region" is a bound region whose binder is not part of `t`.
+/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
+/// bound region or a bound type.
///
/// So, for example, consider a type like the following, which has two binders:
///
/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
/// fn type*, that type has an escaping region: `'a`.
///
-/// Note that what I'm calling an "escaping region" is often just called a "free region". However,
-/// we already use the term "free region". It refers to the regions that we use to represent bound
-/// regions on a fn definition while we are typechecking its body.
+/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
+/// we already use the term "free var". It refers to the regions or types that we use to represent
+/// bound regions or type params on a fn definition while we are typechecking its body.
///
/// To clarify, conceptually there is no particular difference between
-/// an "escaping" region and a "free" region. However, there is a big
+/// an "escaping" var and a "free" var. However, there is a big
/// difference in practice. Basically, when "entering" a binding
/// level, one is generally required to do some sort of processing to
-/// a bound region, such as replacing it with a fresh/placeholder
-/// region, or making an entry in the environment to represent the
-/// scope to which it is attached, etc. An escaping region represents
-/// a bound region for which this processing has not yet been done.
-struct HasEscapingRegionsVisitor {
+/// a bound var, such as replacing it with a fresh/placeholder
+/// var, or making an entry in the environment to represent the
+/// scope to which it is attached, etc. An escaping var represents
+/// a bound var for which this processing has not yet been done.
+struct HasEscapingVarsVisitor {
/// Anything bound by `outer_index` or "above" is escaping
outer_index: ty::DebruijnIndex,
}
-impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor {
+impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
self.outer_index.shift_in(1);
let result = t.super_visit_with(self);
// `outer_index`, that means that `t` contains some content
// bound at `outer_index` or above (because
// `outer_exclusive_binder` is always 1 higher than the
- // content in `t`). Therefore, `t` has some escaping regions.
+ // content in `t`). Therefore, `t` has some escaping vars.
t.outer_exclusive_binder > self.outer_index
}
impl<'a, 'b, 'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> {
- assert!(!substs.has_escaping_regions(),
+ assert!(!substs.has_escaping_bound_vars(),
"substs of instance {:?} not normalized for codegen: {:?}",
def_id, substs);
Instance { def: InstanceDef::Item(def_id), substs: substs }
ty::Param(_) |
ty::Opaque(..) |
ty::Infer(_) |
+ ty::Bound(..) |
ty::Error |
ty::GeneratorWitness(..) |
ty::Never |
}
tcx.layout_raw(param_env.and(normalized))?
}
- ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+
+ ty::Bound(..) |
+ ty::UnnormalizedProjection(..) |
+ ty::GeneratorWitness(..) |
+ ty::Infer(_) => {
bug!("LayoutDetails::compute: unexpected type `{}`", ty)
}
+
ty::Param(_) | ty::Error => {
return Err(LayoutError::Unknown(ty));
}
}
}
- ty::Projection(_) | ty::UnnormalizedProjection(..) |
+ ty::Projection(_) | ty::UnnormalizedProjection(..) | ty::Bound(..) |
ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => {
bug!("TyLayout::field_type: unexpected type `{}`", this.ty)
}
use hir;
-pub use self::sty::{Binder, BoundTy, BoundTyIndex, DebruijnIndex, INNERMOST};
+pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST};
pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig};
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
// Currently we can't normalize projections w/ bound regions.
const HAS_NORMALIZABLE_PROJECTION = 1 << 12;
- // Set if this includes a "canonical" type or region var --
- // ought to be true only for the results of canonicalization.
- const HAS_CANONICAL_VARS = 1 << 13;
-
/// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate.
- const HAS_RE_LATE_BOUND = 1 << 14;
+ const HAS_RE_LATE_BOUND = 1 << 13;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_TY_CLOSURE.bits |
TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
- TypeFlags::HAS_CANONICAL_VARS.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits;
}
}
}
}
+ Bound(..) |
Infer(..) => {
bug!("unexpected type `{:?}` in sized_constraint_for_ty",
ty)
// we simply fallback to the most restrictive rule, which
// requires that `Pi: 'a` for all `i`.
ty::Projection(ref data) => {
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
// best case: no escaping regions, so push the
// projection and skip the subtree (thus generating no
// constraints for Pi). This defers the choice between
ty::FnDef(..) | // OutlivesFunction (*)
ty::FnPtr(_) | // OutlivesFunction (*)
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
+ ty::Bound(..) |
ty::Error => {
// (*) Bare functions and traits are both binders. In the
// RFC, this means we would add the bound regions to the
ty::UnnormalizedProjection(data.fold_with(folder))
}
ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
- ty::Bool | ty::Char | ty::Str | ty::Int(_) |
- ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
- ty::Param(..) | ty::Never | ty::Foreign(..) => return self
+
+ ty::Bool |
+ ty::Char |
+ ty::Str |
+ ty::Int(_) |
+ ty::Uint(_) |
+ ty::Float(_) |
+ ty::Error |
+ ty::Infer(_) |
+ ty::Param(..) |
+ ty::Bound(..) |
+ ty::Never |
+ ty::Foreign(..) => return self
};
if self.sty == sty {
data.visit_with(visitor)
}
ty::Opaque(_, ref substs) => substs.visit_with(visitor),
- ty::Bool | ty::Char | ty::Str | ty::Int(_) |
- ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
- ty::Param(..) | ty::Never | ty::Foreign(..) => false,
+
+ ty::Bool |
+ ty::Char |
+ ty::Str |
+ ty::Int(_) |
+ ty::Uint(_) |
+ ty::Float(_) |
+ ty::Error |
+ ty::Infer(_) |
+ ty::Bound(..) |
+ ty::Param(..) |
+ ty::Never |
+ ty::Foreign(..) => false,
}
}
_ => false,
}
}
+
+ /// When canonicalizing, we replace unbound inference variables and free
+ /// regions with anonymous late bound regions. This method asserts that
+ /// we have an anonymous late bound region, which hence may refer to
+ /// a canonical variable.
+ pub fn assert_bound_var(&self) -> BoundVar {
+ match *self {
+ BoundRegion::BrAnon(var) => BoundVar::from_u32(var),
+ _ => bug!("bound region is not anonymous"),
+ }
+ }
}
/// N.B., If you change this, you'll probably want to change the corresponding
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}
Param(ParamTy),
+ /// Bound type variable, used only when preparing a trait query.
+ Bound(BoundTy),
+
/// A type variable used during type checking.
Infer(InferTy),
/// or some placeholder type.
pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
-> ty::TraitRef<'tcx> {
- // otherwise the escaping regions would be captured by the binder
- // debug_assert!(!self_ty.has_escaping_regions());
+ // otherwise the escaping vars would be captured by the binder
+ // debug_assert!(!self_ty.has_escaping_bound_vars());
ty::TraitRef {
def_id: self.def_id,
}
}
-/// Binder is a binder for higher-ranked lifetimes. It is part of the
+/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
/// (which would be represented by the type `PolyTraitRef ==
/// Binder<TraitRef>`). Note that when we instantiate,
-/// erase, or otherwise "discharge" these bound regions, we change the
+/// erase, or otherwise "discharge" these bound vars, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g. `liberate_late_bound_regions`).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
impl<T> Binder<T> {
/// Wraps `value` in a binder, asserting that `value` does not
- /// contain any bound regions that would be bound by the
+ /// contain any bound vars that would be bound by the
/// binder. This is commonly used to 'inject' a value T into a
/// different binding level.
pub fn dummy<'tcx>(value: T) -> Binder<T>
where T: TypeFoldable<'tcx>
{
- debug_assert!(!value.has_escaping_regions());
+ debug_assert!(!value.has_escaping_bound_vars());
Binder(value)
}
- /// Wraps `value` in a binder, binding late-bound regions (if any).
- pub fn bind<'tcx>(value: T) -> Binder<T>
- {
+ /// Wraps `value` in a binder, binding higher-ranked vars (if any).
+ pub fn bind<'tcx>(value: T) -> Binder<T> {
Binder(value)
}
/// Skips the binder and returns the "bound" value. This is a
/// risky thing to do because it's easy to get confused about
/// debruijn indices and the like. It is usually better to
- /// discharge the binder using `no_late_bound_regions` or
+ /// discharge the binder using `no_bound_vars` or
/// `replace_late_bound_regions` or something like
/// that. `skip_binder` is only valid when you are either
- /// extracting data that has nothing to do with bound regions, you
+ /// extracting data that has nothing to do with bound vars, you
/// are doing some sort of test that does not involve bound
/// regions, or you are being very careful about your depth
/// accounting.
///
/// - extracting the def-id from a PolyTraitRef;
/// - comparing the self type of a PolyTraitRef to see if it is equal to
- /// a type parameter `X`, since the type `X` does not reference any regions
+ /// a type parameter `X`, since the type `X` does not reference any regions
pub fn skip_binder(&self) -> &T {
&self.0
}
}
/// Unwraps and returns the value within, but only if it contains
- /// no bound regions at all. (In other words, if this binder --
+ /// no bound vars at all. (In other words, if this binder --
/// and indeed any enclosing binder -- doesn't bind anything at
/// all.) Otherwise, returns `None`.
///
/// (One could imagine having a method that just unwraps a single
- /// binder, but permits late-bound regions bound by enclosing
+ /// binder, but permits late-bound vars bound by enclosing
/// binders, but that would require adjusting the debruijn
/// indices, and given the shallow binding structure we often use,
/// would not be that useful.)
- pub fn no_late_bound_regions<'tcx>(self) -> Option<T>
- where T : TypeFoldable<'tcx>
+ pub fn no_bound_vars<'tcx>(self) -> Option<T>
+ where T: TypeFoldable<'tcx>
{
- if self.skip_binder().has_escaping_regions() {
+ if self.skip_binder().has_escaping_bound_vars() {
None
} else {
Some(self.skip_binder().clone())
/// `ClosureRegionRequirements` that are produced by MIR borrowck.
/// See `ClosureRegionRequirements` for more details.
ReClosureBound(RegionVid),
-
- /// Canonicalized region, used only when preparing a trait query.
- ReCanonical(BoundTyIndex),
}
impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
FreshTy(u32),
FreshIntTy(u32),
FreshFloatTy(u32),
-
- /// Bound type variable, used only when preparing a trait query.
- BoundTy(BoundTy),
}
newtype_index! {
- pub struct BoundTyIndex { .. }
+ pub struct BoundVar { .. }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct BoundTy {
- pub level: DebruijnIndex,
- pub var: BoundTyIndex,
+ pub index: DebruijnIndex,
+ pub var: BoundVar,
+ pub kind: BoundTyKind,
}
-impl_stable_hash_for!(struct BoundTy { level, var });
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+pub enum BoundTyKind {
+ Anon,
+ Param(InternedString),
+}
+
+impl_stable_hash_for!(struct BoundTy { index, var, kind });
+impl_stable_hash_for!(enum self::BoundTyKind { Anon, Param(a) });
+
+impl BoundTy {
+ pub fn new(index: DebruijnIndex, var: BoundVar) -> Self {
+ BoundTy {
+ index,
+ var,
+ kind: BoundTyKind::Anon,
+ }
+ }
+}
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-> ty::ProjectionPredicate<'tcx>
{
// otherwise the escaping regions would be captured by the binders
- debug_assert!(!self_ty.has_escaping_regions());
+ debug_assert!(!self_ty.has_escaping_bound_vars());
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
RegionKind::ReEmpty => false,
RegionKind::ReErased => false,
RegionKind::ReClosureBound(..) => false,
- RegionKind::ReCanonical(..) => false,
}
}
}
ty::ReErased => {
}
- ty::ReCanonical(..) => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_CANONICAL_VARS;
- }
ty::ReClosureBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
Tuple(..) |
Foreign(..) |
Param(_) |
+ Bound(..) |
Infer(_) |
Error => {
vec![]
ty::Infer(ty::TyVar(_)) => false,
- ty::Infer(ty::BoundTy(_)) |
+ ty::Bound(_) |
ty::Infer(ty::FreshTy(_)) |
ty::Infer(ty::FreshIntTy(_)) |
ty::Infer(ty::FreshFloatTy(_)) =>
use hir::def_id::DefId;
use infer::canonical::Canonical;
-use ty::{self, BoundTyIndex, Lift, List, Ty, TyCtxt};
+use ty::{self, BoundVar, Lift, List, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
span,
root_ty: None,
ty_stack_depth: 0,
- region_binders_passed: 0 };
+ binders_passed: 0 };
(*self).fold_with(&mut folder)
}
}
ty_stack_depth: usize,
// Number of region binders we have passed through while doing the substitution
- region_binders_passed: u32,
+ binders_passed: u32,
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
- self.region_binders_passed += 1;
+ self.binders_passed += 1;
let t = t.super_fold_with(self);
- self.region_binders_passed -= 1;
+ self.binders_passed -= 1;
t
}
}
};
- self.shift_regions_through_binders(ty)
+ self.shift_vars_through_binders(ty)
}
/// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs
- /// when we are substituting a type with escaping regions into a context where we have passed
- /// through region binders. That's quite a mouthful. Let's see an example:
+ /// when we are substituting a type with escaping bound vars into a context where we have
+ /// passed through binders. That's quite a mouthful. Let's see an example:
///
/// ```
/// type Func<A> = fn(A);
/// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
/// first case we do not increase the Debruijn index and in the second case we do. The reason
/// is that only in the second case have we passed through a fn binder.
- fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})",
- ty, self.region_binders_passed, ty.has_escaping_regions());
+ fn shift_vars_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ debug!("shift_vars(ty={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})",
+ ty, self.binders_passed, ty.has_escaping_bound_vars());
- if self.region_binders_passed == 0 || !ty.has_escaping_regions() {
+ if self.binders_passed == 0 || !ty.has_escaping_bound_vars() {
return ty;
}
- let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
- debug!("shift_regions: shifted result = {:?}", result);
+ let result = ty::fold::shift_vars(self.tcx(), &ty, self.binders_passed);
+ debug!("shift_vars: shifted result = {:?}", result);
result
}
fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if self.region_binders_passed == 0 || !region.has_escaping_regions() {
+ if self.binders_passed == 0 || !region.has_escaping_bound_vars() {
return region;
}
- self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
+ ty::fold::shift_region(self.tcx, region, self.binders_passed)
}
}
return false;
}
- self.value.substs.iter().zip(BoundTyIndex::new(0)..).all(|(kind, cvar)| {
+ self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| {
match kind.unpack() {
UnpackedKind::Type(ty) => match ty.sty {
- ty::Infer(ty::BoundTy(ref b)) => cvar == b.var,
+ ty::Bound(b) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(b.index, ty::INNERMOST);
+ cvar == b.var
+ }
_ => false,
},
UnpackedKind::Lifetime(r) => match r {
- ty::ReCanonical(cvar1) => cvar == *cvar1,
+ ty::ReLateBound(index, br) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(*index, ty::INNERMOST);
+ cvar == br.assert_bound_var()
+ }
_ => false,
},
}
erased_self_ty,
predicates);
- assert!(!erased_self_ty.has_escaping_regions());
+ assert!(!erased_self_ty.has_escaping_bound_vars());
traits::elaborate_predicates(self, predicates)
.filter_map(|predicate| {
// construct such an object, but this seems
// correct even if that code changes).
let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
- if t == &erased_self_ty && !r.has_escaping_regions() {
+ if t == &erased_self_ty && !r.has_escaping_bound_vars() {
Some(*r)
} else {
None
// Can refer to a type which may drop.
// FIXME(eddyb) check this against a ParamEnv.
- ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) |
+ ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) |
ty::Opaque(..) | ty::Infer(_) | ty::Error => true,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
match parent_ty.sty {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) |
ty::Str | ty::Infer(_) | ty::Param(_) | ty::Never | ty::Error |
- ty::Foreign(..) => {
+ ty::Bound(..) | ty::Foreign(..) => {
}
ty::Array(ty, len) => {
push_const(stack, len);
let infcx = &mut self.infcx;
let param_env = self.param_env;
self.out.iter()
- .inspect(|pred| assert!(!pred.has_escaping_regions()))
+ .inspect(|pred| assert!(!pred.has_escaping_bound_vars()))
.flat_map(|pred| {
let mut selcx = traits::SelectionContext::new(infcx);
let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
self.out.extend(
trait_ref.substs.types()
- .filter(|ty| !ty.has_escaping_regions())
+ .filter(|ty| !ty.has_escaping_bound_vars())
.map(|ty| traits::Obligation::new(cause.clone(),
param_env,
ty::Predicate::WellFormed(ty))));
let trait_ref = data.trait_ref(self.infcx.tcx);
self.compute_trait_ref(&trait_ref, Elaborate::None);
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
let predicate = trait_ref.to_predicate();
let cause = self.cause(traits::ProjectionWf(data));
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
}
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
- if !subty.has_escaping_regions() {
+ if !subty.has_escaping_bound_vars() {
let cause = self.cause(cause);
let trait_ref = ty::TraitRef {
def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
ty::GeneratorWitness(..) |
ty::Never |
ty::Param(_) |
+ ty::Bound(..) |
ty::Foreign(..) => {
// WfScalar, WfParameter, etc
}
ty::Ref(r, rty, _) => {
// WfReference
- if !r.has_escaping_regions() && !rty.has_escaping_regions() {
+ if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
self.out.push(
traits::Obligation::new(
.map(|pred| traits::Obligation::new(cause.clone(),
self.param_env,
pred))
- .filter(|pred| !pred.has_escaping_regions())
+ .filter(|pred| !pred.has_escaping_bound_vars())
.collect()
}
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
// am looking forward to the future here.
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
let implicit_bounds =
object_region_bounds(self.infcx.tcx, data);
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
use ty::{Bool, Char, Adt};
use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
-use ty::{Param, RawPtr, Ref, Never, Tuple};
+use ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
use ty::{UnnormalizedProjection, Dynamic, Int, Uint, Infer};
use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
ty::ReEarlyBound(ref data) => {
write!(f, "{}", data.name)
}
- ty::ReCanonical(_) => {
- write!(f, "'_")
- }
ty::ReLateBound(_, br) |
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
write!(f, "{:?}", vid)
}
- ty::ReCanonical(c) => {
- write!(f, "'?{}", c.index())
- }
-
ty::RePlaceholder(placeholder) => {
write!(f, "RePlaceholder({:?})", placeholder)
}
ty::TyVar(_) => write!(f, "_"),
ty::IntVar(_) => write!(f, "{}", "{integer}"),
ty::FloatVar(_) => write!(f, "{}", "{float}"),
- ty::BoundTy(_) => write!(f, "_"),
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
ty::TyVar(ref v) => write!(f, "{:?}", v),
ty::IntVar(ref v) => write!(f, "{:?}", v),
ty::FloatVar(ref v) => write!(f, "{:?}", v),
- ty::BoundTy(v) => write!(f, "?{:?}", v.var.index()),
ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
Infer(infer_ty) => write!(f, "{}", infer_ty),
Error => write!(f, "[type error]"),
Param(ref param_ty) => write!(f, "{}", param_ty),
+ Bound(bound_ty) => {
+ match bound_ty.kind {
+ ty::BoundTyKind::Anon => {
+ if bound_ty.index == ty::INNERMOST {
+ write!(f, "?{}", bound_ty.var.index())
+ } else {
+ write!(f, "?{}_{}", bound_ty.index.index(), bound_ty.var.index())
+ }
+ }
+
+ ty::BoundTyKind::Param(p) => write!(f, "{}", p),
+ }
+ }
Adt(def, substs) => cx.parameterized(f, substs, def.did, &[]),
Dynamic(data, r) => {
let r = r.print_to_string(cx);
// These cannot exist in borrowck
RegionKind::ReVar(..) |
- RegionKind::ReCanonical(..) |
RegionKind::RePlaceholder(..) |
RegionKind::ReClosureBound(..) |
RegionKind::ReErased => span_bug!(borrow_span,
ty::ReStatic => self.item_ub,
- ty::ReCanonical(_) |
ty::ReEmpty |
ty::ReClosureBound(..) |
ty::ReLateBound(..) |
use type_of::{LayoutLlvmExt, PointerKind};
use value::Value;
-use rustc_target::abi::{LayoutOf, Size, TyLayout};
+use rustc_target::abi::{LayoutOf, Size, TyLayout, Abi as LayoutAbi};
use rustc::ty::{self, Ty};
use rustc::ty::layout;
FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
let mut layout = cx.layout_of(ty);
// Don't pass the vtable, it's not an argument of the virtual fn.
- // Instead, pass just the (thin pointer) first field of `*dyn Trait`.
+ // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+ // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
if arg_idx == Some(0) {
- // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g.
- // `Box<dyn Trait>` has a few newtype wrappers around the raw
- // pointer, so we'd have to "dig down" to find `*dyn Trait`.
- let pointee = if layout.is_unsized() {
- layout.ty
+ let fat_pointer_ty = if layout.is_unsized() {
+ // unsized `self` is passed as a pointer to `self`
+ // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+ cx.tcx.mk_mut_ptr(layout.ty)
} else {
- layout.ty.builtin_deref(true)
- .unwrap_or_else(|| {
- bug!("FnType::new_vtable: non-pointer self {:?}", layout)
- }).ty
+ match layout.abi {
+ LayoutAbi::ScalarPair(..) => (),
+ _ => bug!("receiver type has unsupported layout: {:?}", layout)
+ }
+
+ // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+ // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+ // elsewhere in the compiler as a method on a `dyn Trait`.
+ // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+ // get a built-in pointer type
+ let mut fat_pointer_layout = layout;
+ 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+ && !fat_pointer_layout.ty.is_region_ptr()
+ {
+ 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+ let field_layout = fat_pointer_layout.field(cx, i);
+
+ if !field_layout.is_zst() {
+ fat_pointer_layout = field_layout;
+ continue 'descend_newtypes
+ }
+ }
+
+ bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
+ }
+
+ fat_pointer_layout.ty
};
- let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
- layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
+
+ // we now have a type like `*mut RcBox<dyn Trait>`
+ // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+ // this is understood as a special case elsewhere in the compiler
+ let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
+ layout = cx.layout_of(unit_pointer_ty);
+ layout.ty = fat_pointer_ty;
}
ArgType::new(layout)
})
},
CodegenComplete,
CodegenItem,
+ CodegenAborted,
}
struct Diagnostic {
let mut needs_lto = Vec::new();
let mut lto_import_only_modules = Vec::new();
let mut started_lto = false;
+ let mut codegen_aborted = false;
// This flag tracks whether all items have gone through codegens
let mut codegen_done = false;
let mut llvm_start_time = None;
// Run the message loop while there's still anything that needs message
- // processing:
+ // processing. Note that as soon as codegen is aborted we simply want to
+ // wait for all existing work to finish, so many of the conditions here
+ // only apply if codegen hasn't been aborted as they represent pending
+ // work to be done.
while !codegen_done ||
- work_items.len() > 0 ||
running > 0 ||
- needs_lto.len() > 0 ||
- lto_import_only_modules.len() > 0 ||
- main_thread_worker_state != MainThreadWorkerState::Idle {
+ (!codegen_aborted && (
+ work_items.len() > 0 ||
+ needs_lto.len() > 0 ||
+ lto_import_only_modules.len() > 0 ||
+ main_thread_worker_state != MainThreadWorkerState::Idle
+ ))
+ {
// While there are still CGUs to be codegened, the coordinator has
// to decide how to utilize the compiler processes implicit Token:
spawn_work(cgcx, item);
}
}
+ } else if codegen_aborted {
+ // don't queue up any more work if codegen was aborted, we're
+ // just waiting for our existing children to finish
} else {
// If we've finished everything related to normal codegen
// then it must be the case that we've got some LTO work to do.
// Spin up what work we can, only doing this while we've got available
// parallelism slots and work left to spawn.
- while work_items.len() > 0 && running < tokens.len() {
+ while !codegen_aborted && work_items.len() > 0 && running < tokens.len() {
let (item, _) = work_items.pop().unwrap();
maybe_start_llvm_timer(cgcx.config(item.module_kind()),
if !cgcx.opts.debugging_opts.no_parallel_llvm {
helper.request_token();
}
+ assert!(!codegen_aborted);
assert_eq!(main_thread_worker_state,
MainThreadWorkerState::Codegenning);
main_thread_worker_state = MainThreadWorkerState::Idle;
Message::CodegenComplete => {
codegen_done = true;
+ assert!(!codegen_aborted);
assert_eq!(main_thread_worker_state,
MainThreadWorkerState::Codegenning);
main_thread_worker_state = MainThreadWorkerState::Idle;
}
+ // If codegen is aborted that means translation was aborted due
+ // to some normal-ish compiler error. In this situation we want
+ // to exit as soon as possible, but we want to make sure all
+ // existing work has finished. Flag codegen as being done, and
+ // then conditions above will ensure no more work is spawned but
+ // we'll keep executing this loop until `running` hits 0.
+ Message::CodegenAborted => {
+ assert!(!codegen_aborted);
+ codegen_done = true;
+ codegen_aborted = true;
+ assert_eq!(main_thread_worker_state,
+ MainThreadWorkerState::Codegenning);
+ }
+
// If a thread exits successfully then we drop a token associated
// with that worker and update our `running` count. We may later
// re-acquire a token to continue running more work. We may also not
drop(self.coordinator_send.send(Box::new(Message::CodegenComplete)));
}
+ /// Consume this context indicating that codegen was entirely aborted, and
+ /// we need to exit as quickly as possible.
+ ///
+ /// This method blocks the current thread until all worker threads have
+ /// finished, and all worker threads should have exited or be real close to
+ /// exiting at this point.
+ pub fn codegen_aborted(self) {
+ // Signal to the coordinator it should spawn no more work and start
+ // shutdown.
+ drop(self.coordinator_send.send(Box::new(Message::CodegenAborted)));
+ drop(self.future.join());
+ }
+
pub fn check_for_errors(&self, sess: &Session) {
self.shared_emitter_main.check(sess, false);
}
}
}
+// impl Drop for OngoingCodegen {
+// fn drop(&mut self) {
+// }
+// }
+
pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt,
module: ModuleCodegen,
cost: u64) {
use rustc_data_structures::sync::Lrc;
use std::any::Any;
+use std::cmp;
use std::ffi::CString;
-use std::sync::Arc;
-use std::time::{Instant, Duration};
use std::i32;
-use std::cmp;
+use std::ops::{Deref, DerefMut};
+use std::sync::Arc;
use std::sync::mpsc;
+use std::time::{Instant, Duration};
use syntax_pos::Span;
use syntax_pos::symbol::InternedString;
use syntax::attr;
// regions must appear in the argument
// listing.
let main_ret_ty = cx.tcx.erase_regions(
- &main_ret_ty.no_late_bound_regions().unwrap(),
+ &main_ret_ty.no_bound_vars().unwrap(),
);
if declare::get_defined_value(cx, "main").is_some() {
metadata,
rx,
codegen_units.len());
+ let ongoing_codegen = AbortCodegenOnDrop(Some(ongoing_codegen));
// Codegen an allocator shim, if necessary.
//
ongoing_codegen.check_for_errors(tcx.sess);
assert_and_save_dep_graph(tcx);
- ongoing_codegen
+ ongoing_codegen.into_inner()
+}
+
+/// A curious wrapper structure whose only purpose is to call `codegen_aborted`
+/// when it's dropped abnormally.
+///
+/// In the process of working on rust-lang/rust#55238 a mysterious segfault was
+/// stumbled upon. The segfault was never reproduced locally, but it was
+/// suspected to be releated to the fact that codegen worker threads were
+/// sticking around by the time the main thread was exiting, causing issues.
+///
+/// This structure is an attempt to fix that issue where the `codegen_aborted`
+/// message will block until all workers have finished. This should ensure that
+/// even if the main codegen thread panics we'll wait for pending work to
+/// complete before returning from the main thread, hopefully avoiding
+/// segfaults.
+///
+/// If you see this comment in the code, then it means that this workaround
+/// worked! We may yet one day track down the mysterious cause of that
+/// segfault...
+struct AbortCodegenOnDrop(Option<OngoingCodegen>);
+
+impl AbortCodegenOnDrop {
+ fn into_inner(mut self) -> OngoingCodegen {
+ self.0.take().unwrap()
+ }
+}
+
+impl Deref for AbortCodegenOnDrop {
+ type Target = OngoingCodegen;
+
+ fn deref(&self) -> &OngoingCodegen {
+ self.0.as_ref().unwrap()
+ }
+}
+
+impl DerefMut for AbortCodegenOnDrop {
+ fn deref_mut(&mut self) -> &mut OngoingCodegen {
+ self.0.as_mut().unwrap()
+ }
+}
+
+impl Drop for AbortCodegenOnDrop {
+ fn drop(&mut self) {
+ if let Some(codegen) = self.0.take() {
+ codegen.codegen_aborted();
+ }
+ }
}
fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
debug!("get_fn(instance={:?})", instance);
assert!(!instance.substs.needs_infer());
- assert!(!instance.substs.has_escaping_regions());
+ assert!(!instance.substs.has_escaping_bound_vars());
assert!(!instance.substs.has_param_types());
let sig = instance.fn_sig(cx.tcx);
ty::Infer(_) |
ty::UnnormalizedProjection(..) |
ty::Projection(..) |
+ ty::Bound(..) |
ty::Opaque(..) |
ty::GeneratorWitness(..) |
ty::Param(_) => {
(&args[..], None)
};
- for (i, arg) in first_args.iter().enumerate() {
+ 'make_args: for (i, arg) in first_args.iter().enumerate() {
let mut op = self.codegen_operand(&bx, arg);
+
if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) {
- if let Pair(data_ptr, meta) = op.val {
- llfn = Some(meth::VirtualIndex::from_index(idx)
- .get_fn(&bx, meta, &fn_ty));
- llargs.push(data_ptr);
- continue;
+ if let Pair(..) = op.val {
+ // In the case of Rc<Self>, we need to explicitly pass a
+ // *mut RcBox<Self> with a Scalar (not ScalarPair) ABI. This is a hack
+ // that is understood elsewhere in the compiler as a method on
+ // `dyn Trait`.
+ // To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until
+ // we get a value of a built-in pointer type
+ 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
+ && !op.layout.ty.is_region_ptr()
+ {
+ 'iter_fields: for i in 0..op.layout.fields.count() {
+ let field = op.extract_field(&bx, i);
+ if !field.layout.is_zst() {
+ // we found the one non-zero-sized field that is allowed
+ // now find *its* non-zero-sized field, or stop if it's a
+ // pointer
+ op = field;
+ continue 'descend_newtypes
+ }
+ }
+
+ span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
+ }
+
+ // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
+ // data pointer and vtable. Look up the method in the vtable, and pass
+ // the data pointer as the first argument
+ match op.val {
+ Pair(data_ptr, meta) => {
+ llfn = Some(meth::VirtualIndex::from_index(idx)
+ .get_fn(&bx, meta, &fn_ty));
+ llargs.push(data_ptr);
+ continue 'make_args
+ }
+ other => bug!("expected a Pair, got {:?}", other)
+ }
} else if let Ref(data_ptr, Some(meta), _) = op.val {
// by-value dynamic dispatch
llfn = Some(meth::VirtualIndex::from_index(idx)
debug!("llvm_type({:#?})", self);
- assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty);
+ assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
// Make sure lifetimes are erased, to avoid generating distinct LLVM
// types for Rust types that only differ in the choice of lifetimes.
smallvec = { version = "0.6.5", features = ["union"] }
syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
+
+[dependencies.jemalloc-sys]
+version = '0.1.8'
+optional = true
+features = ['unprefixed_malloc_on_supported_platforms']
extern crate syntax_ext;
extern crate syntax_pos;
+// Note that the linkage here should be all that we need, on Linux we're not
+// prefixing the symbols here so this should naturally override our default
+// allocator. On OSX it should override via the zone allocator. We shouldn't
+// enable this by default on other platforms, so other platforms aren't handled
+// here yet.
+#[cfg(feature = "jemalloc-sys")]
+extern crate jemalloc_sys;
+
use driver::CompileController;
use pretty::{PpMode, UserIdentifiedItem};
// Theta = [A -> &'a foo]
env.create_simple_region_hierarchy();
- assert!(!env.t_nil().has_escaping_regions());
+ assert!(!env.t_nil().has_escaping_bound_vars());
let t_rptr_free1 = env.t_rptr_free(1);
- assert!(!t_rptr_free1.has_escaping_regions());
+ assert!(!t_rptr_free1.has_escaping_bound_vars());
let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, d1());
- assert!(t_rptr_bound1.has_escaping_regions());
+ assert!(t_rptr_bound1.has_escaping_bound_vars());
let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2());
- assert!(t_rptr_bound2.has_escaping_regions());
+ assert!(t_rptr_bound2.has_escaping_bound_vars());
// t_fn = fn(A)
let t_param = env.t_param(0);
- assert!(!t_param.has_escaping_regions());
+ assert!(!t_param.has_escaping_bound_vars());
let t_fn = env.t_fn(&[t_param], env.t_nil());
- assert!(!t_fn.has_escaping_regions());
+ assert!(!t_fn.has_escaping_bound_vars());
})
}
ty::Param(..) |
ty::Infer(..) |
+ ty::Bound(..) |
ty::Error |
ty::Closure(..) |
ty::Generator(..) |
for (i, dep) in root.crate_deps
.decode(self)
.enumerate() {
- write!(out, "{} {}-{}\n", i + 1, dep.name, dep.hash)?;
+ write!(out, "{} {}{}\n", i + 1, dep.name, dep.extra_filename)?;
}
write!(out, "\n")?;
Ok(())
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReErased
- | ty::ReClosureBound(..)
- | ty::ReCanonical(..) => None,
+ | ty::ReClosureBound(..) => None,
}
}
// when we move to universes, we will, and this assertion
// will start to fail.
let ty::OutlivesPredicate(k1, r2) =
- query_constraint.no_late_bound_regions().unwrap_or_else(|| {
+ query_constraint.no_bound_vars().unwrap_or_else(|| {
bug!(
- "query_constraint {:?} contained bound regions",
+ "query_constraint {:?} contained bound vars",
query_constraint,
);
});
}
fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.has_escaping_regions() || ty.references_error() {
+ if ty.has_escaping_bound_vars() || ty.references_error() {
span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
} else {
ty
.enumerate()
.filter_map(|(idx, constraint)| {
let ty::OutlivesPredicate(k1, r2) =
- constraint.no_late_bound_regions().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound regions", constraint,);
+ constraint.no_bound_vars().unwrap_or_else(|| {
+ bug!("query_constraint {:?} contained bound vars", constraint,);
});
match k1.unpack() {
trait_ty: Ty<'tcx>,
impl_ty: Ty<'tcx>,
output: &mut Vec<MonoItem<'tcx>>) {
- assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_regions() &&
- !impl_ty.needs_subst() && !impl_ty.has_escaping_regions());
+ assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_bound_vars() &&
+ !impl_ty.needs_subst() && !impl_ty.has_escaping_bound_vars());
if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty {
let poly_trait_ref = trait_ty.principal().with_self_ty(tcx, impl_ty);
- assert!(!poly_trait_ref.has_escaping_regions());
+ assert!(!poly_trait_ref.has_escaping_bound_vars());
// Walk all methods of the trait, including those of its supertraits
let methods = tcx.vtable_methods(poly_trait_ref);
// regions must appear in the argument
// listing.
let main_ret_ty = self.tcx.erase_regions(
- &main_ret_ty.no_late_bound_regions().unwrap(),
+ &main_ret_ty.no_bound_vars().unwrap(),
);
let start_instance = Instance::resolve(
self.push_type_params(substs, iter::empty(), output);
}
ty::Error |
+ ty::Bound(..) |
ty::Infer(_) |
ty::UnnormalizedProjection(..) |
ty::Projection(..) |
let param_env = gcx.param_env(def_id);
// Normalize the sig.
- let sig = gcx.fn_sig(def_id).no_late_bound_regions().expect("LBR in ADT constructor signature");
+ let sig = gcx.fn_sig(def_id)
+ .no_bound_vars()
+ .expect("LBR in ADT constructor signature");
let sig = gcx.normalize_erasing_regions(param_env, sig);
let (adt_def, substs) = match sig.output().sty {
{
let did = tcx.require_lang_item(lang_item);
let poly_sig = tcx.fn_sig(did);
- let sig = poly_sig.no_late_bound_regions().unwrap();
+ let sig = poly_sig.no_bound_vars().unwrap();
let lhs_ty = lhs.ty(local_decls, tcx);
let rhs_ty = rhs.ty(local_decls, tcx);
let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
log = "0.4"
rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
serialize = { path = "../libserialize" }
-
-[features]
-jemalloc = []
dll_suffix: ".dylib".to_string(),
archive_format: "bsd".to_string(),
pre_link_args: LinkArgs::new(),
- exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: version >= (10, 7),
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
pre_link_args,
has_elf_tls: false,
eliminate_frame_pointer: false,
- // The following line is a workaround for jemalloc 4.5 being broken on
- // ios. jemalloc 5.0 is supposed to fix this.
- // see https://github.com/rust-lang/rust/issues/45262
- exe_allocation_crate: None,
.. super::apple_base::opts()
})
}
let mut base = super::android_base::opts();
// https://developer.android.com/ndk/guides/abis.html#armeabi
base.features = "+strict-align,+v5te".to_string();
- base.max_atomic_width = Some(64);
+ base.max_atomic_width = Some(32);
Ok(Target {
llvm_target: "arm-linux-androideabi".to_string(),
// dynamic linking.
tls_model: "local-exec".to_string(),
relro_level: RelroLevel::Full,
- exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
}
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
- exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
}
position_independent_executables: true,
eliminate_frame_pointer: false, // FIXME 43575
relro_level: RelroLevel::Full,
- exe_allocation_crate: super::maybe_jemalloc(),
abi_return_struct_as_int: true,
.. Default::default()
}
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
- exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: true,
.. Default::default()
}
}
}
-fn maybe_jemalloc() -> Option<String> {
- if cfg!(feature = "jemalloc") {
- Some("alloc_jemalloc".to_string())
- } else {
- None
- }
-}
-
/// Either a target triple string or a path to a JSON file.
#[derive(PartialEq, Clone, Debug, Hash, RustcEncodable, RustcDecodable)]
pub enum TargetTriple {
has_rpath: true,
target_family: Some("unix".to_string()),
is_like_solaris: true,
- exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
ty::GeneratorWitness(..) |
ty::UnnormalizedProjection(..) |
ty::Infer(..) |
+ ty::Bound(..) |
ty::Error => {
bug!("unexpected type {:?}", ty)
}
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
- ty::Infer(..) | ty::Error => {
+ ty::Bound(..) | ty::Infer(..) | ty::Error => {
// By the time this code runs, all type variables ought to
// be fully resolved.
Err(NoSolution)
// From the full set of obligations, just filter down to the
// region relationships.
implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
- assert!(!obligation.has_escaping_regions());
+ assert!(!obligation.has_escaping_bound_vars());
match obligation.predicate {
ty::Predicate::Trait(..) |
ty::Predicate::Subtype(..) |
vec![]
}
- ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() {
+ ty::Predicate::RegionOutlives(ref data) => match data.no_bound_vars() {
None => vec![],
Some(ty::OutlivesPredicate(r_a, r_b)) => {
vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
}
},
- ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() {
+ ty::Predicate::TypeOutlives(ref data) => match data.no_bound_vars() {
None => vec![],
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
ty::GeneratorWitness(..) |
ty::UnnormalizedProjection(..) |
ty::Infer(..) |
+ ty::Bound(..) |
ty::Error => {
bug!("unexpected type {:?}", ty);
}
// most importantly, that the supertraits don't contain Self,
// to avoid ICEs.
let object_safety_violations =
- tcx.astconv_object_safety_violations(principal.def_id());
+ tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
if !object_safety_violations.is_empty() {
tcx.report_object_safety_error(
span, principal.def_id(), object_safety_violations)
self.region_bounds.iter().map(|&(region_bound, span)| {
// account for the binder being introduced below; no need to shift `param_ty`
// because, at present at least, it can only refer to early-bound regions
- let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1));
+ let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
(ty::Binder::dummy(outlives).to_predicate(), span)
}).chain(
}
// Replace constructor type with constructed type for tuple struct patterns.
let pat_ty = pat_ty.fn_sig(tcx).output();
- let pat_ty = pat_ty.no_late_bound_regions().expect("expected fn type");
+ let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
self.demand_eqtype(pat.span, expected, pat_ty);
ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)),
ty::Param(ref p) => Some(PointerKind::OfParam(p)),
// Insufficient type information.
- ty::Infer(_) => None,
+ ty::Bound(..) | ty::Infer(_) => None,
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
ty::Float(_) | ty::Array(..) | ty::GeneratorWitness(..) |
// Create a `PolyFnSig`. Note the oddity that late bound
// regions appearing free in `expected_sig` are now bound up
// in this binder we are creating.
- assert!(!expected_sig.sig.has_regions_bound_above(ty::INNERMOST));
+ assert!(!expected_sig.sig.has_vars_bound_above(ty::INNERMOST));
let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig(
expected_sig.sig.inputs().iter().cloned(),
expected_sig.sig.output(),
let mut structural_to_nomimal = FxHashMap::default();
let sig = tcx.fn_sig(def_id);
- let sig = sig.no_late_bound_regions().unwrap();
+ let sig = sig.no_bound_vars().unwrap();
if intr.inputs.len() != sig.inputs().len() {
span_err!(tcx.sess, it.span, E0444,
"platform-specific intrinsic has invalid number of \
value
}
};
- assert!(!bounds.has_escaping_regions());
+ assert!(!bounds.has_escaping_bound_vars());
let cause = traits::ObligationCause::misc(span, self.body_id);
obligations.extend(traits::predicates_for_generics(cause.clone(),
fn_sig,
substs);
- assert!(!substs.has_escaping_regions());
+ assert!(!substs.has_escaping_bound_vars());
// It is possible for type parameters or early-bound lifetimes
// to appear in the signature of `self`. The substitutions we
fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
debug!("register_predicate({:?})", obligation);
- if obligation.has_escaping_regions() {
- span_bug!(obligation.cause.span, "escaping regions in predicate {:?}",
+ if obligation.has_escaping_bound_vars() {
+ span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}",
obligation);
}
self.fulfillment_cx
}
fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.has_escaping_regions() {
+ if ty.has_escaping_bound_vars() {
ty // FIXME: normalization and escaping regions
} else {
self.normalize_associated_types_in(span, &ty)
cause: traits::ObligationCause<'tcx>,
predicates: &ty::InstantiatedPredicates<'tcx>)
{
- assert!(!predicates.has_escaping_regions());
+ assert!(!predicates.has_escaping_bound_vars());
debug!("add_obligations_for_parameters(predicates={:?})",
predicates);
}
},
);
- assert!(!substs.has_escaping_regions());
- assert!(!ty.has_escaping_regions());
+ assert!(!substs.has_escaping_bound_vars());
+ assert!(!ty.has_escaping_bound_vars());
// Write the "user substs" down first thing for later.
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
Checker { tcx, trait_def_id }
.check(tcx.lang_items().drop_trait(), visit_implementation_of_drop)
.check(tcx.lang_items().copy_trait(), visit_implementation_of_copy)
- .check(tcx.lang_items().coerce_unsized_trait(),
- visit_implementation_of_coerce_unsized);
+ .check(tcx.lang_items().coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
+ .check(tcx.lang_items().dispatch_from_dyn_trait(),
+ visit_implementation_of_dispatch_from_dyn);
}
struct Checker<'a, 'tcx: 'a> {
let span = tcx.hir.span(impl_node_id);
let param_env = tcx.param_env(impl_did);
- assert!(!self_type.has_escaping_regions());
+ assert!(!self_type.has_escaping_bound_vars());
debug!("visit_implementation_of_copy: self_type={:?} (free)",
self_type);
}
}
+fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ impl_did: DefId,
+) {
+ debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}",
+ impl_did);
+ if impl_did.is_local() {
+ let dispatch_from_dyn_trait = tcx.lang_items().dispatch_from_dyn_trait().unwrap();
+
+ let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap();
+ let span = tcx.hir.span(impl_node_id);
+
+ let source = tcx.type_of(impl_did);
+ assert!(!source.has_escaping_bound_vars());
+ let target = {
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
+
+ trait_ref.substs.type_at(1)
+ };
+
+ debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}",
+ source,
+ target);
+
+ let param_env = tcx.param_env(impl_did);
+
+ let create_err = |msg: &str| {
+ struct_span_err!(tcx.sess, span, E0378, "{}", msg)
+ };
+
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = ObligationCause::misc(span, impl_node_id);
+
+ use ty::TyKind::*;
+ match (&source.sty, &target.sty) {
+ (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
+ if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok()
+ && mutbl_a == *mutbl_b => (),
+ (&RawPtr(tm_a), &RawPtr(tm_b))
+ if tm_a.mutbl == tm_b.mutbl => (),
+ (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
+ if def_a.is_struct() && def_b.is_struct() =>
+ {
+ if def_a != def_b {
+ let source_path = tcx.item_path_str(def_a.did);
+ let target_path = tcx.item_path_str(def_b.did);
+
+ create_err(
+ &format!(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with the same \
+ definition; expected `{}`, found `{}`",
+ source_path, target_path,
+ )
+ ).emit();
+
+ return
+ }
+
+ if def_a.repr.c() || def_a.repr.packed() {
+ create_err(
+ "structs implementing `DispatchFromDyn` may not have \
+ `#[repr(packed)]` or `#[repr(C)]`"
+ ).emit();
+ }
+
+ let fields = &def_a.non_enum_variant().fields;
+
+ let coerced_fields = fields.iter().filter_map(|field| {
+ if tcx.type_of(field.did).is_phantom_data() {
+ // ignore PhantomData fields
+ return None
+ }
+
+ let ty_a = field.ty(tcx, substs_a);
+ let ty_b = field.ty(tcx, substs_b);
+ if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
+ if ok.obligations.is_empty() {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for structs containing the field being coerced, \
+ `PhantomData` fields, and nothing else"
+ ).note(
+ &format!(
+ "extra field `{}` of type `{}` is not allowed",
+ field.ident, ty_a,
+ )
+ ).emit();
+
+ return None;
+ }
+ }
+
+ Some(field)
+ }).collect::<Vec<_>>();
+
+ if coerced_fields.is_empty() {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with a single field \
+ being coerced, none found"
+ ).emit();
+ } else if coerced_fields.len() > 1 {
+ create_err(
+ "implementing the `DispatchFromDyn` trait requires multiple coercions",
+ ).note(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with a single field \
+ being coerced"
+ ).note(
+ &format!(
+ "currently, {} fields need coercions: {}",
+ coerced_fields.len(),
+ coerced_fields.iter().map(|field| {
+ format!("`{}` (`{}` to `{}`)",
+ field.ident,
+ field.ty(tcx, substs_a),
+ field.ty(tcx, substs_b),
+ )
+ }).collect::<Vec<_>>()
+ .join(", ")
+ )
+ ).emit();
+ } else {
+ let mut fulfill_cx = TraitEngine::new(infcx.tcx);
+
+ for field in coerced_fields {
+
+ let predicate = tcx.predicate_for_trait_def(
+ param_env,
+ cause.clone(),
+ dispatch_from_dyn_trait,
+ 0,
+ field.ty(tcx, substs_a),
+ &[field.ty(tcx, substs_b).into()]
+ );
+
+ fulfill_cx.register_predicate_obligation(&infcx, predicate);
+ }
+
+ // Check that all transitive obligations are satisfied.
+ if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ infcx.report_fulfillment_errors(&errors, None, false);
+ }
+
+ // Finally, resolve all regions.
+ let region_scope_tree = region::ScopeTree::default();
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ infcx.resolve_regions_and_report_errors(
+ impl_did,
+ ®ion_scope_tree,
+ &outlives_env,
+ SuppressRegionErrors::default(),
+ );
+ }
+ }
+ _ => {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures"
+ ).emit();
+ }
+ }
+ })
+ }
+}
+
pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>,
impl_did: DefId)
-> CoerceUnsizedInfo {
let span = gcx.hir.span(impl_node_id);
let param_env = gcx.param_env(impl_did);
- assert!(!source.has_escaping_regions());
+ assert!(!source.has_escaping_bound_vars());
let err_info = CoerceUnsizedInfo { custom_kind: None };
E0377,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with the same \
- definition; expected {}, found {}",
+ definition; expected `{}`, found `{}`",
source_path,
target_path);
return err_info;
diff_fields.len(),
diff_fields.iter()
.map(|&(i, a, b)| {
- format!("{} ({} to {})", fields[i].ident, a, b)
+ format!("`{}` (`{}` to `{}`)", fields[i].ident, a, b)
})
.collect::<Vec<_>>()
.join(", ")));
item_def_id: DefId,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
- if let Some(trait_ref) = poly_trait_ref.no_late_bound_regions() {
+ if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
self.tcx().mk_projection(item_def_id, trait_ref.substs)
} else {
// no late-bound regions, we can just ignore the binder
struct.
"##,
+E0378: r##"
+The `DispatchFromDyn` trait currently can only be implemented for
+builtin pointer types and structs that are newtype wrappers around them
+— that is, the struct must have only one field (except for`PhantomData`),
+and that field must itself implement `DispatchFromDyn`.
+
+Examples:
+
+```
+#![feature(dispatch_from_dyn, unsize)]
+use std::{
+ marker::Unsize,
+ ops::DispatchFromDyn,
+};
+
+struct Ptr<T: ?Sized>(*const T);
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T>
+where
+ T: Unsize<U>,
+{}
+```
+
+```
+#![feature(dispatch_from_dyn)]
+use std::{
+ ops::DispatchFromDyn,
+ marker::PhantomData,
+};
+
+struct Wrapper<T> {
+ ptr: T,
+ _phantom: PhantomData<()>,
+}
+
+impl<T, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T>
+where
+ T: DispatchFromDyn<U>,
+{}
+```
+
+Example of illegal `DispatchFromDyn` implementation
+(illegal because of extra field)
+
+```compile-fail,E0378
+#![feature(dispatch_from_dyn)]
+use std::ops::DispatchFromDyn;
+
+struct WrapperExtraField<T> {
+ ptr: T,
+ extra_stuff: i32,
+}
+
+impl<T, U> DispatchFromDyn<WrapperExtraField<U>> for WrapperExtraField<T>
+where
+ T: DispatchFromDyn<U>,
+{}
+```
+"##,
+
E0390: r##"
You tried to implement methods for a primitive type. Erroneous code example:
RegionKind::ReEmpty
| RegionKind::ReErased
| RegionKind::ReClosureBound(..)
- | RegionKind::ReCanonical(..)
| RegionKind::ReScope(..)
| RegionKind::ReVar(..)
| RegionKind::RePlaceholder(..)
ty::UnnormalizedProjection(..) |
ty::GeneratorWitness(..) |
+ ty::Bound(..) |
ty::Infer(..) => {
bug!("unexpected type encountered in \
variance inference: {}",
// way early-bound regions do, so we skip them here.
}
- ty::ReCanonical(_) |
ty::ReFree(..) |
ty::ReClosureBound(..) |
ty::ReScope(..) |
_ => return None,
})
}
+
+ pub fn is_associated(&self) -> bool {
+ match *self {
+ ItemEnum::TypedefItem(_, _) |
+ ItemEnum::AssociatedTypeItem(_, _) => true,
+ _ => false,
+ }
+ }
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
ty::RePlaceholder(..) |
ty::ReEmpty |
ty::ReClosureBound(_) |
- ty::ReCanonical(_) |
ty::ReErased => None
}
}
ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
+ ty::Bound(..) => panic!("Bound"),
ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
if let Some(ref name) = item.name {
info!("Documenting {}", name);
}
- document_stability(w, cx, item)?;
- document_full(w, item, cx, "")?;
+ document_stability(w, cx, item, false)?;
+ document_full(w, item, cx, "", false)?;
Ok(())
}
cx: &Context,
md_text: &str,
links: Vec<(String, String)>,
- prefix: &str)
+ prefix: &str,
+ is_hidden: bool)
-> fmt::Result {
let mut ids = cx.id_map.borrow_mut();
- write!(w, "<div class='docblock'>{}{}</div>",
- prefix, Markdown(md_text, &links, RefCell::new(&mut ids), cx.codes))
+ write!(w, "<div class='docblock{}'>{}{}</div>",
+ if is_hidden { " hidden" } else { "" },
+ prefix,
+ Markdown(md_text, &links, RefCell::new(&mut ids),
+ cx.codes))
}
fn document_short(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, link: AssocItemLink,
- prefix: &str) -> fmt::Result {
+ prefix: &str, is_hidden: bool) -> fmt::Result {
if let Some(s) = item.doc_value() {
let markdown = if s.contains('\n') {
format!("{} [Read more]({})",
} else {
plain_summary_line(Some(s))
};
- render_markdown(w, cx, &markdown, item.links(), prefix)?;
+ render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?;
} else if !prefix.is_empty() {
- write!(w, "<div class='docblock'>{}</div>", prefix)?;
+ write!(w, "<div class='docblock{}'>{}</div>",
+ if is_hidden { " hidden" } else { "" },
+ prefix)?;
}
Ok(())
}
fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
- cx: &Context, prefix: &str) -> fmt::Result {
+ cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result {
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
debug!("Doc block: =====\n{}\n=====", s);
- render_markdown(w, cx, &*s, item.links(), prefix)?;
+ render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?;
} else if !prefix.is_empty() {
- write!(w, "<div class='docblock'>{}</div>", prefix)?;
+ write!(w, "<div class='docblock{}'>{}</div>",
+ if is_hidden { " hidden" } else { "" },
+ prefix)?;
}
Ok(())
}
-fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
+fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
+ is_hidden: bool) -> fmt::Result {
let stabilities = short_stability(item, cx, true);
if !stabilities.is_empty() {
- write!(w, "<div class='stability'>")?;
+ write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?;
for stability in stabilities {
write!(w, "{}", stability)?;
}
RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
};
+ let (is_hidden, extra_class) = if trait_.is_none() ||
+ item.doc_value().is_some() ||
+ item.inner.is_associated() {
+ (false, "")
+ } else {
+ (true, " hidden")
+ };
match item.inner {
clean::MethodItem(clean::Method { ref decl, .. }) |
- clean::TyMethodItem(clean::TyMethod{ ref decl, .. }) => {
+ clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => {
// Only render when the method is not static or we allow static methods
if render_method_item {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "{}", spotlight_decl(decl)?)?;
write!(w, "<span id='{}' class='invisible'>", ns_id)?;
write!(w, "<table class='table-display'><tbody><tr><td><code>")?;
clean::TypedefItem(ref tydef, _) => {
let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
clean::AssociatedConstItem(ref ty, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
let src = if let Some(l) = (Item { cx, item }).src_href() {
clean::AssociatedTypeItem(ref bounds, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
// We need the stability of the item from the trait
// because impls can't have a stability.
- document_stability(w, cx, it)?;
+ document_stability(w, cx, it, is_hidden)?;
if item.doc_value().is_some() {
- document_full(w, item, cx, "")?;
+ document_full(w, item, cx, "", is_hidden)?;
} else if show_def_docs {
// In case the item isn't documented,
// provide short documentation from the trait.
- document_short(w, cx, it, link, "")?;
+ document_short(w, cx, it, link, "", is_hidden)?;
}
}
} else {
- document_stability(w, cx, item)?;
+ document_stability(w, cx, item, is_hidden)?;
if show_def_docs {
- document_full(w, item, cx, "")?;
+ document_full(w, item, cx, "", is_hidden)?;
}
}
} else {
- document_stability(w, cx, item)?;
+ document_stability(w, cx, item, is_hidden)?;
if show_def_docs {
- document_short(w, cx, item, link, "")?;
+ document_short(w, cx, item, link, "", is_hidden)?;
}
}
}
onEach(document.getElementsByClassName('method'), func);
onEach(document.getElementsByClassName('associatedconstant'), func);
onEach(document.getElementsByClassName('impl'), func);
+ onEach(document.getElementsByClassName('impl-items'), function(e) {
+ onEach(e.getElementsByClassName('associatedconstant'), func);
+ var hiddenElems = e.getElementsByClassName('hidden');
+ var needToggle = false;
+
+ for (var i = 0; i < hiddenElems.length; ++i) {
+ if (hasClass(hiddenElems[i], "content") === false &&
+ hasClass(hiddenElems[i], "docblock") === false) {
+ needToggle = true;
+ break;
+ }
+ }
+ if (needToggle === true) {
+ var newToggle = document.createElement('a');
+ newToggle.href = 'javascript:void(0)';
+ newToggle.className = 'collapse-toggle hidden-default collapsed';
+ newToggle.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) + "</span>" +
+ "] Show hidden undocumented items";
+ newToggle.onclick = function() {
+ if (hasClass(this, "collapsed")) {
+ removeClass(this, "collapsed");
+ onEach(this.parentNode.getElementsByClassName("hidden"), function(x) {
+ if (hasClass(x, "content") === false) {
+ removeClass(x, "hidden");
+ addClass(x, "x");
+ }
+ }, true);
+ this.innerHTML = "[<span class='inner'>" + labelForToggleButton(false) +
+ "</span>] Hide undocumented items"
+ } else {
+ addClass(this, "collapsed");
+ onEach(this.parentNode.getElementsByClassName("x"), function(x) {
+ if (hasClass(x, "content") === false) {
+ addClass(x, "hidden");
+ removeClass(x, "x");
+ }
+ }, true);
+ this.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) +
+ "</span>] Show hidden undocumented items";
+ }
+ };
+ e.insertBefore(newToggle, e.firstChild);
+ }
+ });
function createToggle(otherMessage, fontSize, extraClass, show) {
var span = document.createElement('span');
margin-bottom: 15px;
}
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
- margin-left: 20px;
-}
-.content .impl-items .docblock, .content .impl-items .stability {
- margin-bottom: .6em;
-}
-
-.content .impl-items > .stability {
- margin-left: 40px;
-}
-
.content .docblock > .impl-items {
margin-left: 20px;
margin-top: -34px;
top: -9px;
left: -13px;
}
-.methods > .stability {
+
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+ margin-left: 20px;
+}
+
+.content .impl-items .docblock, .content .impl-items .stability {
+ margin-bottom: .6em;
+}
+
+.content .impl-items > .stability {
+ margin-left: 40px;
+}
+
+.methods > .stability, .content .impl-items > .stability {
margin-top: -8px;
}
text-align: center;
}
+.collapse-toggle.hidden-default {
+ position: relative;
+ margin-left: 20px;
+}
+
.ghost {
display: none;
}
var savedHref = [];
-function onEach(arr, func) {
+function onEach(arr, func, reversed) {
if (arr && arr.length > 0 && func) {
- for (var i = 0; i < arr.length; i++) {
- if (func(arr[i]) === true) {
- return true;
+ if (reversed !== true) {
+ for (var i = 0; i < arr.length; ++i) {
+ if (func(arr[i]) === true) {
+ return true;
+ }
+ }
+ } else {
+ for (var i = arr.length - 1; i >= 0; --i) {
+ if (func(arr[i]) === true) {
+ return true;
+ }
}
}
}
[dependencies]
alloc = { path = "../liballoc" }
-alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
alloc_system = { path = "../liballoc_system" }
panic_unwind = { path = "../libpanic_unwind", optional = true }
panic_abort = { path = "../libpanic_abort" }
[features]
backtrace = []
-debug-jemalloc = ["alloc_jemalloc/debug"]
-jemalloc = ["alloc_jemalloc"]
-force_alloc_system = []
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
-//! Currently the default global allocator is unspecified.
-//! The compiler may link to a version of [jemalloc] on some platforms,
-//! but this is not guaranteed.
-//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
-//! to use the [`System`] by default.
+//! Currently the default global allocator is unspecified. Libraries, however,
+//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
+//! default.
//!
-//! [jemalloc]: https://github.com/jemalloc/jemalloc
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
#![default_lib_allocator]
-// Always use alloc_system during stage0 since we don't know if the alloc_*
-// crate the stage0 compiler will pick by default is enabled (e.g.
-// if the user has disabled jemalloc in `./configure`).
-// `force_alloc_system` is *only* intended as a workaround for local rebuilds
-// with a rustc without jemalloc.
-// FIXME(#44236) shouldn't need MSVC logic
-#[cfg(all(not(target_env = "msvc"),
- any(all(stage0, not(test)), feature = "force_alloc_system")))]
+#[cfg(stage0)]
#[global_allocator]
static ALLOC: alloc_system::System = alloc_system::System;
rustc_driver = { path = "../librustc_driver" }
[features]
-jemalloc = ["rustc_target/jemalloc"]
+jemalloc = ['rustc_driver/jemalloc-sys']
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
+#![feature(rustc_attrs)]
+
+use std::{
+ ops::{Deref, CoerceUnsized, DispatchFromDyn},
+ marker::Unsize,
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &*self.0
+ }
+}
+
+impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
+
+struct Wrapper<T: ?Sized>(T);
+
+impl<T: ?Sized> Deref for Wrapper<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
+
+
+trait Trait {
+ // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
+ // without unsized_locals), but wrappers arond `Self` currently are not.
+ // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
+ // fn wrapper(self: Wrapper<Self>) -> i32;
+ fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
+ fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
+ fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
+}
+
+impl Trait for i32 {
+ fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 {
+ **self
+ }
+ fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
+ **self
+ }
+ fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
+ ***self
+ }
+}
+
+fn main() {
+ let pw = Ptr(Box::new(Wrapper(5))) as Ptr<Wrapper<dyn Trait>>;
+ assert_eq!(pw.ptr_wrapper(), 5);
+
+ let wp = Wrapper(Ptr(Box::new(6))) as Wrapper<Ptr<dyn Trait>>;
+ assert_eq!(wp.wrapper_ptr(), 6);
+
+ let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
+ assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
+}
--- /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(arbitrary_self_types)]
+#![feature(pin)]
+#![feature(rustc_attrs)]
+
+use std::{
+ rc::Rc,
+ sync::Arc,
+ pin::Pin,
+};
+
+trait Trait {
+ fn by_rc(self: Rc<Self>) -> i64;
+ fn by_arc(self: Arc<Self>) -> i64;
+ fn by_pin_mut(self: Pin<&mut Self>) -> i64;
+ fn by_pin_box(self: Pin<Box<Self>>) -> i64;
+}
+
+impl Trait for i64 {
+ fn by_rc(self: Rc<Self>) -> i64 {
+ *self
+ }
+ fn by_arc(self: Arc<Self>) -> i64 {
+ *self
+ }
+ fn by_pin_mut(self: Pin<&mut Self>) -> i64 {
+ *self
+ }
+ fn by_pin_box(self: Pin<Box<Self>>) -> i64 {
+ *self
+ }
+}
+
+fn main() {
+ let rc = Rc::new(1i64) as Rc<dyn Trait>;
+ assert_eq!(1, rc.by_rc());
+
+ let arc = Arc::new(2i64) as Arc<dyn Trait>;
+ assert_eq!(2, arc.by_arc());
+
+ let mut value = 3i64;
+ let pin_mut = Pin::new(&mut value) as Pin<&mut dyn Trait>;
+ assert_eq!(3, pin_mut.by_pin_mut());
+
+ let pin_box = Into::<Pin<Box<i64>>>::into(Box::new(4i64)) as Pin<Box<dyn Trait>>;
+ assert_eq!(4, pin_box.by_pin_box());
+}
/// Docs for QUX1 in trait.
const QUX1: i8;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
- /// Docs for QUX_DEFAULT0 in trait.
+ // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+ /// Docs for QUX_DEFAULT12 in trait.
const QUX_DEFAULT0: u16 = 1;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait."
/// Docs for QUX1 in impl.
const QUX1: i8 = 5;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
+ // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
const QUX_DEFAULT0: u16 = 6;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
--- /dev/null
+// Copyright (c) 2015 Anders Kaseorg <andersk@mit.edu>
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// “Software”), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+//! This crate exports a macro `enum_from_primitive!` that wraps an
+//! `enum` declaration and automatically adds an implementation of
+//! `num::FromPrimitive` (reexported here), to allow conversion from
+//! primitive integers to the enum. It therefore provides an
+//! alternative to the built-in `#[derive(FromPrimitive)]`, which
+//! requires the unstable `std::num::FromPrimitive` and is disabled in
+//! Rust 1.0.
+//!
+//! # Example
+//!
+//! ```
+//! #[macro_use] extern crate enum_primitive;
+//! extern crate num_traits;
+//! use num_traits::FromPrimitive;
+//!
+//! enum_from_primitive! {
+//! #[derive(Debug, PartialEq)]
+//! enum FooBar {
+//! Foo = 17,
+//! Bar = 42,
+//! Baz,
+//! }
+//! }
+//!
+//! fn main() {
+//! assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
+//! assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
+//! assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
+//! assert_eq!(FooBar::from_i32(91), None);
+//! }
+//! ```
+
+
+pub mod num_traits {
+ pub trait FromPrimitive: Sized {
+ fn from_i64(n: i64) -> Option<Self>;
+ fn from_u64(n: u64) -> Option<Self>;
+ }
+}
+
+pub use std::option::Option;
+pub use num_traits::FromPrimitive;
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+macro_rules! enum_from_primitive_impl_ty {
+ ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => {
+ #[allow(non_upper_case_globals, unused)]
+ fn $meth(n: $ty) -> $crate::Option<Self> {
+ $( if n == $name::$variant as $ty {
+ $crate::Option::Some($name::$variant)
+ } else )* {
+ $crate::Option::None
+ }
+ }
+ };
+}
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl_ty)]
+macro_rules! enum_from_primitive_impl {
+ ($name:ident, $( $variant:ident )*) => {
+ impl $crate::FromPrimitive for $name {
+ enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* }
+ enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* }
+ }
+ };
+}
+
+/// Wrap this macro around an `enum` declaration to get an
+/// automatically generated implementation of `num::FromPrimitive`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl)]
+macro_rules! enum_from_primitive {
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+ };
+}
+
// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
// @has - '//*[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait a_method definition.'
pub struct S3(usize);
/// Docs associated with the S3 trait implementation.
--- /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.
+
+// ensure this code doesn't stack overflow
+// aux-build:enum_primitive.rs
+
+#[macro_use] extern crate enum_primitive;
+
+enum_from_primitive! {
+ pub enum Test {
+ A1,A2,A3,A4,A5,A6,
+ B1,B2,B3,B4,B5,B6,
+ C1,C2,C3,C4,C5,C6,
+ D1,D2,D3,D4,D5,D6,
+ E1,E2,E3,E4,E5,E6,
+ F1,F2,F3,F4,F5,F6,
+ G1,G2,G3,G4,G5,G6,
+ H1,H2,H3,H4,H5,H6,
+ I1,I2,I3,I4,I5,I6,
+ J1,J2,J3,J4,J5,J6,
+ K1,K2,K3,K4,K5,K6,
+ L1,L2,L3,L4,L5,L6,
+ M1,M2,M3,M4,M5,M6,
+ N1,N2,N3,N4,N5,N6,
+ O1,O2,O3,O4,O5,O6,
+ P1,P2,P3,P4,P5,P6,
+ Q1,Q2,Q3,Q4,Q5,Q6,
+ R1,R2,R3,R4,R5,R6,
+ S1,S2,S3,S4,S5,S6,
+ T1,T2,T3,T4,T5,T6,
+ U1,U2,U3,U4,U5,U6,
+ V1,V2,V3,V4,V5,V6,
+ W1,W2,W3,W4,W5,W6,
+ X1,X2,X3,X4,X5,X6,
+ Y1,Y2,Y3,Y4,Y5,Y6,
+ Z1,Z2,Z3,Z4,Z5,Z6,
+ }
+}
+
use std::rc::Rc;
trait Foo {
- fn foo(self: Rc<Self>) -> usize;
+ fn foo(self: &Rc<Self>) -> usize;
}
trait Bar {
- fn foo(self: Rc<Self>) -> usize where Self: Sized;
- fn bar(self: Box<Self>) -> usize;
+ fn foo(self: &Rc<Self>) -> usize where Self: Sized;
+ fn bar(self: Rc<Self>) -> usize;
}
impl Foo for usize {
- fn foo(self: Rc<Self>) -> usize {
- *self
+ fn foo(self: &Rc<Self>) -> usize {
+ **self
}
}
impl Bar for usize {
- fn foo(self: Rc<Self>) -> usize {
- *self
+ fn foo(self: &Rc<Self>) -> usize {
+ **self
}
- fn bar(self: Box<Self>) -> usize {
+ fn bar(self: Rc<Self>) -> usize {
*self
}
}
fn make_foo() {
- let x = Box::new(5usize) as Box<Foo>;
+ let x = Rc::new(5usize) as Rc<Foo>;
//~^ ERROR E0038
//~| ERROR E0038
}
fn make_bar() {
- let x = Box::new(5usize) as Box<Bar>;
+ let x = Rc::new(5usize) as Rc<Bar>;
x.bar();
}
error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/arbitrary-self-types-not-object-safe.rs:40:33
+ --> $DIR/arbitrary-self-types-not-object-safe.rs:40:32
|
-LL | let x = Box::new(5usize) as Box<Foo>;
- | ^^^^^^^^ the trait `Foo` cannot be made into an object
+LL | let x = Rc::new(5usize) as Rc<Foo>;
+ | ^^^^^^^ the trait `Foo` cannot be made into an object
|
- = note: method `foo` has a non-standard `self` type
+ = note: method `foo`'s receiver cannot be dispatched on
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:40:13
|
-LL | let x = Box::new(5usize) as Box<Foo>;
- | ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+LL | let x = Rc::new(5usize) as Rc<Foo>;
+ | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
- = note: method `foo` has a non-standard `self` type
- = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<usize>`
+ = note: method `foo`'s receiver cannot be dispatched on
+ = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// compile-flags: -Wunused
+
+// ensure there are no special warnings about uninhabited types
+// when deriving Debug on an empty enum
+
+#[derive(Debug)]
+enum Void {} //~ WARN never used
+
+#[derive(Debug)]
+enum Foo { //~ WARN never used
+ Bar(u8),
+ Void(Void),
+}
+
+fn main() {}
+
--- /dev/null
+warning: enum is never used: `Void`
+ --> $DIR/derive-uninhabited-enum-38885.rs:18:1
+ |
+LL | enum Void {} //~ WARN never used
+ | ^^^^^^^^^
+ |
+ = note: `-W dead-code` implied by `-W unused`
+
+warning: enum is never used: `Foo`
+ --> $DIR/derive-uninhabited-enum-38885.rs:21:1
+ |
+LL | enum Foo { //~ WARN never used
+ | ^^^^^^^^
+
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
|
= note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
- = note: currently, 2 fields need coercions: b (T to U), c (U to T)
+ = note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`)
error: aborting due to previous error
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unsize, dispatch_from_dyn)]
+
+use std::{
+ ops::DispatchFromDyn,
+ marker::{Unsize, PhantomData},
+};
+
+struct WrapperWithExtraField<T>(T, i32);
+
+impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+where
+ T: DispatchFromDyn<U>,
+{} //~^^^ ERROR [E0378]
+
+
+struct MultiplePointers<T: ?Sized>{
+ ptr1: *const T,
+ ptr2: *const T,
+}
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+where
+ T: Unsize<U>,
+{} //~^^^ ERROR [E0378]
+
+
+struct NothingToCoerce<T: ?Sized> {
+ data: PhantomData<T>,
+}
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
+//~^ ERROR [E0378]
+
+#[repr(C)]
+struct HasReprC<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+where
+ T: Unsize<U>,
+{} //~^^^ ERROR [E0378]
+
+fn main() {}
--- /dev/null
+error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, `PhantomData` fields, and nothing else
+ --> $DIR/invalid_dispatch_from_dyn_impls.rs:20:1
+ |
+LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+LL | | where
+LL | | T: DispatchFromDyn<U>,
+LL | | {} //~^^^ ERROR [E0378]
+ | |__^
+ |
+ = note: extra field `1` of type `i32` is not allowed
+
+error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+ --> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1
+ |
+LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+LL | | where
+LL | | T: Unsize<U>,
+LL | | {} //~^^^ ERROR [E0378]
+ | |__^
+ |
+ = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
+ = note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`)
+
+error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced, none found
+ --> $DIR/invalid_dispatch_from_dyn_impls.rs:41:1
+ |
+LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
+ --> $DIR/invalid_dispatch_from_dyn_impls.rs:47:1
+ |
+LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+LL | | where
+LL | | T: Unsize<U>,
+LL | | {} //~^^^ ERROR [E0378]
+ | |__^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0378`.
| ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
|
= note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
- = note: currently, 2 fields need coercions: _ptr (*const T to *const U), _boo (NotPhantomData<T> to NotPhantomData<U>)
+ = note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData<T>` to `NotPhantomData<U>`)
error: aborting due to previous error
// A, B, C are resolved as inherent items, their traits don't need to be in scope
C::A; //~ ERROR associated constant `A` is private
//~^ ERROR the trait `assoc_const::C` cannot be made into an object
- //~| ERROR the trait bound `dyn assoc_const::C: assoc_const::A` is not satisfied
C::B; // ERROR the trait `assoc_const::C` cannot be made into an object
- //~^ ERROR the trait bound `dyn assoc_const::C: assoc_const::B` is not satisfied
C::C; // OK
}
LL | C::A; //~ ERROR associated constant `A` is private
| ^^^^
-error[E0277]: the trait bound `dyn assoc_const::C: assoc_const::A` is not satisfied
- --> $DIR/trait-item-privacy.rs:111:5
- |
-LL | C::A; //~ ERROR associated constant `A` is private
- | ^^^^ the trait `assoc_const::A` is not implemented for `dyn assoc_const::C`
- |
-note: required by `assoc_const::A::A`
- --> $DIR/trait-item-privacy.rs:35:9
- |
-LL | const A: u8 = 0;
- | ^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `dyn assoc_const::C: assoc_const::B` is not satisfied
- --> $DIR/trait-item-privacy.rs:114:5
- |
-LL | C::B; // ERROR the trait `assoc_const::C` cannot be made into an object
- | ^^^^ the trait `assoc_const::B` is not implemented for `dyn assoc_const::C`
- |
-note: required by `assoc_const::B::B`
- --> $DIR/trait-item-privacy.rs:39:9
- |
-LL | const B: u8 = 0;
- | ^^^^^^^^^^^^^^^^
-
error[E0038]: the trait `assoc_const::C` cannot be made into an object
--> $DIR/trait-item-privacy.rs:111:5
|
= note: the trait cannot contain associated consts like `A`
error[E0223]: ambiguous associated type
- --> $DIR/trait-item-privacy.rs:127:12
+ --> $DIR/trait-item-privacy.rs:125:12
|
LL | let _: S::A; //~ ERROR ambiguous associated type
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
error[E0223]: ambiguous associated type
- --> $DIR/trait-item-privacy.rs:128:12
+ --> $DIR/trait-item-privacy.rs:126:12
|
LL | let _: S::B; //~ ERROR ambiguous associated type
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
error[E0223]: ambiguous associated type
- --> $DIR/trait-item-privacy.rs:129:12
+ --> $DIR/trait-item-privacy.rs:127:12
|
LL | let _: S::C; //~ ERROR ambiguous associated type
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
error: associated type `A` is private
- --> $DIR/trait-item-privacy.rs:131:12
+ --> $DIR/trait-item-privacy.rs:129:12
|
LL | let _: T::A; //~ ERROR associated type `A` is private
| ^^^^
error: associated type `A` is private
- --> $DIR/trait-item-privacy.rs:140:9
+ --> $DIR/trait-item-privacy.rs:138:9
|
LL | A = u8, //~ ERROR associated type `A` is private
| ^^^^^^
-error: aborting due to 17 previous errors
+error: aborting due to 15 previous errors
-Some errors occurred: E0038, E0223, E0277, E0599, E0624.
+Some errors occurred: E0038, E0223, E0599, E0624.
For more information about an error, try `rustc --explain E0038`.
(box 10 as Box<bar>).dup();
//~^ ERROR E0038
//~| ERROR E0038
- //~| ERROR E0277
}
LL | 10.blah::<i32, i32>(); //~ ERROR wrong number of type arguments: expected 1, found 2
| ^^^ unexpected type argument
-error[E0277]: the trait bound `dyn bar: bar` is not satisfied
- --> $DIR/trait-test-2.rs:20:26
- |
-LL | (box 10 as Box<bar>).dup();
- | ^^^ the trait `bar` is not implemented for `dyn bar`
-
error[E0038]: the trait `bar` cannot be made into an object
--> $DIR/trait-test-2.rs:20:16
|
= note: method `blah` has generic type parameters
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn bar>>` for `std::boxed::Box<{integer}>`
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors occurred: E0038, E0107, E0277.
+Some errors occurred: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.
MAINTAINERS = {
'miri': '@oli-obk @RalfJung @eddyb',
'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk',
- 'rls': '@nrc',
+ 'rls': '@nrc @Xanewok',
'rustfmt': '@nrc',
'book': '@carols10cents @steveklabnik',
'nomicon': '@frewsxcv @Gankro',
status[os] = new
if new > old:
changed = True
- message += '🎉 {} on {}: {} → {}.\n' \
- .format(tool, os, old, new)
+ message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
+ .format(tool, os, old, new, MAINTAINERS.get(tool))
elif new < old:
changed = True
message += '💔 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
// This is intentional, this dependency just makes the crate available
// for others later on. Cover cases
- let whitelisted = krate == "alloc_jemalloc";
- let whitelisted = whitelisted || krate.starts_with("panic");
+ let whitelisted = krate.starts_with("panic");
if toml.contains("name = \"std\"") && whitelisted {
continue
}
fn filter_dirs(path: &Path) -> bool {
let skip = [
"src/dlmalloc",
- "src/jemalloc",
"src/llvm",
"src/llvm-emscripten",
"src/libbacktrace",
//! - core may not have platform-specific code
//! - libcompiler_builtins may have platform-specific code
//! - liballoc_system may have platform-specific code
-//! - liballoc_jemalloc may have platform-specific code
//! - libpanic_abort may have platform-specific code
//! - libpanic_unwind may have platform-specific code
//! - libunwind may have platform-specific code
// Paths that may contain platform-specific code
const EXCEPTION_PATHS: &[&str] = &[
// std crates
- "src/liballoc_jemalloc",
"src/liballoc_system",
"src/libcompiler_builtins",
"src/liblibc",