Merge branch 'master' into issue-30961
This commit is contained in:
commit
cbb88faad7
663 changed files with 15343 additions and 8698 deletions
23
src/bootstrap/Cargo.lock
generated
23
src/bootstrap/Cargo.lock
generated
|
|
@ -5,10 +5,10 @@ dependencies = [
|
|||
"build_helper 0.1.0",
|
||||
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)",
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -25,7 +25,7 @@ name = "cmake"
|
|||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -33,12 +33,17 @@ name = "filetime"
|
|||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.26"
|
||||
version = "0.3.31"
|
||||
source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -48,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -57,7 +62,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -70,7 +75,7 @@ name = "num_cpus"
|
|||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -29,6 +29,6 @@ getopts = "0.2"
|
|||
rustc-serialize = "0.3"
|
||||
winapi = "0.2"
|
||||
kernel32-sys = "0.2"
|
||||
gcc = "0.3.17"
|
||||
gcc = { git = "https://github.com/alexcrichton/gcc-rs" }
|
||||
libc = "0.2"
|
||||
md5 = "0.1"
|
||||
|
|
|
|||
|
|
@ -92,8 +92,7 @@ pub fn std_link(build: &Build,
|
|||
}
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
|
||||
if target.contains("musl") &&
|
||||
(target.contains("x86_64") || target.contains("i686")) {
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
copy_third_party_objects(build, target, &libdir);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ pub struct Config {
|
|||
// libstd features
|
||||
pub debug_jemalloc: bool,
|
||||
pub use_jemalloc: bool,
|
||||
pub backtrace: bool, // support for RUST_BACKTRACE
|
||||
|
||||
// misc
|
||||
pub channel: String,
|
||||
|
|
@ -134,6 +135,7 @@ struct Rust {
|
|||
debuginfo: Option<bool>,
|
||||
debug_jemalloc: Option<bool>,
|
||||
use_jemalloc: Option<bool>,
|
||||
backtrace: Option<bool>,
|
||||
default_linker: Option<String>,
|
||||
default_ar: Option<String>,
|
||||
channel: Option<String>,
|
||||
|
|
@ -158,6 +160,7 @@ impl Config {
|
|||
let mut config = Config::default();
|
||||
config.llvm_optimize = true;
|
||||
config.use_jemalloc = true;
|
||||
config.backtrace = true;
|
||||
config.rust_optimize = true;
|
||||
config.rust_optimize_tests = true;
|
||||
config.submodules = true;
|
||||
|
|
@ -230,6 +233,7 @@ impl Config {
|
|||
set(&mut config.rust_rpath, rust.rpath);
|
||||
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
|
||||
set(&mut config.use_jemalloc, rust.use_jemalloc);
|
||||
set(&mut config.backtrace, rust.backtrace);
|
||||
set(&mut config.channel, rust.channel.clone());
|
||||
config.rustc_default_linker = rust.default_linker.clone();
|
||||
config.rustc_default_ar = rust.default_ar.clone();
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@
|
|||
# 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
|
||||
|
||||
# The default linker that will be used by the generated compiler. Note that this
|
||||
# is not the linker used to link said compiler.
|
||||
#default-linker = "cc"
|
||||
|
|
|
|||
|
|
@ -388,6 +388,10 @@ impl Build {
|
|||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass-valgrind");
|
||||
}
|
||||
CheckMirOpt { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"mir-opt", "mir-opt");
|
||||
}
|
||||
CheckCodegen { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen", "codegen");
|
||||
|
|
@ -648,6 +652,9 @@ impl Build {
|
|||
if self.config.use_jemalloc {
|
||||
features.push_str(" jemalloc");
|
||||
}
|
||||
if self.config.backtrace {
|
||||
features.push_str(" backtrace");
|
||||
}
|
||||
return features
|
||||
}
|
||||
|
||||
|
|
@ -848,6 +855,12 @@ impl Build {
|
|||
base.push("-stdlib=libc++".into());
|
||||
base.push("-mmacosx-version-min=10.7".into());
|
||||
}
|
||||
// This is a hack, because newer binutils broke things on some vms/distros
|
||||
// (i.e., linking against unknown relocs disabled by the following flag)
|
||||
// See: https://github.com/rust-lang/rust/issues/34978
|
||||
if target == "x86_64-unknown-linux-musl" {
|
||||
base.push("-Wa,-mrelax-relocations=no".into());
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -133,86 +133,397 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
|
|||
|
||||
/// Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
///
|
||||
/// This uses the CMake build system and an existing LLVM build directory to
|
||||
/// compile the project.
|
||||
/// Note that while compiler-rt has a build system associated with it, we
|
||||
/// specifically don't use it here. The compiler-rt build system, written in
|
||||
/// CMake, is actually *very* difficult to work with in terms of getting it to
|
||||
/// compile on all the relevant platforms we want it to compile on. In the end
|
||||
/// it became so much pain to work with local patches, work around the oddities
|
||||
/// of the build system, etc, that we're just building everything by hand now.
|
||||
///
|
||||
/// In general compiler-rt is just a bunch of intrinsics that are in practice
|
||||
/// *very* stable. We just need to make sure that all the relevant functions and
|
||||
/// such are compiled somewhere and placed in an object file somewhere.
|
||||
/// Eventually, these should all be written in Rust!
|
||||
///
|
||||
/// So below you'll find a listing of every single file in the compiler-rt repo
|
||||
/// that we're compiling. We just reach in and compile with the `gcc` crate
|
||||
/// which should have all the relevant flags and such already configured.
|
||||
///
|
||||
/// The risk here is that if we update compiler-rt we may need to compile some
|
||||
/// new intrinsics, but to be honest we surely don't use all of the intrinsics
|
||||
/// listed below today so the likelihood of us actually needing a new intrinsic
|
||||
/// is quite low. The failure case is also just that someone reports a link
|
||||
/// error (if any) and then we just add it to the list. Overall, that cost is
|
||||
/// far far less than working with compiler-rt's build system over time.
|
||||
pub fn compiler_rt(build: &Build, target: &str) {
|
||||
let dst = build.compiler_rt_out(target);
|
||||
let arch = target.split('-').next().unwrap();
|
||||
let mode = if build.config.rust_optimize {"Release"} else {"Debug"};
|
||||
|
||||
let build_llvm_config = build.llvm_config(&build.config.build);
|
||||
let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt"));
|
||||
cfg.target(target)
|
||||
.host(&build.config.build)
|
||||
.out_dir(&dst)
|
||||
.profile(mode)
|
||||
.define("LLVM_CONFIG_PATH", build_llvm_config)
|
||||
.define("COMPILER_RT_DEFAULT_TARGET_TRIPLE", target)
|
||||
.define("COMPILER_RT_BUILD_SANITIZERS", "OFF")
|
||||
.define("COMPILER_RT_BUILD_EMUTLS", "OFF")
|
||||
// inform about c/c++ compilers, the c++ compiler isn't actually used but
|
||||
// it's needed to get the initial configure to work on all platforms.
|
||||
.define("CMAKE_C_COMPILER", build.cc(target))
|
||||
.define("CMAKE_CXX_COMPILER", build.cc(target));
|
||||
|
||||
let (dir, build_target, libname) = if target.contains("linux") ||
|
||||
target.contains("freebsd") ||
|
||||
target.contains("netbsd") {
|
||||
let os_extra = if target.contains("android") && target.contains("arm") {
|
||||
"-android"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let builtins_arch = match arch {
|
||||
"i586" => "i386",
|
||||
"arm" | "armv7" if target.contains("android") => "armhf",
|
||||
"arm" if target.contains("eabihf") => "armhf",
|
||||
_ => arch,
|
||||
};
|
||||
let target = format!("clang_rt.builtins-{}", builtins_arch);
|
||||
("linux".to_string(),
|
||||
target.clone(),
|
||||
format!("{}{}", target, os_extra))
|
||||
} else if target.contains("apple-darwin") {
|
||||
let builtins_arch = match arch {
|
||||
"i686" => "i386",
|
||||
_ => arch,
|
||||
};
|
||||
let target = format!("clang_rt.builtins_{}_osx", builtins_arch);
|
||||
("builtins".to_string(), target.clone(), target)
|
||||
} else if target.contains("apple-ios") {
|
||||
cfg.define("COMPILER_RT_ENABLE_IOS", "ON");
|
||||
let target = match arch {
|
||||
"armv7s" => "hard_pic_armv7em_macho_embedded".to_string(),
|
||||
"aarch64" => "builtins_arm64_ios".to_string(),
|
||||
_ => format!("hard_pic_{}_macho_embedded", arch),
|
||||
};
|
||||
("builtins".to_string(), target.clone(), target)
|
||||
} else if target.contains("windows-gnu") {
|
||||
let target = format!("clang_rt.builtins-{}", arch);
|
||||
("windows".to_string(), target.clone(), target)
|
||||
} else if target.contains("windows-msvc") {
|
||||
let builtins_arch = match arch {
|
||||
"i586" | "i686" => "i386",
|
||||
_ => arch,
|
||||
};
|
||||
(format!("windows/{}", mode),
|
||||
"lib/builtins/builtins".to_string(),
|
||||
format!("clang_rt.builtins-{}", builtins_arch))
|
||||
} else {
|
||||
panic!("can't get os from target: {}", target)
|
||||
};
|
||||
let output = dst.join("build/lib").join(dir)
|
||||
.join(staticlib(&libname, target));
|
||||
let build_dir = build.compiler_rt_out(target);
|
||||
let output = build_dir.join(staticlib("compiler-rt", target));
|
||||
build.compiler_rt_built.borrow_mut().insert(target.to_string(),
|
||||
output.clone());
|
||||
if fs::metadata(&output).is_ok() {
|
||||
t!(fs::create_dir_all(&build_dir));
|
||||
|
||||
let mut cfg = gcc::Config::new();
|
||||
cfg.cargo_metadata(false)
|
||||
.out_dir(&build_dir)
|
||||
.target(target)
|
||||
.host(&build.config.build)
|
||||
.opt_level(2)
|
||||
.debug(false);
|
||||
|
||||
if target.contains("msvc") {
|
||||
// Don't pull in extra libraries on MSVC
|
||||
cfg.flag("/Zl");
|
||||
|
||||
// Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
|
||||
cfg.define("__func__", Some("__FUNCTION__"));
|
||||
} else {
|
||||
// Turn off various features of gcc and such, mostly copying
|
||||
// compiler-rt's build system already
|
||||
cfg.flag("-fno-builtin");
|
||||
cfg.flag("-fvisibility=hidden");
|
||||
cfg.flag("-fomit-frame-pointer");
|
||||
cfg.flag("-ffreestanding");
|
||||
}
|
||||
|
||||
let mut sources = vec![
|
||||
"absvdi2.c",
|
||||
"absvsi2.c",
|
||||
"adddf3.c",
|
||||
"addsf3.c",
|
||||
"addvdi3.c",
|
||||
"addvsi3.c",
|
||||
"apple_versioning.c",
|
||||
"ashldi3.c",
|
||||
"ashrdi3.c",
|
||||
"clear_cache.c",
|
||||
"clzdi2.c",
|
||||
"clzsi2.c",
|
||||
"cmpdi2.c",
|
||||
"comparedf2.c",
|
||||
"comparesf2.c",
|
||||
"ctzdi2.c",
|
||||
"ctzsi2.c",
|
||||
"divdc3.c",
|
||||
"divdf3.c",
|
||||
"divdi3.c",
|
||||
"divmoddi4.c",
|
||||
"divmodsi4.c",
|
||||
"divsc3.c",
|
||||
"divsf3.c",
|
||||
"divsi3.c",
|
||||
"divxc3.c",
|
||||
"extendsfdf2.c",
|
||||
"extendhfsf2.c",
|
||||
"ffsdi2.c",
|
||||
"fixdfdi.c",
|
||||
"fixdfsi.c",
|
||||
"fixsfdi.c",
|
||||
"fixsfsi.c",
|
||||
"fixunsdfdi.c",
|
||||
"fixunsdfsi.c",
|
||||
"fixunssfdi.c",
|
||||
"fixunssfsi.c",
|
||||
"fixunsxfdi.c",
|
||||
"fixunsxfsi.c",
|
||||
"fixxfdi.c",
|
||||
"floatdidf.c",
|
||||
"floatdisf.c",
|
||||
"floatdixf.c",
|
||||
"floatsidf.c",
|
||||
"floatsisf.c",
|
||||
"floatundidf.c",
|
||||
"floatundisf.c",
|
||||
"floatundixf.c",
|
||||
"floatunsidf.c",
|
||||
"floatunsisf.c",
|
||||
"int_util.c",
|
||||
"lshrdi3.c",
|
||||
"moddi3.c",
|
||||
"modsi3.c",
|
||||
"muldc3.c",
|
||||
"muldf3.c",
|
||||
"muldi3.c",
|
||||
"mulodi4.c",
|
||||
"mulosi4.c",
|
||||
"muloti4.c",
|
||||
"mulsc3.c",
|
||||
"mulsf3.c",
|
||||
"mulvdi3.c",
|
||||
"mulvsi3.c",
|
||||
"mulxc3.c",
|
||||
"negdf2.c",
|
||||
"negdi2.c",
|
||||
"negsf2.c",
|
||||
"negvdi2.c",
|
||||
"negvsi2.c",
|
||||
"paritydi2.c",
|
||||
"paritysi2.c",
|
||||
"popcountdi2.c",
|
||||
"popcountsi2.c",
|
||||
"powidf2.c",
|
||||
"powisf2.c",
|
||||
"powixf2.c",
|
||||
"subdf3.c",
|
||||
"subsf3.c",
|
||||
"subvdi3.c",
|
||||
"subvsi3.c",
|
||||
"truncdfhf2.c",
|
||||
"truncdfsf2.c",
|
||||
"truncsfhf2.c",
|
||||
"ucmpdi2.c",
|
||||
"udivdi3.c",
|
||||
"udivmoddi4.c",
|
||||
"udivmodsi4.c",
|
||||
"udivsi3.c",
|
||||
"umoddi3.c",
|
||||
"umodsi3.c",
|
||||
];
|
||||
|
||||
if !target.contains("ios") {
|
||||
sources.extend(vec![
|
||||
"absvti2.c",
|
||||
"addtf3.c",
|
||||
"addvti3.c",
|
||||
"ashlti3.c",
|
||||
"ashrti3.c",
|
||||
"clzti2.c",
|
||||
"cmpti2.c",
|
||||
"ctzti2.c",
|
||||
"divtf3.c",
|
||||
"divti3.c",
|
||||
"ffsti2.c",
|
||||
"fixdfti.c",
|
||||
"fixsfti.c",
|
||||
"fixunsdfti.c",
|
||||
"fixunssfti.c",
|
||||
"fixunsxfti.c",
|
||||
"fixxfti.c",
|
||||
"floattidf.c",
|
||||
"floattisf.c",
|
||||
"floattixf.c",
|
||||
"floatuntidf.c",
|
||||
"floatuntisf.c",
|
||||
"floatuntixf.c",
|
||||
"lshrti3.c",
|
||||
"modti3.c",
|
||||
"multf3.c",
|
||||
"multi3.c",
|
||||
"mulvti3.c",
|
||||
"negti2.c",
|
||||
"negvti2.c",
|
||||
"parityti2.c",
|
||||
"popcountti2.c",
|
||||
"powitf2.c",
|
||||
"subtf3.c",
|
||||
"subvti3.c",
|
||||
"trampoline_setup.c",
|
||||
"ucmpti2.c",
|
||||
"udivmodti4.c",
|
||||
"udivti3.c",
|
||||
"umodti3.c",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("apple") {
|
||||
sources.extend(vec![
|
||||
"atomic_flag_clear.c",
|
||||
"atomic_flag_clear_explicit.c",
|
||||
"atomic_flag_test_and_set.c",
|
||||
"atomic_flag_test_and_set_explicit.c",
|
||||
"atomic_signal_fence.c",
|
||||
"atomic_thread_fence.c",
|
||||
]);
|
||||
}
|
||||
|
||||
if !target.contains("windows") {
|
||||
sources.push("emutls.c");
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(vec![
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if !target.contains("freebsd") {
|
||||
sources.push("gcc_personality_v0.c");
|
||||
}
|
||||
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(vec![
|
||||
"x86_64/chkstk.S",
|
||||
"x86_64/chkstk2.S",
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
"x86_64/floatundidf.S",
|
||||
"x86_64/floatundisf.S",
|
||||
"x86_64/floatundixf.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("i386") ||
|
||||
target.contains("i586") ||
|
||||
target.contains("i686") {
|
||||
sources.extend(vec![
|
||||
"i386/ashldi3.S",
|
||||
"i386/ashrdi3.S",
|
||||
"i386/chkstk.S",
|
||||
"i386/chkstk2.S",
|
||||
"i386/divdi3.S",
|
||||
"i386/floatdidf.S",
|
||||
"i386/floatdisf.S",
|
||||
"i386/floatdixf.S",
|
||||
"i386/floatundidf.S",
|
||||
"i386/floatundisf.S",
|
||||
"i386/floatundixf.S",
|
||||
"i386/lshrdi3.S",
|
||||
"i386/moddi3.S",
|
||||
"i386/muldi3.S",
|
||||
"i386/udivdi3.S",
|
||||
"i386/umoddi3.S",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if target.contains("arm") && !target.contains("ios") {
|
||||
sources.extend(vec![
|
||||
"arm/aeabi_cdcmp.S",
|
||||
"arm/aeabi_cdcmpeq_check_nan.c",
|
||||
"arm/aeabi_cfcmp.S",
|
||||
"arm/aeabi_cfcmpeq_check_nan.c",
|
||||
"arm/aeabi_dcmp.S",
|
||||
"arm/aeabi_div0.c",
|
||||
"arm/aeabi_drsub.c",
|
||||
"arm/aeabi_fcmp.S",
|
||||
"arm/aeabi_frsub.c",
|
||||
"arm/aeabi_idivmod.S",
|
||||
"arm/aeabi_ldivmod.S",
|
||||
"arm/aeabi_memcmp.S",
|
||||
"arm/aeabi_memcpy.S",
|
||||
"arm/aeabi_memmove.S",
|
||||
"arm/aeabi_memset.S",
|
||||
"arm/aeabi_uidivmod.S",
|
||||
"arm/aeabi_uldivmod.S",
|
||||
"arm/bswapdi2.S",
|
||||
"arm/bswapsi2.S",
|
||||
"arm/clzdi2.S",
|
||||
"arm/clzsi2.S",
|
||||
"arm/comparesf2.S",
|
||||
"arm/divmodsi4.S",
|
||||
"arm/divsi3.S",
|
||||
"arm/modsi3.S",
|
||||
"arm/switch16.S",
|
||||
"arm/switch32.S",
|
||||
"arm/switch8.S",
|
||||
"arm/switchu8.S",
|
||||
"arm/sync_synchronize.S",
|
||||
"arm/udivmodsi4.S",
|
||||
"arm/udivsi3.S",
|
||||
"arm/umodsi3.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("armv7") {
|
||||
sources.extend(vec![
|
||||
"arm/sync_fetch_and_add_4.S",
|
||||
"arm/sync_fetch_and_add_8.S",
|
||||
"arm/sync_fetch_and_and_4.S",
|
||||
"arm/sync_fetch_and_and_8.S",
|
||||
"arm/sync_fetch_and_max_4.S",
|
||||
"arm/sync_fetch_and_max_8.S",
|
||||
"arm/sync_fetch_and_min_4.S",
|
||||
"arm/sync_fetch_and_min_8.S",
|
||||
"arm/sync_fetch_and_nand_4.S",
|
||||
"arm/sync_fetch_and_nand_8.S",
|
||||
"arm/sync_fetch_and_or_4.S",
|
||||
"arm/sync_fetch_and_or_8.S",
|
||||
"arm/sync_fetch_and_sub_4.S",
|
||||
"arm/sync_fetch_and_sub_8.S",
|
||||
"arm/sync_fetch_and_umax_4.S",
|
||||
"arm/sync_fetch_and_umax_8.S",
|
||||
"arm/sync_fetch_and_umin_4.S",
|
||||
"arm/sync_fetch_and_umin_8.S",
|
||||
"arm/sync_fetch_and_xor_4.S",
|
||||
"arm/sync_fetch_and_xor_8.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("eabihf") {
|
||||
sources.extend(vec![
|
||||
"arm/adddf3vfp.S",
|
||||
"arm/addsf3vfp.S",
|
||||
"arm/divdf3vfp.S",
|
||||
"arm/divsf3vfp.S",
|
||||
"arm/eqdf2vfp.S",
|
||||
"arm/eqsf2vfp.S",
|
||||
"arm/extendsfdf2vfp.S",
|
||||
"arm/fixdfsivfp.S",
|
||||
"arm/fixsfsivfp.S",
|
||||
"arm/fixunsdfsivfp.S",
|
||||
"arm/fixunssfsivfp.S",
|
||||
"arm/floatsidfvfp.S",
|
||||
"arm/floatsisfvfp.S",
|
||||
"arm/floatunssidfvfp.S",
|
||||
"arm/floatunssisfvfp.S",
|
||||
"arm/gedf2vfp.S",
|
||||
"arm/gesf2vfp.S",
|
||||
"arm/gtdf2vfp.S",
|
||||
"arm/gtsf2vfp.S",
|
||||
"arm/ledf2vfp.S",
|
||||
"arm/lesf2vfp.S",
|
||||
"arm/ltdf2vfp.S",
|
||||
"arm/ltsf2vfp.S",
|
||||
"arm/muldf3vfp.S",
|
||||
"arm/mulsf3vfp.S",
|
||||
"arm/negdf2vfp.S",
|
||||
"arm/negsf2vfp.S",
|
||||
"arm/nedf2vfp.S",
|
||||
"arm/nesf2vfp.S",
|
||||
"arm/restore_vfp_d8_d15_regs.S",
|
||||
"arm/save_vfp_d8_d15_regs.S",
|
||||
"arm/subdf3vfp.S",
|
||||
"arm/subsf3vfp.S",
|
||||
"arm/truncdfsf2vfp.S",
|
||||
"arm/unorddf2vfp.S",
|
||||
"arm/unordsf2vfp.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("aarch64") {
|
||||
sources.extend(vec![
|
||||
"comparetf2.c",
|
||||
"extenddftf2.c",
|
||||
"extendsftf2.c",
|
||||
"fixtfdi.c",
|
||||
"fixtfsi.c",
|
||||
"fixtfti.c",
|
||||
"fixunstfdi.c",
|
||||
"fixunstfsi.c",
|
||||
"fixunstfti.c",
|
||||
"floatditf.c",
|
||||
"floatsitf.c",
|
||||
"floatunditf.c",
|
||||
"floatunsitf.c",
|
||||
"multc3.c",
|
||||
"trunctfdf2.c",
|
||||
"trunctfsf2.c",
|
||||
]);
|
||||
}
|
||||
|
||||
let mut out_of_date = false;
|
||||
for src in sources {
|
||||
let src = build.src.join("src/compiler-rt/lib/builtins").join(src);
|
||||
out_of_date = out_of_date || !up_to_date(&src, &output);
|
||||
cfg.file(src);
|
||||
}
|
||||
if !out_of_date {
|
||||
return
|
||||
}
|
||||
let _ = fs::remove_dir_all(&dst);
|
||||
t!(fs::create_dir_all(&dst));
|
||||
cfg.build_target(&build_target);
|
||||
cfg.build();
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
||||
|
||||
/// Compiles the `rust_test_helpers.c` library which we used in various
|
||||
|
|
|
|||
|
|
@ -31,6 +31,15 @@ use Build;
|
|||
pub fn check(build: &mut Build) {
|
||||
let mut checked = HashSet::new();
|
||||
let path = env::var_os("PATH").unwrap_or(OsString::new());
|
||||
// On Windows, quotes are invalid characters for filename paths, and if
|
||||
// one is present as part of the PATH then that can lead to the system
|
||||
// being unable to identify the files properly. See
|
||||
// https://github.com/rust-lang/rust/issues/34959 for more details.
|
||||
if cfg!(windows) {
|
||||
if path.to_string_lossy().contains("\"") {
|
||||
panic!("PATH contains invalid character '\"'");
|
||||
}
|
||||
}
|
||||
let mut need_cmd = |cmd: &OsStr| {
|
||||
if !checked.insert(cmd.to_owned()) {
|
||||
return
|
||||
|
|
@ -100,7 +109,7 @@ pub fn check(build: &mut Build) {
|
|||
}
|
||||
|
||||
// Make sure musl-root is valid if specified
|
||||
if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
match build.config.musl_root {
|
||||
Some(ref root) => {
|
||||
if fs::metadata(root.join("lib/libc.a")).is_err() {
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ macro_rules! targets {
|
|||
(check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }),
|
||||
(check_incremental, CheckIncremental { compiler: Compiler<'a> }),
|
||||
(check_ui, CheckUi { compiler: Compiler<'a> }),
|
||||
(check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }),
|
||||
(check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }),
|
||||
(check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }),
|
||||
(check_docs, CheckDocs { compiler: Compiler<'a> }),
|
||||
|
|
@ -347,9 +348,7 @@ impl<'a> Step<'a> {
|
|||
vec![self.libstd(compiler),
|
||||
self.target(host).rustc(compiler.stage)]
|
||||
}
|
||||
Source::CompilerRt { _dummy } => {
|
||||
vec![self.llvm(()).target(&build.config.build)]
|
||||
}
|
||||
Source::CompilerRt { _dummy } => Vec::new(),
|
||||
Source::Llvm { _dummy } => Vec::new(),
|
||||
Source::TestHelpers { _dummy } => Vec::new(),
|
||||
Source::DebuggerScripts { stage: _ } => Vec::new(),
|
||||
|
|
@ -452,6 +451,7 @@ impl<'a> Step<'a> {
|
|||
self.check_pretty_rfail_full(compiler),
|
||||
self.check_rpass_valgrind(compiler),
|
||||
self.check_rmake(compiler),
|
||||
self.check_mir_opt(compiler),
|
||||
|
||||
// crates
|
||||
self.check_crate_rustc(compiler),
|
||||
|
|
@ -479,6 +479,7 @@ impl<'a> Step<'a> {
|
|||
Source::CheckTidy { stage } => {
|
||||
vec![self.tool_tidy(stage)]
|
||||
}
|
||||
Source::CheckMirOpt { compiler} |
|
||||
Source::CheckPrettyRPass { compiler } |
|
||||
Source::CheckPrettyRFail { compiler } |
|
||||
Source::CheckRFail { compiler } |
|
||||
|
|
|
|||
|
|
@ -103,7 +103,10 @@ pub fn add_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
|
|||
/// Uses last-modified time checks to verify this.
|
||||
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
|
||||
let threshold = mtime(dst);
|
||||
let meta = t!(fs::metadata(src));
|
||||
let meta = match fs::metadata(src) {
|
||||
Ok(meta) => meta,
|
||||
Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
|
||||
};
|
||||
if meta.is_dir() {
|
||||
dir_up_to_date(src, &threshold)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit ac3d1cda612edccb6f1da53cbf7716e248405f3b
|
||||
Subproject commit 8598065bd965d9713bfafb6c1e766d63a7b17b89
|
||||
|
|
@ -223,6 +223,7 @@ trait system to overload operators. Calling functions is no different. We have
|
|||
three separate traits to overload with:
|
||||
|
||||
```rust
|
||||
# #![feature(unboxed_closures)]
|
||||
# mod foo {
|
||||
pub trait Fn<Args> : FnMut<Args> {
|
||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||
|
|
@ -291,9 +292,9 @@ isn’t interesting. The next part is:
|
|||
# some_closure(1) }
|
||||
```
|
||||
|
||||
Because `Fn` is a trait, we can bound our generic with it. In this case, our
|
||||
closure takes a `i32` as an argument and returns an `i32`, and so the generic
|
||||
bound we use is `Fn(i32) -> i32`.
|
||||
Because `Fn` is a trait, we can use it as a bound for our generic type. In
|
||||
this case, our closure takes a `i32` as an argument and returns an `i32`, and
|
||||
so the generic bound we use is `Fn(i32) -> i32`.
|
||||
|
||||
There’s one other key point here: because we’re bounding a generic with a
|
||||
trait, this will get monomorphized, and therefore, we’ll be doing static
|
||||
|
|
|
|||
|
|
@ -575,16 +575,69 @@ against `libc` and `libm` by default.
|
|||
|
||||
# The "nullable pointer optimization"
|
||||
|
||||
Certain types are defined to not be NULL. This includes references (`&T`,
|
||||
`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`).
|
||||
When interfacing with C, pointers that might be NULL are often used.
|
||||
As a special case, a generic `enum` that contains exactly two variants, one of
|
||||
which contains no data and the other containing a single field, is eligible
|
||||
for the "nullable pointer optimization". When such an enum is instantiated
|
||||
with one of the non-nullable types, it is represented as a single pointer,
|
||||
and the non-data variant is represented as the NULL pointer. So
|
||||
`Option<extern "C" fn(c_int) -> c_int>` is how one represents a nullable
|
||||
function pointer using the C ABI.
|
||||
Certain Rust types are defined to never be `null`. This includes references (`&T`,
|
||||
`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`). When
|
||||
interfacing with C, pointers that might be `null` are often used, which would seem to
|
||||
require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types.
|
||||
However, the language provides a workaround.
|
||||
|
||||
As a special case, an `enum` is eligible for the "nullable pointer optimization" if it contains
|
||||
exactly two variants, one of which contains no data and the other contains a field of one of the
|
||||
non-nullable types listed above. This means no extra space is required for a discriminant; rather,
|
||||
the empty variant is represented by putting a `null` value into the non-nullable field. This is
|
||||
called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible
|
||||
types.
|
||||
|
||||
The most common type that takes advantage of the nullable pointer optimization is `Option<T>`,
|
||||
where `None` corresponds to `null`. So `Option<extern "C" fn(c_int) -> c_int>` is a correct way
|
||||
to represent a nullable function pointer using the C ABI (corresponding to the C type
|
||||
`int (*)(int)`).
|
||||
|
||||
Here is a contrived example. Let's say some C library has a facility for registering a
|
||||
callback, which gets called in certain situations. The callback is passed a function pointer
|
||||
and an integer and it is supposed to run the function with the integer as a parameter. So
|
||||
we have function pointers flying across the FFI boundary in both directions.
|
||||
|
||||
```rust
|
||||
# #![feature(libc)]
|
||||
extern crate libc;
|
||||
use libc::c_int;
|
||||
|
||||
# #[cfg(hidden)]
|
||||
extern "C" {
|
||||
/// Register the callback.
|
||||
fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
|
||||
}
|
||||
# unsafe fn register(_: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>,
|
||||
# c_int) -> c_int>)
|
||||
# {}
|
||||
|
||||
/// This fairly useless function receives a function pointer and an integer
|
||||
/// from C, and returns the result of calling the function with the integer.
|
||||
/// In case no function is provided, it squares the integer by default.
|
||||
extern "C" fn apply(process: Option<extern "C" fn(c_int) -> c_int>, int: c_int) -> c_int {
|
||||
match process {
|
||||
Some(f) => f(int),
|
||||
None => int * int
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
register(Some(apply));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And the code on the C side looks like this:
|
||||
|
||||
```c
|
||||
void register(void (*f)(void (*)(int), int)) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
No `transmute` required!
|
||||
|
||||
# Calling Rust code from C
|
||||
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ numbers. A bare number like above is actually shorthand for `^0.3.0`,
|
|||
meaning "anything compatible with 0.3.0".
|
||||
If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"`
|
||||
(note the two equal signs).
|
||||
And if we wanted to use the latest version we could use `*`.
|
||||
And if we wanted to use the latest version we could use `rand="*"`.
|
||||
We could also use a range of versions.
|
||||
[Cargo’s documentation][cargodoc] contains more details.
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ asm!("xor %eax, %eax"
|
|||
: "eax"
|
||||
);
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Whitespace also doesn't matter:
|
||||
|
|
@ -70,6 +72,8 @@ Whitespace also doesn't matter:
|
|||
# fn main() { unsafe {
|
||||
asm!("xor %eax, %eax" ::: "eax");
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## Operands
|
||||
|
|
@ -129,6 +133,8 @@ stay valid.
|
|||
// Put the value 0x200 in eax
|
||||
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Input and output registers need not be listed since that information
|
||||
|
|
@ -164,6 +170,8 @@ unsafe {
|
|||
}
|
||||
println!("eax is currently {}", result);
|
||||
# }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## More Information
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ For example, `Box` pointers require two lang items, one for allocation
|
|||
and one for deallocation. A freestanding program that uses the `Box`
|
||||
sugar for dynamic allocations via `malloc` and `free`:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
#![feature(lang_items, box_syntax, start, libc)]
|
||||
#![no_std]
|
||||
|
||||
|
|
|
|||
|
|
@ -105,19 +105,19 @@ When you need to keep track of how many times you already looped, you can use th
|
|||
#### On ranges:
|
||||
|
||||
```rust
|
||||
for (i, j) in (5..10).enumerate() {
|
||||
println!("i = {} and j = {}", i, j);
|
||||
for (index, value) in (5..10).enumerate() {
|
||||
println!("index = {} and value = {}", index, value);
|
||||
}
|
||||
```
|
||||
|
||||
Outputs:
|
||||
|
||||
```text
|
||||
i = 0 and j = 5
|
||||
i = 1 and j = 6
|
||||
i = 2 and j = 7
|
||||
i = 3 and j = 8
|
||||
i = 4 and j = 9
|
||||
index = 0 and value = 5
|
||||
index = 1 and value = 6
|
||||
index = 2 and value = 7
|
||||
index = 3 and value = 8
|
||||
index = 4 and value = 9
|
||||
```
|
||||
|
||||
Don't forget to add the parentheses around the range.
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
* `|` (`|…| expr`): closures. See [Closures].
|
||||
* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
|
||||
* `||` (`expr || expr`): logical or.
|
||||
* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)].
|
||||
* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]).
|
||||
|
||||
## Other Syntax
|
||||
|
||||
|
|
@ -231,6 +231,7 @@
|
|||
[Primitive Types (Tuples)]: primitive-types.html#tuples
|
||||
[Raw Pointers]: raw-pointers.html
|
||||
[Reference (Byte String Literals)]: ../reference.html#byte-string-literals
|
||||
[Reference (Integer literals)]: ../reference.html#integer-literals
|
||||
[Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals
|
||||
[Reference (Raw String Literals)]: ../reference.html#raw-string-literals
|
||||
[References and Borrowing]: references-and-borrowing.html
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ The stack is very fast, and is where memory is allocated in Rust by default.
|
|||
But the allocation is local to a function call, and is limited in size. The
|
||||
heap, on the other hand, is slower, and is explicitly allocated by your
|
||||
program. But it’s effectively unlimited in size, and is globally accessible.
|
||||
Note this meaning of heap, which allocates arbitrary-sized blocks of memory in arbitrary
|
||||
order, is quite different from the heap data structure.
|
||||
|
||||
# The Stack
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ dispatch with trait objects by casting:
|
|||
# trait Foo { fn method(&self) -> String; }
|
||||
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
|
||||
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
|
||||
|
||||
fn do_something(x: &Foo) {
|
||||
x.method();
|
||||
}
|
||||
|
|
@ -140,7 +139,6 @@ or by coercing:
|
|||
# trait Foo { fn method(&self) -> String; }
|
||||
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
|
||||
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
|
||||
|
||||
fn do_something(x: &Foo) {
|
||||
x.method();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ struct Vec<T> {
|
|||
}
|
||||
```
|
||||
|
||||
Unlike the previous example it *appears* that everything is exactly as we
|
||||
Unlike the previous example, it *appears* that everything is exactly as we
|
||||
want. Every generic argument to Vec shows up in at least one field.
|
||||
Good to go!
|
||||
|
||||
|
|
@ -84,4 +84,3 @@ standard library made a utility for itself called `Unique<T>` which:
|
|||
* includes a `PhantomData<T>`
|
||||
* auto-derives Send/Sync as if T was contained
|
||||
* marks the pointer as NonZero for the null-pointer optimization
|
||||
|
||||
|
|
|
|||
|
|
@ -1653,14 +1653,43 @@ the Rust ABI and the foreign ABI.
|
|||
A number of [attributes](#ffi-attributes) control the behavior of external blocks.
|
||||
|
||||
By default external blocks assume that the library they are calling uses the
|
||||
standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as
|
||||
shown here:
|
||||
standard C ABI on the specific platform. Other ABIs may be specified using an
|
||||
`abi` string, as shown here:
|
||||
|
||||
```ignore
|
||||
// Interface to the Windows API
|
||||
extern "stdcall" { }
|
||||
```
|
||||
|
||||
There are three ABI strings which are cross-platform, and which all compilers
|
||||
are guaranteed to support:
|
||||
|
||||
* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
|
||||
Rust code.
|
||||
* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default
|
||||
your C compiler supports.
|
||||
* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in
|
||||
which case it's `"stdcall"`, or what you should use to link to the Windows API
|
||||
itself
|
||||
|
||||
There are also some platform-specific ABI strings:
|
||||
|
||||
* `extern "cdecl"` -- The default for x86\_32 C code.
|
||||
* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
|
||||
* `extern "win64"` -- The default for C code on x86\_64 Windows.
|
||||
* `extern "aapcs"` -- The default for ARM.
|
||||
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
|
||||
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
|
||||
* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's
|
||||
`__vectorcall` and clang's `__attribute__((vectorcall))`
|
||||
|
||||
Finally, there are some rustc-specific ABI strings:
|
||||
|
||||
* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics.
|
||||
* `extern "rust-call"` -- The ABI of the Fn::call trait functions.
|
||||
* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for
|
||||
example, `sqrt` -- have this ABI. You should never have to deal with it.
|
||||
|
||||
The `link` attribute allows the name of the library to be specified. When
|
||||
specified the compiler will attempt to link against the native library of the
|
||||
specified name.
|
||||
|
|
@ -3020,7 +3049,8 @@ as
|
|||
== != < > <= >=
|
||||
&&
|
||||
||
|
||||
= ..
|
||||
.. ...
|
||||
=
|
||||
```
|
||||
|
||||
Operators at the same precedence level are evaluated left-to-right. [Unary
|
||||
|
|
|
|||
|
|
@ -23,11 +23,5 @@ RUN apt-get update && apt-get -y install \
|
|||
libedit-dev zlib1g-dev \
|
||||
llvm-3.7-tools cmake
|
||||
|
||||
# When we compile compiler-rt we pass it the llvm-config we just installed on
|
||||
# the system, but unfortunately it doesn't infer correctly where
|
||||
# LLVMConfig.cmake is so we need to coerce it a bit...
|
||||
RUN mkdir -p /usr/lib/llvm-3.7/build/share/llvm
|
||||
RUN ln -s /usr/share/llvm-3.7/cmake /usr/lib/llvm-3.7/build/share/llvm/cmake
|
||||
|
||||
RUN mkdir /build
|
||||
WORKDIR /build
|
||||
|
|
|
|||
154
src/etc/char_private.py
Normal file
154
src/etc/char_private.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2011-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# This script uses the following Unicode tables:
|
||||
# - Categories.txt
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
def to_ranges(iter):
|
||||
current = None
|
||||
for i in iter:
|
||||
if current is None or i != current[1] or i in (0x10000, 0x20000):
|
||||
if current is not None:
|
||||
yield tuple(current)
|
||||
current = [i, i + 1]
|
||||
else:
|
||||
current[1] += 1
|
||||
if current is not None:
|
||||
yield tuple(current)
|
||||
|
||||
def get_escaped(dictionary):
|
||||
for i in range(0x110000):
|
||||
if dictionary.get(i, "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and i != ord(' '):
|
||||
yield i
|
||||
|
||||
def get_file(f):
|
||||
try:
|
||||
return open(os.path.basename(f))
|
||||
except FileNotFoundError:
|
||||
subprocess.run(["curl", "-O", f], check=True)
|
||||
return open(os.path.basename(f))
|
||||
|
||||
def main():
|
||||
file = get_file("http://www.unicode.org/notes/tn36/Categories.txt")
|
||||
|
||||
dictionary = {int(line.split()[0], 16): line.split()[1] for line in file}
|
||||
|
||||
CUTOFF=0x10000
|
||||
singletons0 = []
|
||||
singletons1 = []
|
||||
normal0 = []
|
||||
normal1 = []
|
||||
extra = []
|
||||
|
||||
for a, b in to_ranges(get_escaped(dictionary)):
|
||||
if a > 2 * CUTOFF:
|
||||
extra.append((a, b - a))
|
||||
elif a == b - 1:
|
||||
if a & CUTOFF:
|
||||
singletons1.append(a & ~CUTOFF)
|
||||
else:
|
||||
singletons0.append(a)
|
||||
elif a == b - 2:
|
||||
if a & CUTOFF:
|
||||
singletons1.append(a & ~CUTOFF)
|
||||
singletons1.append((a + 1) & ~CUTOFF)
|
||||
else:
|
||||
singletons0.append(a)
|
||||
singletons0.append(a + 1)
|
||||
else:
|
||||
if a >= 2 * CUTOFF:
|
||||
extra.append((a, b - a))
|
||||
elif a & CUTOFF:
|
||||
normal1.append((a & ~CUTOFF, b - a))
|
||||
else:
|
||||
normal0.append((a, b - a))
|
||||
|
||||
print("""\
|
||||
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// NOTE: The following code was generated by "src/etc/char_private.py",
|
||||
// do not edit directly!
|
||||
|
||||
use slice::SliceExt;
|
||||
|
||||
fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
|
||||
for &s in singletons {
|
||||
if x == s {
|
||||
return false;
|
||||
} else if x < s {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for w in normal.chunks(2) {
|
||||
let start = w[0];
|
||||
let len = w[1];
|
||||
let difference = (x as i32) - (start as i32);
|
||||
if 0 <= difference {
|
||||
if difference < len as i32 {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_printable(x: char) -> bool {
|
||||
let x = x as u32;
|
||||
let lower = x as u16;
|
||||
if x < 0x10000 {
|
||||
check(lower, SINGLETONS0, NORMAL0)
|
||||
} else if x < 0x20000 {
|
||||
check(lower, SINGLETONS1, NORMAL1)
|
||||
} else {\
|
||||
""")
|
||||
for a, b in extra:
|
||||
print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b))
|
||||
print(" return false;")
|
||||
print(" }")
|
||||
print("""\
|
||||
true
|
||||
}
|
||||
}\
|
||||
""")
|
||||
print()
|
||||
print("const SINGLETONS0: &'static [u16] = &[")
|
||||
for s in singletons0:
|
||||
print(" 0x{:x},".format(s))
|
||||
print("];")
|
||||
print("const SINGLETONS1: &'static [u16] = &[")
|
||||
for s in singletons1:
|
||||
print(" 0x{:x},".format(s))
|
||||
print("];")
|
||||
print("const NORMAL0: &'static [u16] = &[")
|
||||
for a, b in normal0:
|
||||
print(" 0x{:x}, 0x{:x},".format(a, b))
|
||||
print("];")
|
||||
print("const NORMAL1: &'static [u16] = &[")
|
||||
for a, b in normal1:
|
||||
print(" 0x{:x}, 0x{:x},".format(a, b))
|
||||
print("];")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -58,6 +58,7 @@ case "$TARG_DIR" in
|
|||
|
||||
cp ${PREFIX}/bin/rustc${BIN_SUF} ${TARG_DIR}/stage0/bin/
|
||||
cp ${PREFIX}/${LIB_DIR}/${RUSTLIBDIR}/${TARG_DIR}/${LIB_DIR}/* ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}arena*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rust*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}std*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
|
|
|
|||
|
|
@ -77,6 +77,13 @@ for lib in out.strip().replace("\n", ' ').split(' '):
|
|||
lib = lib.strip()[2:]
|
||||
elif lib[0] == '-':
|
||||
lib = lib.strip()[1:]
|
||||
# If this actually points at a literal file then we're on MSVC which now
|
||||
# prints full paths, so get just the name of the library and strip off the
|
||||
# trailing ".lib"
|
||||
elif os.path.exists(lib):
|
||||
lib = os.path.basename(lib)[:-4]
|
||||
elif lib[-4:] == '.lib':
|
||||
lib = lib[:-4]
|
||||
f.write("#[link(name = \"" + lib + "\"")
|
||||
if not llvm_shared and 'LLVM' in lib:
|
||||
f.write(", kind = \"static\"")
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
//!
|
||||
//! Sharing some immutable data between threads:
|
||||
//!
|
||||
// Note that we **do not** run these tests here. The windows builders get super
|
||||
// unhappy of a thread outlives the main thread and then exits at the same time
|
||||
// (something deadlocks) so we just avoid this entirely by not running these
|
||||
// tests.
|
||||
//! ```no_run
|
||||
//! use std::sync::Arc;
|
||||
//! use std::thread;
|
||||
|
|
@ -97,7 +101,8 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
|||
/// by putting it inside `Mutex` and then share `Mutex` immutably
|
||||
/// with `Arc<T>` as shown below.
|
||||
///
|
||||
/// ```
|
||||
// See comment at the top of this file for why the test is no_run
|
||||
/// ```no_run
|
||||
/// use std::sync::{Arc, Mutex};
|
||||
/// use std::thread;
|
||||
///
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ libc = { path = "../rustc/libc_shim" }
|
|||
|
||||
[build-dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
gcc = "0.3.17"
|
||||
gcc = "0.3.27"
|
||||
|
||||
[features]
|
||||
debug = []
|
||||
|
|
|
|||
|
|
@ -73,7 +73,16 @@ fn main() {
|
|||
.replace("\\", "/"))
|
||||
.current_dir(&build_dir)
|
||||
.env("CC", compiler.path())
|
||||
.env("EXTRA_CFLAGS", cflags)
|
||||
.env("EXTRA_CFLAGS", cflags.clone())
|
||||
// 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", cflags.clone())
|
||||
.env("AR", &ar)
|
||||
.env("RANLIB", format!("{} s", ar.display()));
|
||||
|
||||
|
|
|
|||
|
|
@ -313,6 +313,10 @@ pub struct RangeMut<'a, K: 'a, V: 'a> {
|
|||
}
|
||||
|
||||
/// A view into a single entry in a map, which may either be vacant or occupied.
|
||||
/// This enum is constructed from the [`entry`] method on [`BTreeMap`].
|
||||
///
|
||||
/// [`BTreeMap`]: struct.BTreeMap.html
|
||||
/// [`entry`]: struct.BTreeMap.html#method.entry
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub enum Entry<'a, K: 'a, V: 'a> {
|
||||
/// A vacant Entry
|
||||
|
|
@ -326,7 +330,23 @@ pub enum Entry<'a, K: 'a, V: 'a> {
|
|||
OccupiedEntry<'a, K, V>),
|
||||
}
|
||||
|
||||
/// A vacant Entry.
|
||||
#[stable(feature= "debug_btree_map", since = "1.12.0")]
|
||||
impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Vacant(ref v) => f.debug_tuple("Entry")
|
||||
.field(v)
|
||||
.finish(),
|
||||
Occupied(ref o) => f.debug_tuple("Entry")
|
||||
.field(o)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A vacant Entry. It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct VacantEntry<'a, K: 'a, V: 'a> {
|
||||
key: K,
|
||||
|
|
@ -337,7 +357,18 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> {
|
|||
_marker: PhantomData<&'a mut (K, V)>,
|
||||
}
|
||||
|
||||
/// An occupied Entry.
|
||||
#[stable(feature= "debug_btree_map", since = "1.12.0")]
|
||||
impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("VacantEntry")
|
||||
.field(self.key())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An occupied Entry. It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
|
||||
handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
|
||||
|
|
@ -348,6 +379,16 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
|
|||
_marker: PhantomData<&'a mut (K, V)>,
|
||||
}
|
||||
|
||||
#[stable(feature= "debug_btree_map", since = "1.12.0")]
|
||||
impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("OccupiedEntry")
|
||||
.field("key", self.key())
|
||||
.field("value", self.get())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// An iterator for merging two sorted sequences into one
|
||||
struct MergeIter<K, V, I: Iterator<Item = (K, V)>> {
|
||||
left: Peekable<I>,
|
||||
|
|
@ -1857,6 +1898,17 @@ impl<K, V> BTreeMap<K, V> {
|
|||
impl<'a, K: Ord, V> Entry<'a, K, V> {
|
||||
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
match self {
|
||||
|
|
@ -1867,6 +1919,19 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
|
|||
|
||||
/// Ensures a value is in the entry by inserting the result of the default function if empty,
|
||||
/// and returns a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, String> = BTreeMap::new();
|
||||
/// let s = "hoho".to_owned();
|
||||
///
|
||||
/// map.entry("poneyland").or_insert_with(|| s);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], "hoho".to_owned());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
match self {
|
||||
|
|
@ -1876,6 +1941,15 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
|
|||
}
|
||||
|
||||
/// Returns a reference to this entry's key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[stable(feature = "map_entry_keys", since = "1.10.0")]
|
||||
pub fn key(&self) -> &K {
|
||||
match *self {
|
||||
|
|
@ -1888,12 +1962,36 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
|
|||
impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
|
||||
/// Gets a reference to the key that would be used when inserting a value
|
||||
/// through the VacantEntry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[stable(feature = "map_entry_keys", since = "1.10.0")]
|
||||
pub fn key(&self) -> &K {
|
||||
&self.key
|
||||
}
|
||||
|
||||
/// Take ownership of the key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_entry_recover_keys)]
|
||||
///
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
///
|
||||
/// if let Entry::Vacant(v) = map.entry("poneyland") {
|
||||
/// v.into_key();
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "map_entry_recover_keys", issue = "34285")]
|
||||
pub fn into_key(self) -> K {
|
||||
self.key
|
||||
|
|
@ -1901,6 +1999,21 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
|
|||
|
||||
/// Sets the value of the entry with the VacantEntry's key,
|
||||
/// and returns a mutable reference to it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
///
|
||||
/// // count the number of occurrences of letters in the vec
|
||||
/// for x in vec!["a","b","a","c","a","b"] {
|
||||
/// *count.entry(x).or_insert(0) += 1;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(count["a"], 3);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn insert(self, value: V) -> &'a mut V {
|
||||
*self.length += 1;
|
||||
|
|
@ -1946,30 +2059,106 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
|
|||
|
||||
impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
|
||||
/// Gets a reference to the key in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[stable(feature = "map_entry_keys", since = "1.10.0")]
|
||||
pub fn key(&self) -> &K {
|
||||
self.handle.reborrow().into_kv().0
|
||||
}
|
||||
|
||||
/// Take ownership of the key and value from the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_entry_recover_keys)]
|
||||
///
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// // We delete the entry from the map.
|
||||
/// o.remove_pair();
|
||||
/// }
|
||||
///
|
||||
/// // If now try to get the value, it will panic:
|
||||
/// // println!("{}", map["poneyland"]);
|
||||
/// ```
|
||||
#[unstable(feature = "map_entry_recover_keys", issue = "34285")]
|
||||
pub fn remove_pair(self) -> (K, V) {
|
||||
self.remove_kv()
|
||||
}
|
||||
|
||||
/// Gets a reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// assert_eq!(o.get(), &12);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get(&self) -> &V {
|
||||
self.handle.reborrow().into_kv().1
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// if let Entry::Occupied(mut o) = map.entry("poneyland") {
|
||||
/// *o.get_mut() += 10;
|
||||
/// }
|
||||
/// assert_eq!(map["poneyland"], 22);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get_mut(&mut self) -> &mut V {
|
||||
self.handle.kv_mut().1
|
||||
}
|
||||
|
||||
/// Converts the entry into a mutable reference to its value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// *o.into_mut() += 10;
|
||||
/// }
|
||||
/// assert_eq!(map["poneyland"], 22);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_mut(self) -> &'a mut V {
|
||||
self.handle.into_kv_mut().1
|
||||
|
|
@ -1977,12 +2166,43 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
|
|||
|
||||
/// Sets the value of the entry with the OccupiedEntry's key,
|
||||
/// and returns the entry's old value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(mut o) = map.entry("poneyland") {
|
||||
/// assert_eq!(o.insert(15), 12);
|
||||
/// }
|
||||
/// assert_eq!(map["poneyland"], 15);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn insert(&mut self, value: V) -> V {
|
||||
mem::replace(self.get_mut(), value)
|
||||
}
|
||||
|
||||
/// Takes the value of the entry out of the map, and returns it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::collections::btree_map::Entry;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// assert_eq!(o.remove(), 12);
|
||||
/// }
|
||||
/// // If we try to get "poneyland"'s value, it'll panic:
|
||||
/// // println!("{}", map["poneyland"]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn remove(self) -> V {
|
||||
self.remove_kv().1
|
||||
|
|
|
|||
|
|
@ -409,8 +409,8 @@
|
|||
//! ## Precision
|
||||
//!
|
||||
//! For non-numeric types, this can be considered a "maximum width". If the resulting string is
|
||||
//! longer than this width, then it is truncated down to this many characters and only those are
|
||||
//! emitted.
|
||||
//! longer than this width, then it is truncated down to this many characters and that truncated
|
||||
//! value is emitted with proper `fill`, `alignment` and `width` if those parameters are set.
|
||||
//!
|
||||
//! For integral types, this is ignored.
|
||||
//!
|
||||
|
|
@ -434,42 +434,37 @@
|
|||
//! in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
|
||||
//! to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
|
||||
//!
|
||||
//! For example, these:
|
||||
//! For example, the following calls all print the same thing `Hello x is 0.01000`:
|
||||
//!
|
||||
//! ```
|
||||
//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)}
|
||||
//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
|
||||
//! println!("Hello {0} is {1:.5}", "x", 0.01);
|
||||
//!
|
||||
//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)}
|
||||
//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
|
||||
//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
|
||||
//!
|
||||
//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)}
|
||||
//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
|
||||
//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
|
||||
//!
|
||||
//! // Hello {next arg (x)} is {second of next two args (0.01) with precision
|
||||
//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
|
||||
//! // specified in first of next two args (5)}
|
||||
//! println!("Hello {} is {:.*}", "x", 5, 0.01);
|
||||
//!
|
||||
//! // Hello {next arg (x)} is {arg 2 (0.01) with precision
|
||||
//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
|
||||
//! // specified in its predecessor (5)}
|
||||
//! println!("Hello {} is {2:.*}", "x", 5, 0.01);
|
||||
//!
|
||||
//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified
|
||||
//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
|
||||
//! // in arg "prec" (5)}
|
||||
//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
|
||||
//! ```
|
||||
//!
|
||||
//! All print the same thing:
|
||||
//!
|
||||
//! ```text
|
||||
//! Hello x is 0.01000
|
||||
//! ```
|
||||
//!
|
||||
//! While these:
|
||||
//!
|
||||
//! ```
|
||||
//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
|
||||
//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
|
||||
//! println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
|
||||
//! ```
|
||||
//!
|
||||
//! print two significantly different things:
|
||||
|
|
@ -477,6 +472,7 @@
|
|||
//! ```text
|
||||
//! Hello, `1234.560` has 3 fractional digits
|
||||
//! Hello, `123` has 3 characters
|
||||
//! Hello, ` 123` has 3 right-aligned characters
|
||||
//! ```
|
||||
//!
|
||||
//! # Escaping
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#![feature(allow_internal_unstable)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![cfg_attr(not(test), feature(char_escape_debug))]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(dropck_parametricity)]
|
||||
#![feature(fmt_internals)]
|
||||
|
|
@ -48,7 +49,6 @@
|
|||
#![feature(specialization)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(step_by)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![feature(unsafe_no_drop_flag)]
|
||||
|
|
|
|||
|
|
@ -172,6 +172,14 @@ impl<T> Default for LinkedList<T> {
|
|||
|
||||
impl<T> LinkedList<T> {
|
||||
/// Creates an empty `LinkedList`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let list: LinkedList<u32> = LinkedList::new();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new() -> Self {
|
||||
|
|
@ -195,19 +203,22 @@ impl<T> LinkedList<T> {
|
|||
/// ```
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut a = LinkedList::new();
|
||||
/// let mut b = LinkedList::new();
|
||||
/// a.push_back(1);
|
||||
/// a.push_back(2);
|
||||
/// b.push_back(3);
|
||||
/// b.push_back(4);
|
||||
/// let mut list1 = LinkedList::new();
|
||||
/// list1.push_back('a');
|
||||
///
|
||||
/// a.append(&mut b);
|
||||
/// let mut list2 = LinkedList::new();
|
||||
/// list2.push_back('b');
|
||||
/// list2.push_back('c');
|
||||
///
|
||||
/// for e in &a {
|
||||
/// println!("{}", e); // prints 1, then 2, then 3, then 4
|
||||
/// }
|
||||
/// println!("{}", b.len()); // prints 0
|
||||
/// list1.append(&mut list2);
|
||||
///
|
||||
/// let mut iter = list1.iter();
|
||||
/// assert_eq!(iter.next(), Some(&'a'));
|
||||
/// assert_eq!(iter.next(), Some(&'b'));
|
||||
/// assert_eq!(iter.next(), Some(&'c'));
|
||||
/// assert!(iter.next().is_none());
|
||||
///
|
||||
/// assert!(list2.is_empty());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
|
|
@ -226,6 +237,24 @@ impl<T> LinkedList<T> {
|
|||
}
|
||||
|
||||
/// Provides a forward iterator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut list: LinkedList<u32> = LinkedList::new();
|
||||
///
|
||||
/// list.push_back(0);
|
||||
/// list.push_back(1);
|
||||
/// list.push_back(2);
|
||||
///
|
||||
/// let mut iter = list.iter();
|
||||
/// assert_eq!(iter.next(), Some(&0));
|
||||
/// assert_eq!(iter.next(), Some(&1));
|
||||
/// assert_eq!(iter.next(), Some(&2));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
|
|
@ -238,6 +267,28 @@ impl<T> LinkedList<T> {
|
|||
}
|
||||
|
||||
/// Provides a forward iterator with mutable references.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut list: LinkedList<u32> = LinkedList::new();
|
||||
///
|
||||
/// list.push_back(0);
|
||||
/// list.push_back(1);
|
||||
/// list.push_back(2);
|
||||
///
|
||||
/// for element in list.iter_mut() {
|
||||
/// *element += 10;
|
||||
/// }
|
||||
///
|
||||
/// let mut iter = list.iter();
|
||||
/// assert_eq!(iter.next(), Some(&10));
|
||||
/// assert_eq!(iter.next(), Some(&11));
|
||||
/// assert_eq!(iter.next(), Some(&12));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
|
|
@ -289,7 +340,6 @@ impl<T> LinkedList<T> {
|
|||
///
|
||||
/// dl.push_back(3);
|
||||
/// assert_eq!(dl.len(), 3);
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -316,7 +366,6 @@ impl<T> LinkedList<T> {
|
|||
/// dl.clear();
|
||||
/// assert_eq!(dl.len(), 0);
|
||||
/// assert_eq!(dl.front(), None);
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -326,6 +375,23 @@ impl<T> LinkedList<T> {
|
|||
|
||||
/// Returns `true` if the `LinkedList` contains an element equal to the
|
||||
/// given value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(linked_list_contains)]
|
||||
///
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut list: LinkedList<u32> = LinkedList::new();
|
||||
///
|
||||
/// list.push_back(0);
|
||||
/// list.push_back(1);
|
||||
/// list.push_back(2);
|
||||
///
|
||||
/// assert_eq!(list.contains(&0), true);
|
||||
/// assert_eq!(list.contains(&10), false);
|
||||
/// ```
|
||||
#[unstable(feature = "linked_list_contains", reason = "recently added",
|
||||
issue = "32630")]
|
||||
pub fn contains(&self, x: &T) -> bool
|
||||
|
|
@ -347,7 +413,6 @@ impl<T> LinkedList<T> {
|
|||
///
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.front(), Some(&1));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -374,7 +439,6 @@ impl<T> LinkedList<T> {
|
|||
/// Some(x) => *x = 5,
|
||||
/// }
|
||||
/// assert_eq!(dl.front(), Some(&5));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -395,7 +459,6 @@ impl<T> LinkedList<T> {
|
|||
///
|
||||
/// dl.push_back(1);
|
||||
/// assert_eq!(dl.back(), Some(&1));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -422,7 +485,6 @@ impl<T> LinkedList<T> {
|
|||
/// Some(x) => *x = 5,
|
||||
/// }
|
||||
/// assert_eq!(dl.back(), Some(&5));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -446,7 +508,6 @@ impl<T> LinkedList<T> {
|
|||
///
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.front().unwrap(), &1);
|
||||
///
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_front(&mut self, elt: T) {
|
||||
|
|
@ -471,9 +532,7 @@ impl<T> LinkedList<T> {
|
|||
/// assert_eq!(d.pop_front(), Some(3));
|
||||
/// assert_eq!(d.pop_front(), Some(1));
|
||||
/// assert_eq!(d.pop_front(), None);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn pop_front(&mut self) -> Option<T> {
|
||||
self.pop_front_node().map(Node::into_element)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,22 @@ pub trait RangeArgument<T> {
|
|||
/// Start index (inclusive)
|
||||
///
|
||||
/// Return start value if present, else `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collections)]
|
||||
/// #![feature(collections_range)]
|
||||
///
|
||||
/// extern crate collections;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// use collections::range::RangeArgument;
|
||||
///
|
||||
/// assert_eq!((..10).start(), None);
|
||||
/// assert_eq!((3..10).start(), Some(&3));
|
||||
/// # }
|
||||
/// ```
|
||||
fn start(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
|
|
@ -30,6 +46,22 @@ pub trait RangeArgument<T> {
|
|||
/// End index (exclusive)
|
||||
///
|
||||
/// Return end value if present, else `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collections)]
|
||||
/// #![feature(collections_range)]
|
||||
///
|
||||
/// extern crate collections;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// use collections::range::RangeArgument;
|
||||
///
|
||||
/// assert_eq!((3..).end(), None);
|
||||
/// assert_eq!((3..10).end(), Some(&10));
|
||||
/// # }
|
||||
/// ```
|
||||
fn end(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -544,14 +544,21 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`,
|
||||
/// `[3,4]`):
|
||||
/// ```
|
||||
/// let slice = ['r', 'u', 's', 't'];
|
||||
/// let mut iter = slice.windows(2);
|
||||
/// assert_eq!(iter.next().unwrap(), &['r', 'u']);
|
||||
/// assert_eq!(iter.next().unwrap(), &['u', 's']);
|
||||
/// assert_eq!(iter.next().unwrap(), &['s', 't']);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// let v = &[1, 2, 3, 4];
|
||||
/// for win in v.windows(2) {
|
||||
/// println!("{:?}", win);
|
||||
/// }
|
||||
/// If the slice is shorter than `size`:
|
||||
///
|
||||
/// ```
|
||||
/// let slice = ['f', 'o', 'o'];
|
||||
/// let mut iter = slice.windows(4);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
|
|
@ -570,15 +577,13 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Print the slice two elements at a time (i.e. `[1,2]`,
|
||||
/// `[3,4]`, `[5]`):
|
||||
///
|
||||
/// ```rust
|
||||
/// let v = &[1, 2, 3, 4, 5];
|
||||
///
|
||||
/// for chunk in v.chunks(2) {
|
||||
/// println!("{:?}", chunk);
|
||||
/// }
|
||||
/// ```
|
||||
/// let slice = ['l', 'o', 'r', 'e', 'm'];
|
||||
/// let mut iter = slice.chunks(2);
|
||||
/// assert_eq!(iter.next().unwrap(), &['l', 'o']);
|
||||
/// assert_eq!(iter.next().unwrap(), &['r', 'e']);
|
||||
/// assert_eq!(iter.next().unwrap(), &['m']);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
|
|
@ -684,15 +689,40 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`,
|
||||
/// `[20]`, `[50]`):
|
||||
/// ```
|
||||
/// let slice = [10, 40, 33, 20];
|
||||
/// let mut iter = slice.split(|num| num % 3 == 0);
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap(), &[10, 40]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[20]);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// If the first element is matched, an empty slice will be the first item
|
||||
/// returned by the iterator. Similarly, if the last element in the slice
|
||||
/// is matched, an empty slice will be the last item returned by the
|
||||
/// iterator:
|
||||
///
|
||||
/// ```
|
||||
/// let v = [10, 40, 30, 20, 60, 50];
|
||||
/// let slice = [10, 40, 33];
|
||||
/// let mut iter = slice.split(|num| num % 3 == 0);
|
||||
///
|
||||
/// for group in v.split(|num| *num % 3 == 0) {
|
||||
/// println!("{:?}", group);
|
||||
/// }
|
||||
/// assert_eq!(iter.next().unwrap(), &[10, 40]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[]);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// If two matched elements are directly adjacent, an empty slice will be
|
||||
/// present between them:
|
||||
///
|
||||
/// ```
|
||||
/// let slice = [10, 6, 33, 20];
|
||||
/// let mut iter = slice.split(|num| num % 3 == 0);
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap(), &[10]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[20]);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1697,6 +1697,14 @@ impl str {
|
|||
return s;
|
||||
}
|
||||
|
||||
/// Escapes each char in `s` with `char::escape_debug`.
|
||||
#[unstable(feature = "str_escape",
|
||||
reason = "return type may change to be an iterator",
|
||||
issue = "27791")]
|
||||
pub fn escape_debug(&self) -> String {
|
||||
self.chars().flat_map(|c| c.escape_debug()).collect()
|
||||
}
|
||||
|
||||
/// Escapes each char in `s` with `char::escape_default`.
|
||||
#[unstable(feature = "str_escape",
|
||||
reason = "return type may change to be an iterator",
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ use core::fmt;
|
|||
use core::hash;
|
||||
use core::iter::FromIterator;
|
||||
use core::mem;
|
||||
use core::ops::{self, Add, Index, IndexMut};
|
||||
use core::ops::{self, Add, AddAssign, Index, IndexMut};
|
||||
use core::ptr;
|
||||
use core::str::pattern::Pattern;
|
||||
use rustc_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER};
|
||||
|
|
@ -701,6 +701,12 @@ impl String {
|
|||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal datastructures.
|
||||
///
|
||||
/// The ownership of `ptr` is effectively transferred to the
|
||||
/// `String` which may then deallocate, reallocate or change the
|
||||
/// contents of memory pointed to by the pointer at will. Ensure
|
||||
/// that nothing else uses the pointer after calling this
|
||||
/// function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -1126,18 +1132,62 @@ impl String {
|
|||
assert!(idx <= len);
|
||||
assert!(self.is_char_boundary(idx));
|
||||
let bits = ch.encode_utf8();
|
||||
let bits = bits.as_slice();
|
||||
let amt = bits.len();
|
||||
self.vec.reserve(amt);
|
||||
|
||||
unsafe {
|
||||
ptr::copy(self.vec.as_ptr().offset(idx as isize),
|
||||
self.vec.as_mut_ptr().offset((idx + amt) as isize),
|
||||
len - idx);
|
||||
ptr::copy(bits.as_ptr(),
|
||||
self.vec.as_mut_ptr().offset(idx as isize),
|
||||
amt);
|
||||
self.vec.set_len(len + amt);
|
||||
self.insert_bytes(idx, bits.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
|
||||
let len = self.len();
|
||||
let amt = bytes.len();
|
||||
self.vec.reserve(amt);
|
||||
|
||||
ptr::copy(self.vec.as_ptr().offset(idx as isize),
|
||||
self.vec.as_mut_ptr().offset((idx + amt) as isize),
|
||||
len - idx);
|
||||
ptr::copy(bytes.as_ptr(),
|
||||
self.vec.as_mut_ptr().offset(idx as isize),
|
||||
amt);
|
||||
self.vec.set_len(len + amt);
|
||||
}
|
||||
|
||||
/// Inserts a string into this `String` at a byte position.
|
||||
///
|
||||
/// This is an `O(n)` operation as it requires copying every element in the
|
||||
/// buffer.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `idx` is larger than the `String`'s length, or if it does not
|
||||
/// lie on a [`char`] boundary.
|
||||
///
|
||||
/// [`char`]: ../../std/primitive.char.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(insert_str)]
|
||||
///
|
||||
/// let mut s = String::from("bar");
|
||||
///
|
||||
/// s.insert_str(0, "foo");
|
||||
///
|
||||
/// assert_eq!("foobar", s);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "insert_str",
|
||||
reason = "recent addition",
|
||||
issue = "0")]
|
||||
pub fn insert_str(&mut self, idx: usize, string: &str) {
|
||||
let len = self.len();
|
||||
assert!(idx <= len);
|
||||
assert!(self.is_char_boundary(idx));
|
||||
|
||||
unsafe {
|
||||
self.insert_bytes(idx, string.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1559,6 +1609,14 @@ impl<'a> Add<&'a str> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "stringaddassign", since = "1.12.0")]
|
||||
impl<'a> AddAssign<&'a str> for String {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, other: &str) {
|
||||
self.push_str(other);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::Range<usize>> for String {
|
||||
type Output = str;
|
||||
|
|
@ -1823,6 +1881,26 @@ impl Into<Vec<u8>> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "stringfromchars", since = "1.12.0")]
|
||||
impl<'a> From<&'a [char]> for String {
|
||||
#[inline]
|
||||
fn from(v: &'a [char]) -> String {
|
||||
let mut s = String::with_capacity(v.len());
|
||||
for c in v {
|
||||
s.push(*c);
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "stringfromchars", since = "1.12.0")]
|
||||
impl From<Vec<char>> for String {
|
||||
#[inline]
|
||||
fn from(v: Vec<char>) -> String {
|
||||
String::from(v.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Write for String {
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ use core::mem;
|
|||
use core::ops::{Index, IndexMut};
|
||||
use core::ops;
|
||||
use core::ptr;
|
||||
use core::ptr::Shared;
|
||||
use core::slice;
|
||||
|
||||
use super::SpecExtend;
|
||||
|
|
@ -342,12 +343,18 @@ impl<T> Vec<T> {
|
|||
///
|
||||
/// * `ptr` needs to have been previously allocated via `String`/`Vec<T>`
|
||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
||||
/// * `length` needs to be the length that less than or equal to `capacity`.
|
||||
/// * `length` needs to be less than or equal to `capacity`.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal datastructures.
|
||||
///
|
||||
/// The ownership of `ptr` is effectively transferred to the
|
||||
/// `Vec<T>` which may then deallocate, reallocate or change the
|
||||
/// contents of memory pointed to by the pointer at will. Ensure
|
||||
/// that nothing else uses the pointer after calling this
|
||||
/// function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -469,6 +476,25 @@ impl<T> Vec<T> {
|
|||
/// Note that this will drop any excess capacity. Calling this and
|
||||
/// converting back to a vector with `into_vec()` is equivalent to calling
|
||||
/// `shrink_to_fit()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1, 2, 3];
|
||||
///
|
||||
/// let slice = v.into_boxed_slice();
|
||||
/// ```
|
||||
///
|
||||
/// Any excess capacity is removed:
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec = Vec::with_capacity(10);
|
||||
/// vec.extend([1, 2, 3].iter().cloned());
|
||||
///
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// let slice = vec.into_boxed_slice();
|
||||
/// assert_eq!(slice.into_vec().capacity(), 3);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_boxed_slice(mut self) -> Box<[T]> {
|
||||
unsafe {
|
||||
|
|
@ -479,18 +505,45 @@ impl<T> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Shorten a vector to be `len` elements long, dropping excess elements.
|
||||
/// Shortens the vector, keeping the first `len` elements and dropping
|
||||
/// the rest.
|
||||
///
|
||||
/// If `len` is greater than the vector's current length, this has no
|
||||
/// effect.
|
||||
///
|
||||
/// The [`drain`] method can emulate `truncate`, but causes the excess
|
||||
/// elements to be returned instead of dropped.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Truncating a five element vector to two elements:
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec = vec![1, 2, 3, 4, 5];
|
||||
/// vec.truncate(2);
|
||||
/// assert_eq!(vec, [1, 2]);
|
||||
/// ```
|
||||
///
|
||||
/// No truncation occurs when `len` is greater than the vector's current
|
||||
/// length:
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec = vec![1, 2, 3];
|
||||
/// vec.truncate(8);
|
||||
/// assert_eq!(vec, [1, 2, 3]);
|
||||
/// ```
|
||||
///
|
||||
/// Truncating when `len == 0` is equivalent to calling the [`clear`]
|
||||
/// method.
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec = vec![1, 2, 3];
|
||||
/// vec.truncate(0);
|
||||
/// assert_eq!(vec, []);
|
||||
/// ```
|
||||
///
|
||||
/// [`clear`]: #method.clear
|
||||
/// [`drain`]: #method.drain
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
unsafe {
|
||||
|
|
@ -508,6 +561,14 @@ impl<T> Vec<T> {
|
|||
/// Extracts a slice containing the entire vector.
|
||||
///
|
||||
/// Equivalent to `&s[..]`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::{self, Write};
|
||||
/// let buffer = vec![1, 2, 3, 5, 8];
|
||||
/// io::sink().write(buffer.as_slice()).unwrap();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "vec_as_slice", since = "1.7.0")]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
|
|
@ -517,6 +578,14 @@ impl<T> Vec<T> {
|
|||
/// Extracts a mutable slice of the entire vector.
|
||||
///
|
||||
/// Equivalent to `&mut s[..]`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::{self, Read};
|
||||
/// let mut buffer = vec![0; 3];
|
||||
/// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "vec_as_slice", since = "1.7.0")]
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
|
|
@ -532,9 +601,38 @@ impl<T> Vec<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut v = vec![1, 2, 3, 4];
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// let mut vec = vec!['r', 'u', 's', 't'];
|
||||
///
|
||||
/// unsafe {
|
||||
/// v.set_len(1);
|
||||
/// ptr::drop_in_place(&mut vec[3]);
|
||||
/// vec.set_len(3);
|
||||
/// }
|
||||
/// assert_eq!(vec, ['r', 'u', 's']);
|
||||
/// ```
|
||||
///
|
||||
/// In this example, there is a memory leak since the memory locations
|
||||
/// owned by the inner vectors were not freed prior to the `set_len` call:
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec = vec![vec![1, 0, 0],
|
||||
/// vec![0, 1, 0],
|
||||
/// vec![0, 0, 1]];
|
||||
/// unsafe {
|
||||
/// vec.set_len(0);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// In this example, the vector gets expanded from zero to four items
|
||||
/// without any memory allocations occurring, resulting in vector
|
||||
/// values of unallocated memory:
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec: Vec<char> = Vec::new();
|
||||
///
|
||||
/// unsafe {
|
||||
/// vec.set_len(4);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -821,8 +919,8 @@ impl<T> Vec<T> {
|
|||
Drain {
|
||||
tail_start: end,
|
||||
tail_len: len - end,
|
||||
iter: range_slice.iter_mut(),
|
||||
vec: self as *mut _,
|
||||
iter: range_slice.iter(),
|
||||
vec: Shared::new(self as *mut _),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1728,8 +1826,8 @@ pub struct Drain<'a, T: 'a> {
|
|||
/// Length of tail
|
||||
tail_len: usize,
|
||||
/// Current remaining range to remove
|
||||
iter: slice::IterMut<'a, T>,
|
||||
vec: *mut Vec<T>,
|
||||
iter: slice::Iter<'a, T>,
|
||||
vec: Shared<Vec<T>>,
|
||||
}
|
||||
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
|
|
@ -1767,7 +1865,7 @@ impl<'a, T> Drop for Drain<'a, T> {
|
|||
|
||||
if self.tail_len > 0 {
|
||||
unsafe {
|
||||
let source_vec = &mut *self.vec;
|
||||
let source_vec = &mut **self.vec;
|
||||
// memmove back untouched tail, update to new length
|
||||
let start = source_vec.len();
|
||||
let tail = self.tail_start;
|
||||
|
|
|
|||
|
|
@ -365,12 +365,28 @@ impl<T> VecDeque<T> {
|
|||
|
||||
impl<T> VecDeque<T> {
|
||||
/// Creates an empty `VecDeque`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let vector: VecDeque<u32> = VecDeque::new();
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new() -> VecDeque<T> {
|
||||
VecDeque::with_capacity(INITIAL_CAPACITY)
|
||||
}
|
||||
|
||||
/// Creates an empty `VecDeque` with space for at least `n` elements.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn with_capacity(n: usize) -> VecDeque<T> {
|
||||
// +1 since the ringbuffer always leaves one space empty
|
||||
|
|
@ -386,6 +402,8 @@ impl<T> VecDeque<T> {
|
|||
|
||||
/// Retrieves an element in the `VecDeque` by index.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -409,6 +427,8 @@ impl<T> VecDeque<T> {
|
|||
|
||||
/// Retrieves an element in the `VecDeque` mutably by index.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -440,6 +460,8 @@ impl<T> VecDeque<T> {
|
|||
///
|
||||
/// Fails if there is no element with either index.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -696,6 +718,25 @@ impl<T> VecDeque<T> {
|
|||
|
||||
/// Returns a pair of slices which contain, in order, the contents of the
|
||||
/// `VecDeque`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut vector: VecDeque<u32> = VecDeque::new();
|
||||
///
|
||||
/// vector.push_back(0);
|
||||
/// vector.push_back(1);
|
||||
/// vector.push_back(2);
|
||||
///
|
||||
/// assert_eq!(vector.as_slices(), (&[0u32, 1, 2] as &[u32], &[] as &[u32]));
|
||||
///
|
||||
/// vector.push_front(10);
|
||||
/// vector.push_front(9);
|
||||
///
|
||||
/// assert_eq!(vector.as_slices(), (&[9u32, 10] as &[u32], &[0u32, 1, 2] as &[u32]));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn as_slices(&self) -> (&[T], &[T]) {
|
||||
|
|
@ -715,6 +756,24 @@ impl<T> VecDeque<T> {
|
|||
|
||||
/// Returns a pair of slices which contain, in order, the contents of the
|
||||
/// `VecDeque`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut vector: VecDeque<u32> = VecDeque::new();
|
||||
///
|
||||
/// vector.push_back(0);
|
||||
/// vector.push_back(1);
|
||||
///
|
||||
/// vector.push_front(10);
|
||||
/// vector.push_front(9);
|
||||
///
|
||||
/// vector.as_mut_slices().0[0] = 42;
|
||||
/// vector.as_mut_slices().1[0] = 24;
|
||||
/// assert_eq!(vector.as_slices(), (&[42u32, 10] as &[u32], &[24u32, 1] as &[u32]));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
|
||||
|
|
@ -789,7 +848,7 @@ impl<T> VecDeque<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
|
||||
///
|
||||
/// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
|
||||
/// assert_eq!(vec![3].into_iter().collect::<VecDeque<_>>(), v.drain(2..).collect());
|
||||
/// assert_eq!(vec![1, 2].into_iter().collect::<VecDeque<_>>(), v);
|
||||
|
|
@ -875,6 +934,22 @@ impl<T> VecDeque<T> {
|
|||
|
||||
/// Returns `true` if the `VecDeque` contains an element equal to the
|
||||
/// given value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(vec_deque_contains)]
|
||||
///
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut vector: VecDeque<u32> = VecDeque::new();
|
||||
///
|
||||
/// vector.push_back(0);
|
||||
/// vector.push_back(1);
|
||||
///
|
||||
/// assert_eq!(vector.contains(&1), true);
|
||||
/// assert_eq!(vector.contains(&10), false);
|
||||
/// ```
|
||||
#[unstable(feature = "vec_deque_contains", reason = "recently added",
|
||||
issue = "32630")]
|
||||
pub fn contains(&self, x: &T) -> bool
|
||||
|
|
@ -1111,6 +1186,8 @@ impl<T> VecDeque<T> {
|
|||
///
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -1145,6 +1222,8 @@ impl<T> VecDeque<T> {
|
|||
///
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -1176,6 +1255,8 @@ impl<T> VecDeque<T> {
|
|||
/// end is closer to the insertion point will be moved to make room,
|
||||
/// and all the affected elements will be moved to new positions.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `index` is greater than `VecDeque`'s length
|
||||
|
|
@ -1403,7 +1484,10 @@ impl<T> VecDeque<T> {
|
|||
/// room, and all the affected elements will be moved to new positions.
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
|
|
@ -1581,6 +1665,8 @@ impl<T> VecDeque<T> {
|
|||
///
|
||||
/// Note that the capacity of `self` does not change.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `at > len`
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::binary_heap::Drain;
|
||||
|
||||
#[test]
|
||||
fn test_iterator() {
|
||||
|
|
@ -292,3 +293,8 @@ fn test_extend_specialization() {
|
|||
|
||||
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -703,16 +703,32 @@ fn test_escape_unicode() {
|
|||
assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_debug() {
|
||||
assert_eq!("abc".escape_debug(), "abc");
|
||||
assert_eq!("a c".escape_debug(), "a c");
|
||||
assert_eq!("éèê".escape_debug(), "éèê");
|
||||
assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t");
|
||||
assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\");
|
||||
assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}");
|
||||
assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}");
|
||||
assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}");
|
||||
assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}");
|
||||
assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_default() {
|
||||
assert_eq!("abc".escape_default(), "abc");
|
||||
assert_eq!("a c".escape_default(), "a c");
|
||||
assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}");
|
||||
assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t");
|
||||
assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\");
|
||||
assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}");
|
||||
assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}");
|
||||
assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}");
|
||||
assert_eq!("ab\u{fb00}".escape_default(), "ab\\u{fb00}");
|
||||
assert_eq!("\u{1d4ea}\r".escape_default(), "\\u{1d4ea}\\r");
|
||||
assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}");
|
||||
assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -192,6 +192,17 @@ fn test_push_str() {
|
|||
assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_assign() {
|
||||
let mut s = String::new();
|
||||
s += "";
|
||||
assert_eq!(s.as_str(), "");
|
||||
s += "abc";
|
||||
assert_eq!(s.as_str(), "abc");
|
||||
s += "ประเทศไทย中华Việt Nam";
|
||||
assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push() {
|
||||
let mut data = String::from("ประเทศไทย中");
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
use std::borrow::Cow;
|
||||
use std::iter::{FromIterator, repeat};
|
||||
use std::mem::size_of;
|
||||
use std::vec::Drain;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
|
|
@ -510,6 +511,11 @@ fn test_cow_from() {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_new(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
|
|
|||
|
|
@ -847,6 +847,20 @@ impl<'b, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<RefMut<'b, U>> for RefM
|
|||
/// The `UnsafeCell<T>` type is the only legal way to obtain aliasable data that is considered
|
||||
/// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior.
|
||||
///
|
||||
/// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or
|
||||
/// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`,
|
||||
/// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way
|
||||
/// to do this. When `UnsafeCell<T>` is immutably aliased, it is still safe to obtain a mutable
|
||||
/// reference to its interior and/or to mutate it. However, it is up to the abstraction designer
|
||||
/// to ensure that no two mutable references obtained this way are active at the same time, and
|
||||
/// that there are no active mutable references or mutations when an immutable reference is obtained
|
||||
/// from the cell. This is often done via runtime checks.
|
||||
///
|
||||
/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell<T>` is
|
||||
/// okay (provided you enforce the invariants some other way); it is still undefined behavior
|
||||
/// to have multiple `&mut UnsafeCell<T>` aliases.
|
||||
///
|
||||
///
|
||||
/// Types like `Cell<T>` and `RefCell<T>` use this type to wrap their internal data.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -916,6 +930,11 @@ impl<T> UnsafeCell<T> {
|
|||
impl<T: ?Sized> UnsafeCell<T> {
|
||||
/// Gets a mutable pointer to the wrapped value.
|
||||
///
|
||||
/// This can be cast to a pointer of any kind.
|
||||
/// Ensure that the access is unique when casting to
|
||||
/// `&mut T`, and ensure that there are no mutations or mutable
|
||||
/// aliases going on when casting to `&T`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
use prelude::v1::*;
|
||||
|
||||
use char_private::is_printable;
|
||||
use mem::transmute;
|
||||
|
||||
// UTF-8 ranges and tags for encoding characters
|
||||
|
|
@ -263,6 +264,8 @@ pub trait CharExt {
|
|||
fn escape_unicode(self) -> EscapeUnicode;
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn escape_default(self) -> EscapeDefault;
|
||||
#[unstable(feature = "char_escape_debug", issue = "35068")]
|
||||
fn escape_debug(self) -> EscapeDebug;
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn len_utf8(self) -> usize;
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
|
|
@ -326,6 +329,19 @@ impl CharExt for char {
|
|||
EscapeDefault { state: init_state }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn escape_debug(self) -> EscapeDebug {
|
||||
let init_state = match self {
|
||||
'\t' => EscapeDefaultState::Backslash('t'),
|
||||
'\r' => EscapeDefaultState::Backslash('r'),
|
||||
'\n' => EscapeDefaultState::Backslash('n'),
|
||||
'\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
|
||||
c if is_printable(c) => EscapeDefaultState::Char(c),
|
||||
c => EscapeDefaultState::Unicode(c.escape_unicode()),
|
||||
};
|
||||
EscapeDebug(EscapeDefault { state: init_state })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn len_utf8(self) -> usize {
|
||||
let code = self as u32;
|
||||
|
|
@ -600,6 +616,27 @@ impl ExactSizeIterator for EscapeDefault {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator that yields the literal escape code of a `char`.
|
||||
///
|
||||
/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its
|
||||
/// documentation for more.
|
||||
///
|
||||
/// [`escape_debug()`]: ../../std/primitive.char.html#method.escape_debug
|
||||
/// [`char`]: ../../std/primitive.char.html
|
||||
#[unstable(feature = "char_escape_debug", issue = "35068")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EscapeDebug(EscapeDefault);
|
||||
|
||||
#[unstable(feature = "char_escape_debug", issue = "35068")]
|
||||
impl Iterator for EscapeDebug {
|
||||
type Item = char;
|
||||
fn next(&mut self) -> Option<char> { self.0.next() }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
|
||||
}
|
||||
|
||||
#[unstable(feature = "char_escape_debug", issue = "35068")]
|
||||
impl ExactSizeIterator for EscapeDebug { }
|
||||
|
||||
/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
|
||||
/// value.
|
||||
///
|
||||
|
|
|
|||
695
src/libcore/char_private.rs
Normal file
695
src/libcore/char_private.rs
Normal file
|
|
@ -0,0 +1,695 @@
|
|||
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// NOTE: The following code was generated by "src/etc/char_private.py",
|
||||
// do not edit directly!
|
||||
|
||||
use slice::SliceExt;
|
||||
|
||||
fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
|
||||
for &s in singletons {
|
||||
if x == s {
|
||||
return false;
|
||||
} else if x < s {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for w in normal.chunks(2) {
|
||||
let start = w[0];
|
||||
let len = w[1];
|
||||
let difference = (x as i32) - (start as i32);
|
||||
if 0 <= difference {
|
||||
if difference < len as i32 {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_printable(x: char) -> bool {
|
||||
let x = x as u32;
|
||||
let lower = x as u16;
|
||||
if x < 0x10000 {
|
||||
check(lower, SINGLETONS0, NORMAL0)
|
||||
} else if x < 0x20000 {
|
||||
check(lower, SINGLETONS1, NORMAL1)
|
||||
} else {
|
||||
if 0x20000 <= x && x < 0x2f800 {
|
||||
return false;
|
||||
}
|
||||
if 0x2fa1e <= x && x < 0xe0100 {
|
||||
return false;
|
||||
}
|
||||
if 0xe01f0 <= x && x < 0x110000 {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
const SINGLETONS0: &'static [u16] = &[
|
||||
0xad,
|
||||
0x378,
|
||||
0x379,
|
||||
0x38b,
|
||||
0x38d,
|
||||
0x3a2,
|
||||
0x557,
|
||||
0x558,
|
||||
0x560,
|
||||
0x588,
|
||||
0x590,
|
||||
0x61c,
|
||||
0x61d,
|
||||
0x6dd,
|
||||
0x70e,
|
||||
0x70f,
|
||||
0x74b,
|
||||
0x74c,
|
||||
0x82e,
|
||||
0x82f,
|
||||
0x83f,
|
||||
0x85c,
|
||||
0x85d,
|
||||
0x8a1,
|
||||
0x8ff,
|
||||
0x978,
|
||||
0x980,
|
||||
0x984,
|
||||
0x98d,
|
||||
0x98e,
|
||||
0x991,
|
||||
0x992,
|
||||
0x9a9,
|
||||
0x9b1,
|
||||
0x9ba,
|
||||
0x9bb,
|
||||
0x9c5,
|
||||
0x9c6,
|
||||
0x9c9,
|
||||
0x9ca,
|
||||
0x9de,
|
||||
0x9e4,
|
||||
0x9e5,
|
||||
0xa04,
|
||||
0xa11,
|
||||
0xa12,
|
||||
0xa29,
|
||||
0xa31,
|
||||
0xa34,
|
||||
0xa37,
|
||||
0xa3a,
|
||||
0xa3b,
|
||||
0xa3d,
|
||||
0xa49,
|
||||
0xa4a,
|
||||
0xa5d,
|
||||
0xa84,
|
||||
0xa8e,
|
||||
0xa92,
|
||||
0xaa9,
|
||||
0xab1,
|
||||
0xab4,
|
||||
0xaba,
|
||||
0xabb,
|
||||
0xac6,
|
||||
0xaca,
|
||||
0xace,
|
||||
0xacf,
|
||||
0xae4,
|
||||
0xae5,
|
||||
0xb04,
|
||||
0xb0d,
|
||||
0xb0e,
|
||||
0xb11,
|
||||
0xb12,
|
||||
0xb29,
|
||||
0xb31,
|
||||
0xb34,
|
||||
0xb3a,
|
||||
0xb3b,
|
||||
0xb45,
|
||||
0xb46,
|
||||
0xb49,
|
||||
0xb4a,
|
||||
0xb5e,
|
||||
0xb64,
|
||||
0xb65,
|
||||
0xb84,
|
||||
0xb91,
|
||||
0xb9b,
|
||||
0xb9d,
|
||||
0xbc9,
|
||||
0xbce,
|
||||
0xbcf,
|
||||
0xc04,
|
||||
0xc0d,
|
||||
0xc11,
|
||||
0xc29,
|
||||
0xc34,
|
||||
0xc45,
|
||||
0xc49,
|
||||
0xc57,
|
||||
0xc64,
|
||||
0xc65,
|
||||
0xc80,
|
||||
0xc81,
|
||||
0xc84,
|
||||
0xc8d,
|
||||
0xc91,
|
||||
0xca9,
|
||||
0xcb4,
|
||||
0xcba,
|
||||
0xcbb,
|
||||
0xcc5,
|
||||
0xcc9,
|
||||
0xcdf,
|
||||
0xce4,
|
||||
0xce5,
|
||||
0xcf0,
|
||||
0xd04,
|
||||
0xd0d,
|
||||
0xd11,
|
||||
0xd3b,
|
||||
0xd3c,
|
||||
0xd45,
|
||||
0xd49,
|
||||
0xd64,
|
||||
0xd65,
|
||||
0xd80,
|
||||
0xd81,
|
||||
0xd84,
|
||||
0xdb2,
|
||||
0xdbc,
|
||||
0xdbe,
|
||||
0xdbf,
|
||||
0xdd5,
|
||||
0xdd7,
|
||||
0xe83,
|
||||
0xe85,
|
||||
0xe86,
|
||||
0xe89,
|
||||
0xe8b,
|
||||
0xe8c,
|
||||
0xe98,
|
||||
0xea0,
|
||||
0xea4,
|
||||
0xea6,
|
||||
0xea8,
|
||||
0xea9,
|
||||
0xeac,
|
||||
0xeba,
|
||||
0xebe,
|
||||
0xebf,
|
||||
0xec5,
|
||||
0xec7,
|
||||
0xece,
|
||||
0xecf,
|
||||
0xeda,
|
||||
0xedb,
|
||||
0xf48,
|
||||
0xf98,
|
||||
0xfbd,
|
||||
0xfcd,
|
||||
0x10c6,
|
||||
0x10ce,
|
||||
0x10cf,
|
||||
0x1249,
|
||||
0x124e,
|
||||
0x124f,
|
||||
0x1257,
|
||||
0x1259,
|
||||
0x125e,
|
||||
0x125f,
|
||||
0x1289,
|
||||
0x128e,
|
||||
0x128f,
|
||||
0x12b1,
|
||||
0x12b6,
|
||||
0x12b7,
|
||||
0x12bf,
|
||||
0x12c1,
|
||||
0x12c6,
|
||||
0x12c7,
|
||||
0x12d7,
|
||||
0x1311,
|
||||
0x1316,
|
||||
0x1317,
|
||||
0x135b,
|
||||
0x135c,
|
||||
0x1680,
|
||||
0x170d,
|
||||
0x176d,
|
||||
0x1771,
|
||||
0x17de,
|
||||
0x17df,
|
||||
0x180e,
|
||||
0x180f,
|
||||
0x196e,
|
||||
0x196f,
|
||||
0x1a1c,
|
||||
0x1a1d,
|
||||
0x1a5f,
|
||||
0x1a7d,
|
||||
0x1a7e,
|
||||
0x1f16,
|
||||
0x1f17,
|
||||
0x1f1e,
|
||||
0x1f1f,
|
||||
0x1f46,
|
||||
0x1f47,
|
||||
0x1f4e,
|
||||
0x1f4f,
|
||||
0x1f58,
|
||||
0x1f5a,
|
||||
0x1f5c,
|
||||
0x1f5e,
|
||||
0x1f7e,
|
||||
0x1f7f,
|
||||
0x1fb5,
|
||||
0x1fc5,
|
||||
0x1fd4,
|
||||
0x1fd5,
|
||||
0x1fdc,
|
||||
0x1ff0,
|
||||
0x1ff1,
|
||||
0x1ff5,
|
||||
0x2072,
|
||||
0x2073,
|
||||
0x208f,
|
||||
0x2700,
|
||||
0x2c2f,
|
||||
0x2c5f,
|
||||
0x2d26,
|
||||
0x2d2e,
|
||||
0x2d2f,
|
||||
0x2da7,
|
||||
0x2daf,
|
||||
0x2db7,
|
||||
0x2dbf,
|
||||
0x2dc7,
|
||||
0x2dcf,
|
||||
0x2dd7,
|
||||
0x2ddf,
|
||||
0x2e9a,
|
||||
0x3040,
|
||||
0x3097,
|
||||
0x3098,
|
||||
0x318f,
|
||||
0x321f,
|
||||
0x32ff,
|
||||
0xa78f,
|
||||
0xa9ce,
|
||||
0xaa4e,
|
||||
0xaa4f,
|
||||
0xaa5a,
|
||||
0xaa5b,
|
||||
0xab07,
|
||||
0xab08,
|
||||
0xab0f,
|
||||
0xab10,
|
||||
0xab27,
|
||||
0xabee,
|
||||
0xabef,
|
||||
0xfa6e,
|
||||
0xfa6f,
|
||||
0xfb37,
|
||||
0xfb3d,
|
||||
0xfb3f,
|
||||
0xfb42,
|
||||
0xfb45,
|
||||
0xfd90,
|
||||
0xfd91,
|
||||
0xfdfe,
|
||||
0xfdff,
|
||||
0xfe53,
|
||||
0xfe67,
|
||||
0xfe75,
|
||||
0xffc8,
|
||||
0xffc9,
|
||||
0xffd0,
|
||||
0xffd1,
|
||||
0xffd8,
|
||||
0xffd9,
|
||||
0xffe7,
|
||||
0xfffe,
|
||||
0xffff,
|
||||
];
|
||||
const SINGLETONS1: &'static [u16] = &[
|
||||
0xc,
|
||||
0x27,
|
||||
0x3b,
|
||||
0x3e,
|
||||
0x4e,
|
||||
0x4f,
|
||||
0x31f,
|
||||
0x39e,
|
||||
0x49e,
|
||||
0x49f,
|
||||
0x806,
|
||||
0x807,
|
||||
0x809,
|
||||
0x836,
|
||||
0x83d,
|
||||
0x83e,
|
||||
0x856,
|
||||
0xa04,
|
||||
0xa14,
|
||||
0xa18,
|
||||
0xb56,
|
||||
0xb57,
|
||||
0x10bd,
|
||||
0x1135,
|
||||
0xd127,
|
||||
0xd128,
|
||||
0xd455,
|
||||
0xd49d,
|
||||
0xd4a0,
|
||||
0xd4a1,
|
||||
0xd4a3,
|
||||
0xd4a4,
|
||||
0xd4a7,
|
||||
0xd4a8,
|
||||
0xd4ad,
|
||||
0xd4ba,
|
||||
0xd4bc,
|
||||
0xd4c4,
|
||||
0xd506,
|
||||
0xd50b,
|
||||
0xd50c,
|
||||
0xd515,
|
||||
0xd51d,
|
||||
0xd53a,
|
||||
0xd53f,
|
||||
0xd545,
|
||||
0xd551,
|
||||
0xd6a6,
|
||||
0xd6a7,
|
||||
0xd7cc,
|
||||
0xd7cd,
|
||||
0xee04,
|
||||
0xee20,
|
||||
0xee23,
|
||||
0xee25,
|
||||
0xee26,
|
||||
0xee28,
|
||||
0xee33,
|
||||
0xee38,
|
||||
0xee3a,
|
||||
0xee48,
|
||||
0xee4a,
|
||||
0xee4c,
|
||||
0xee50,
|
||||
0xee53,
|
||||
0xee55,
|
||||
0xee56,
|
||||
0xee58,
|
||||
0xee5a,
|
||||
0xee5c,
|
||||
0xee5e,
|
||||
0xee60,
|
||||
0xee63,
|
||||
0xee65,
|
||||
0xee66,
|
||||
0xee6b,
|
||||
0xee73,
|
||||
0xee78,
|
||||
0xee7d,
|
||||
0xee7f,
|
||||
0xee8a,
|
||||
0xeea4,
|
||||
0xeeaa,
|
||||
0xf0af,
|
||||
0xf0b0,
|
||||
0xf0bf,
|
||||
0xf0c0,
|
||||
0xf0d0,
|
||||
0xf12f,
|
||||
0xf336,
|
||||
0xf3c5,
|
||||
0xf43f,
|
||||
0xf441,
|
||||
0xf4f8,
|
||||
0xf53e,
|
||||
0xf53f,
|
||||
];
|
||||
const NORMAL0: &'static [u16] = &[
|
||||
0x0, 0x20,
|
||||
0x7f, 0x22,
|
||||
0x37f, 0x5,
|
||||
0x528, 0x9,
|
||||
0x58b, 0x4,
|
||||
0x5c8, 0x8,
|
||||
0x5eb, 0x5,
|
||||
0x5f5, 0x11,
|
||||
0x7b2, 0xe,
|
||||
0x7fb, 0x5,
|
||||
0x85f, 0x41,
|
||||
0x8ad, 0x37,
|
||||
0x9b3, 0x3,
|
||||
0x9cf, 0x8,
|
||||
0x9d8, 0x4,
|
||||
0x9fc, 0x5,
|
||||
0xa0b, 0x4,
|
||||
0xa43, 0x4,
|
||||
0xa4e, 0x3,
|
||||
0xa52, 0x7,
|
||||
0xa5f, 0x7,
|
||||
0xa76, 0xb,
|
||||
0xad1, 0xf,
|
||||
0xaf2, 0xf,
|
||||
0xb4e, 0x8,
|
||||
0xb58, 0x4,
|
||||
0xb78, 0xa,
|
||||
0xb8b, 0x3,
|
||||
0xb96, 0x3,
|
||||
0xba0, 0x3,
|
||||
0xba5, 0x3,
|
||||
0xbab, 0x3,
|
||||
0xbba, 0x4,
|
||||
0xbc3, 0x3,
|
||||
0xbd1, 0x6,
|
||||
0xbd8, 0xe,
|
||||
0xbfb, 0x6,
|
||||
0xc3a, 0x3,
|
||||
0xc4e, 0x7,
|
||||
0xc5a, 0x6,
|
||||
0xc70, 0x8,
|
||||
0xcce, 0x7,
|
||||
0xcd7, 0x7,
|
||||
0xcf3, 0xf,
|
||||
0xd4f, 0x8,
|
||||
0xd58, 0x8,
|
||||
0xd76, 0x3,
|
||||
0xd97, 0x3,
|
||||
0xdc7, 0x3,
|
||||
0xdcb, 0x4,
|
||||
0xde0, 0x12,
|
||||
0xdf5, 0xc,
|
||||
0xe3b, 0x4,
|
||||
0xe5c, 0x25,
|
||||
0xe8e, 0x6,
|
||||
0xee0, 0x20,
|
||||
0xf6d, 0x4,
|
||||
0xfdb, 0x25,
|
||||
0x10c8, 0x5,
|
||||
0x137d, 0x3,
|
||||
0x139a, 0x6,
|
||||
0x13f5, 0xb,
|
||||
0x169d, 0x3,
|
||||
0x16f1, 0xf,
|
||||
0x1715, 0xb,
|
||||
0x1737, 0x9,
|
||||
0x1754, 0xc,
|
||||
0x1774, 0xc,
|
||||
0x17ea, 0x6,
|
||||
0x17fa, 0x6,
|
||||
0x181a, 0x6,
|
||||
0x1878, 0x8,
|
||||
0x18ab, 0x5,
|
||||
0x18f6, 0xa,
|
||||
0x191d, 0x3,
|
||||
0x192c, 0x4,
|
||||
0x193c, 0x4,
|
||||
0x1941, 0x3,
|
||||
0x1975, 0xb,
|
||||
0x19ac, 0x4,
|
||||
0x19ca, 0x6,
|
||||
0x19db, 0x3,
|
||||
0x1a8a, 0x6,
|
||||
0x1a9a, 0x6,
|
||||
0x1aae, 0x52,
|
||||
0x1b4c, 0x4,
|
||||
0x1b7d, 0x3,
|
||||
0x1bf4, 0x8,
|
||||
0x1c38, 0x3,
|
||||
0x1c4a, 0x3,
|
||||
0x1c80, 0x40,
|
||||
0x1cc8, 0x8,
|
||||
0x1cf7, 0x9,
|
||||
0x1de7, 0x15,
|
||||
0x1fff, 0x11,
|
||||
0x2028, 0x8,
|
||||
0x205f, 0x11,
|
||||
0x209d, 0x3,
|
||||
0x20ba, 0x16,
|
||||
0x20f1, 0xf,
|
||||
0x218a, 0x6,
|
||||
0x23f4, 0xc,
|
||||
0x2427, 0x19,
|
||||
0x244b, 0x15,
|
||||
0x2b4d, 0x3,
|
||||
0x2b5a, 0xa6,
|
||||
0x2cf4, 0x5,
|
||||
0x2d28, 0x5,
|
||||
0x2d68, 0x7,
|
||||
0x2d71, 0xe,
|
||||
0x2d97, 0x9,
|
||||
0x2e3c, 0x44,
|
||||
0x2ef4, 0xc,
|
||||
0x2fd6, 0x1a,
|
||||
0x2ffc, 0x5,
|
||||
0x3100, 0x5,
|
||||
0x312e, 0x3,
|
||||
0x31bb, 0x5,
|
||||
0x31e4, 0xc,
|
||||
0x3400, 0x19c0,
|
||||
0x4e00, 0x5200,
|
||||
0xa48d, 0x3,
|
||||
0xa4c7, 0x9,
|
||||
0xa62c, 0x14,
|
||||
0xa698, 0x7,
|
||||
0xa6f8, 0x8,
|
||||
0xa794, 0xc,
|
||||
0xa7ab, 0x4d,
|
||||
0xa82c, 0x4,
|
||||
0xa83a, 0x6,
|
||||
0xa878, 0x8,
|
||||
0xa8c5, 0x9,
|
||||
0xa8da, 0x6,
|
||||
0xa8fc, 0x4,
|
||||
0xa954, 0xb,
|
||||
0xa97d, 0x3,
|
||||
0xa9da, 0x4,
|
||||
0xa9e0, 0x20,
|
||||
0xaa37, 0x9,
|
||||
0xaa7c, 0x4,
|
||||
0xaac3, 0x18,
|
||||
0xaaf7, 0xa,
|
||||
0xab17, 0x9,
|
||||
0xab2f, 0x91,
|
||||
0xabfa, 0x2bb6,
|
||||
0xd7c7, 0x4,
|
||||
0xd7fc, 0x2104,
|
||||
0xfada, 0x26,
|
||||
0xfb07, 0xc,
|
||||
0xfb18, 0x5,
|
||||
0xfbc2, 0x11,
|
||||
0xfd40, 0x10,
|
||||
0xfdc8, 0x28,
|
||||
0xfe1a, 0x6,
|
||||
0xfe27, 0x9,
|
||||
0xfe6c, 0x4,
|
||||
0xfefd, 0x4,
|
||||
0xffbf, 0x3,
|
||||
0xffdd, 0x3,
|
||||
0xffef, 0xd,
|
||||
];
|
||||
const NORMAL1: &'static [u16] = &[
|
||||
0x5e, 0x22,
|
||||
0xfb, 0x5,
|
||||
0x103, 0x4,
|
||||
0x134, 0x3,
|
||||
0x18b, 0x5,
|
||||
0x19c, 0x34,
|
||||
0x1fe, 0x82,
|
||||
0x29d, 0x3,
|
||||
0x2d1, 0x2f,
|
||||
0x324, 0xc,
|
||||
0x34b, 0x35,
|
||||
0x3c4, 0x4,
|
||||
0x3d6, 0x2a,
|
||||
0x4aa, 0x356,
|
||||
0x839, 0x3,
|
||||
0x860, 0xa0,
|
||||
0x91c, 0x3,
|
||||
0x93a, 0x5,
|
||||
0x940, 0x40,
|
||||
0x9b8, 0x6,
|
||||
0x9c0, 0x40,
|
||||
0xa07, 0x5,
|
||||
0xa34, 0x4,
|
||||
0xa3b, 0x4,
|
||||
0xa48, 0x8,
|
||||
0xa59, 0x7,
|
||||
0xa80, 0x80,
|
||||
0xb36, 0x3,
|
||||
0xb73, 0x5,
|
||||
0xb80, 0x80,
|
||||
0xc49, 0x217,
|
||||
0xe7f, 0x181,
|
||||
0x104e, 0x4,
|
||||
0x1070, 0x10,
|
||||
0x10c2, 0xe,
|
||||
0x10e9, 0x7,
|
||||
0x10fa, 0x6,
|
||||
0x1144, 0x3c,
|
||||
0x11c9, 0x7,
|
||||
0x11da, 0x4a6,
|
||||
0x16b8, 0x8,
|
||||
0x16ca, 0x936,
|
||||
0x236f, 0x91,
|
||||
0x2463, 0xd,
|
||||
0x2474, 0xb8c,
|
||||
0x342f, 0x33d1,
|
||||
0x6a39, 0x4c7,
|
||||
0x6f45, 0xb,
|
||||
0x6f7f, 0x10,
|
||||
0x6fa0, 0x4060,
|
||||
0xb002, 0x1ffe,
|
||||
0xd0f6, 0xa,
|
||||
0xd173, 0x8,
|
||||
0xd1de, 0x22,
|
||||
0xd246, 0xba,
|
||||
0xd357, 0x9,
|
||||
0xd372, 0x8e,
|
||||
0xd547, 0x3,
|
||||
0xd800, 0x1600,
|
||||
0xee3c, 0x6,
|
||||
0xee43, 0x4,
|
||||
0xee9c, 0x5,
|
||||
0xeebc, 0x34,
|
||||
0xeef2, 0x10e,
|
||||
0xf02c, 0x4,
|
||||
0xf094, 0xc,
|
||||
0xf0e0, 0x20,
|
||||
0xf10b, 0x5,
|
||||
0xf16c, 0x4,
|
||||
0xf19b, 0x4b,
|
||||
0xf203, 0xd,
|
||||
0xf23b, 0x5,
|
||||
0xf249, 0x7,
|
||||
0xf252, 0xae,
|
||||
0xf321, 0xf,
|
||||
0xf37d, 0x3,
|
||||
0xf394, 0xc,
|
||||
0xf3cb, 0x15,
|
||||
0xf3f1, 0xf,
|
||||
0xf4fd, 0x3,
|
||||
0xf544, 0xc,
|
||||
0xf568, 0x93,
|
||||
0xf641, 0x4,
|
||||
0xf650, 0x30,
|
||||
0xf6c6, 0x3a,
|
||||
0xf774, 0x88c,
|
||||
];
|
||||
|
|
@ -980,15 +980,19 @@ impl<'a> Formatter<'a> {
|
|||
return self.buf.write_str(s);
|
||||
}
|
||||
// The `precision` field can be interpreted as a `max-width` for the
|
||||
// string being formatted
|
||||
if let Some(max) = self.precision {
|
||||
// If there's a maximum width and our string is longer than
|
||||
// that, then we must always have truncation. This is the only
|
||||
// case where the maximum length will matter.
|
||||
// string being formatted.
|
||||
let s = if let Some(max) = self.precision {
|
||||
// If our string is longer that the precision, then we must have
|
||||
// truncation. However other flags like `fill`, `width` and `align`
|
||||
// must act as always.
|
||||
if let Some((i, _)) = s.char_indices().skip(max).next() {
|
||||
return self.buf.write_str(&s[..i])
|
||||
&s[..i]
|
||||
} else {
|
||||
&s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
&s
|
||||
};
|
||||
// The `width` field is more of a `min-width` parameter at this point.
|
||||
match self.width {
|
||||
// If we're under the maximum length, and there's no minimum length
|
||||
|
|
@ -1379,7 +1383,7 @@ impl Debug for str {
|
|||
f.write_char('"')?;
|
||||
let mut from = 0;
|
||||
for (i, c) in self.char_indices() {
|
||||
let esc = c.escape_default();
|
||||
let esc = c.escape_debug();
|
||||
// If char needs escaping, flush backlog so far and write, else skip
|
||||
if esc.len() != 1 {
|
||||
f.write_str(&self[from..i])?;
|
||||
|
|
@ -1405,7 +1409,7 @@ impl Display for str {
|
|||
impl Debug for char {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.write_char('\'')?;
|
||||
for c in self.escape_default() {
|
||||
for c in self.escape_debug() {
|
||||
f.write_char(c)?
|
||||
}
|
||||
f.write_char('\'')
|
||||
|
|
|
|||
|
|
@ -234,6 +234,16 @@ pub trait BuildHasher {
|
|||
type Hasher: Hasher;
|
||||
|
||||
/// Creates a new hasher.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::hash_map::RandomState;
|
||||
/// use std::hash::BuildHasher;
|
||||
///
|
||||
/// let s = RandomState::new();
|
||||
/// let new_s = s.build_hasher();
|
||||
/// ```
|
||||
#[stable(since = "1.7.0", feature = "build_hasher")]
|
||||
fn build_hasher(&self) -> Self::Hasher;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,17 +277,200 @@ extern "rust-intrinsic" {
|
|||
/// Moves a value out of scope without running drop glue.
|
||||
pub fn forget<T>(_: T) -> ();
|
||||
|
||||
/// Unsafely transforms a value of one type into a value of another type.
|
||||
/// Reinterprets the bits of a value of one type as another type; both types
|
||||
/// must have the same size. Neither the original, nor the result, may be an
|
||||
/// [invalid value] (../../nomicon/meet-safe-and-unsafe.html).
|
||||
///
|
||||
/// Both types must have the same size.
|
||||
/// `transmute` is semantically equivalent to a bitwise move of one type
|
||||
/// into another. It copies the bits from the destination type into the
|
||||
/// source type, then forgets the original. It's equivalent to C's `memcpy`
|
||||
/// under the hood, just like `transmute_copy`.
|
||||
///
|
||||
/// `transmute` is incredibly unsafe. There are a vast number of ways to
|
||||
/// cause undefined behavior with this function. `transmute` should be
|
||||
/// the absolute last resort.
|
||||
///
|
||||
/// The [nomicon](../../nomicon/transmutes.html) has additional
|
||||
/// documentation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
/// There are a few things that `transmute` is really useful for.
|
||||
///
|
||||
/// let array: &[u8] = unsafe { mem::transmute("Rust") };
|
||||
/// assert_eq!(array, [82, 117, 115, 116]);
|
||||
/// Getting the bitpattern of a floating point type (or, more generally,
|
||||
/// type punning, when `T` and `U` aren't pointers):
|
||||
///
|
||||
/// ```
|
||||
/// let bitpattern = unsafe {
|
||||
/// std::mem::transmute::<f32, u32>(1.0)
|
||||
/// };
|
||||
/// assert_eq!(bitpattern, 0x3F800000);
|
||||
/// ```
|
||||
///
|
||||
/// Turning a pointer into a function pointer:
|
||||
///
|
||||
/// ```
|
||||
/// fn foo() -> i32 {
|
||||
/// 0
|
||||
/// }
|
||||
/// let pointer = foo as *const ();
|
||||
/// let function = unsafe {
|
||||
/// std::mem::transmute::<*const (), fn() -> i32>(pointer)
|
||||
/// };
|
||||
/// assert_eq!(function(), 0);
|
||||
/// ```
|
||||
///
|
||||
/// Extending a lifetime, or shortening an invariant lifetime; this is
|
||||
/// advanced, very unsafe rust:
|
||||
///
|
||||
/// ```
|
||||
/// struct R<'a>(&'a i32);
|
||||
/// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
|
||||
/// std::mem::transmute::<R<'b>, R<'static>>(r)
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
|
||||
/// -> &'b mut R<'c> {
|
||||
/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Alternatives
|
||||
///
|
||||
/// However, many uses of `transmute` can be achieved through other means.
|
||||
/// `transmute` can transform any type into any other, with just the caveat
|
||||
/// that they're the same size, and often interesting results occur. Below
|
||||
/// are common applications of `transmute` which can be replaced with safe
|
||||
/// applications of `as`:
|
||||
///
|
||||
/// Turning a pointer into a `usize`:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr = &0;
|
||||
/// let ptr_num_transmute = unsafe {
|
||||
/// std::mem::transmute::<&i32, usize>(ptr)
|
||||
/// };
|
||||
/// // Use an `as` cast instead
|
||||
/// let ptr_num_cast = ptr as *const i32 as usize;
|
||||
/// ```
|
||||
///
|
||||
/// Turning a `*mut T` into an `&mut T`:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *mut i32 = &mut 0;
|
||||
/// let ref_transmuted = unsafe {
|
||||
/// std::mem::transmute::<*mut i32, &mut i32>(ptr)
|
||||
/// };
|
||||
/// // Use a reborrow instead
|
||||
/// let ref_casted = unsafe { &mut *ptr };
|
||||
/// ```
|
||||
///
|
||||
/// Turning an `&mut T` into an `&mut U`:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr = &mut 0;
|
||||
/// let val_transmuted = unsafe {
|
||||
/// std::mem::transmute::<&mut i32, &mut u32>(ptr)
|
||||
/// };
|
||||
/// // Now, put together `as` and reborrowing - note the chaining of `as`
|
||||
/// // `as` is not transitive
|
||||
/// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };
|
||||
/// ```
|
||||
///
|
||||
/// Turning an `&str` into an `&[u8]`:
|
||||
///
|
||||
/// ```
|
||||
/// // this is not a good way to do this.
|
||||
/// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
|
||||
/// assert_eq!(slice, &[82, 117, 115, 116]);
|
||||
/// // You could use `str::as_bytes`
|
||||
/// let slice = "Rust".as_bytes();
|
||||
/// assert_eq!(slice, &[82, 117, 115, 116]);
|
||||
/// // Or, just use a byte string, if you have control over the string
|
||||
/// // literal
|
||||
/// assert_eq!(b"Rust", &[82, 117, 115, 116]);
|
||||
/// ```
|
||||
///
|
||||
/// Turning a `Vec<&T>` into a `Vec<Option<&T>>`:
|
||||
///
|
||||
/// ```
|
||||
/// let store = [0, 1, 2, 3];
|
||||
/// let mut v_orig = store.iter().collect::<Vec<&i32>>();
|
||||
/// // Using transmute: this is Undefined Behavior, and a bad idea.
|
||||
/// // However, it is no-copy.
|
||||
/// let v_transmuted = unsafe {
|
||||
/// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
|
||||
/// v_orig.clone())
|
||||
/// };
|
||||
/// // This is the suggested, safe way.
|
||||
/// // It does copy the entire Vector, though, into a new array.
|
||||
/// let v_collected = v_orig.clone()
|
||||
/// .into_iter()
|
||||
/// .map(|r| Some(r))
|
||||
/// .collect::<Vec<Option<&i32>>>();
|
||||
/// // The no-copy, unsafe way, still using transmute, but not UB.
|
||||
/// // This is equivalent to the original, but safer, and reuses the
|
||||
/// // same Vec internals. Therefore the new inner type must have the
|
||||
/// // exact same size, and the same or lesser alignment, as the old
|
||||
/// // type. The same caveats exist for this method as transmute, for
|
||||
/// // the original inner type (`&i32`) to the converted inner type
|
||||
/// // (`Option<&i32>`), so read the nomicon pages linked above.
|
||||
/// let v_from_raw = unsafe {
|
||||
/// Vec::from_raw_parts(v_orig.as_mut_ptr(),
|
||||
/// v_orig.len(),
|
||||
/// v_orig.capacity())
|
||||
/// };
|
||||
/// std::mem::forget(v_orig);
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `split_at_mut`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::{slice, mem};
|
||||
/// // There are multiple ways to do this; and there are multiple problems
|
||||
/// // with the following, transmute, way.
|
||||
/// fn split_at_mut_transmute<T>(slice: &mut [T], mid: usize)
|
||||
/// -> (&mut [T], &mut [T]) {
|
||||
/// let len = slice.len();
|
||||
/// assert!(mid <= len);
|
||||
/// unsafe {
|
||||
/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice);
|
||||
/// // first: transmute is not typesafe; all it checks is that T and
|
||||
/// // U are of the same size. Second, right here, you have two
|
||||
/// // mutable references pointing to the same memory.
|
||||
/// (&mut slice[0..mid], &mut slice2[mid..len])
|
||||
/// }
|
||||
/// }
|
||||
/// // This gets rid of the typesafety problems; `&mut *` will *only* give
|
||||
/// // you an `&mut T` from an `&mut T` or `*mut T`.
|
||||
/// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
|
||||
/// -> (&mut [T], &mut [T]) {
|
||||
/// let len = slice.len();
|
||||
/// assert!(mid <= len);
|
||||
/// unsafe {
|
||||
/// let slice2 = &mut *(slice as *mut [T]);
|
||||
/// // however, you still have two mutable references pointing to
|
||||
/// // the same memory.
|
||||
/// (&mut slice[0..mid], &mut slice2[mid..len])
|
||||
/// }
|
||||
/// }
|
||||
/// // This is how the standard library does it. This is the best method, if
|
||||
/// // you need to do something like this
|
||||
/// fn split_at_stdlib<T>(slice: &mut [T], mid: usize)
|
||||
/// -> (&mut [T], &mut [T]) {
|
||||
/// let len = slice.len();
|
||||
/// assert!(mid <= len);
|
||||
/// unsafe {
|
||||
/// let ptr = slice.as_mut_ptr();
|
||||
/// // This now has three mutable references pointing at the same
|
||||
/// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1.
|
||||
/// // `slice` is never used after `let ptr = ...`, and so one can
|
||||
/// // treat it as "dead", and therefore, you only have two real
|
||||
/// // mutable slices.
|
||||
/// (slice::from_raw_parts_mut(ptr, mid),
|
||||
/// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn transmute<T, U>(e: T) -> U;
|
||||
|
|
|
|||
|
|
@ -386,10 +386,11 @@ pub trait Extend<A> {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait DoubleEndedIterator: Iterator {
|
||||
/// An iterator able to yield elements from both ends.
|
||||
/// Removes and returns an element from the end of the iterator.
|
||||
///
|
||||
/// As this is the only method for this trait, the [trait-level] docs
|
||||
/// contain more details.
|
||||
/// Returns `None` when there are no more elements.
|
||||
///
|
||||
/// The [trait-level] docs contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.DoubleEndedIterator.html
|
||||
///
|
||||
|
|
|
|||
|
|
@ -103,17 +103,17 @@ mod int_macros;
|
|||
#[macro_use]
|
||||
mod uint_macros;
|
||||
|
||||
#[path = "num/isize.rs"] pub mod isize;
|
||||
#[path = "num/i8.rs"] pub mod i8;
|
||||
#[path = "num/i16.rs"] pub mod i16;
|
||||
#[path = "num/i32.rs"] pub mod i32;
|
||||
#[path = "num/i64.rs"] pub mod i64;
|
||||
#[path = "num/isize.rs"] pub mod isize;
|
||||
#[path = "num/i8.rs"] pub mod i8;
|
||||
#[path = "num/i16.rs"] pub mod i16;
|
||||
#[path = "num/i32.rs"] pub mod i32;
|
||||
#[path = "num/i64.rs"] pub mod i64;
|
||||
|
||||
#[path = "num/usize.rs"] pub mod usize;
|
||||
#[path = "num/u8.rs"] pub mod u8;
|
||||
#[path = "num/u16.rs"] pub mod u16;
|
||||
#[path = "num/u32.rs"] pub mod u32;
|
||||
#[path = "num/u64.rs"] pub mod u64;
|
||||
#[path = "num/u8.rs"] pub mod u8;
|
||||
#[path = "num/u16.rs"] pub mod u16;
|
||||
#[path = "num/u32.rs"] pub mod u32;
|
||||
#[path = "num/u64.rs"] pub mod u64;
|
||||
|
||||
#[path = "num/f32.rs"] pub mod f32;
|
||||
#[path = "num/f64.rs"] pub mod f64;
|
||||
|
|
@ -161,5 +161,6 @@ pub mod hash;
|
|||
pub mod fmt;
|
||||
|
||||
// note: does not need to be public
|
||||
mod char_private;
|
||||
mod iter_private;
|
||||
mod tuple;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,17 @@ macro_rules! panic {
|
|||
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||
/// evaluated to `true` at runtime.
|
||||
///
|
||||
/// Assertions are always checked in both debug and release builds, and cannot
|
||||
/// be disabled. See `debug_assert!` for assertions that are not enabled in
|
||||
/// release builds by default.
|
||||
///
|
||||
/// Unsafe code relies on `assert!` to enforce run-time invariants that, if
|
||||
/// violated could lead to unsafety.
|
||||
///
|
||||
/// Other use-cases of `assert!` include
|
||||
/// [testing](https://doc.rust-lang.org/book/testing.html) and enforcing
|
||||
/// run-time invariants in safe code (whose violation cannot result in unsafety).
|
||||
///
|
||||
/// This macro has a second version, where a custom panic message can be provided.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -123,6 +134,13 @@ macro_rules! assert_eq {
|
|||
/// expensive to be present in a release build but may be helpful during
|
||||
/// development.
|
||||
///
|
||||
/// An unchecked assertion allows a program in an inconsistent state to keep
|
||||
/// running, which might have unexpected consequences but does not introduce
|
||||
/// unsafety as long as this only happens in safe code. The performance cost
|
||||
/// of assertions, is however, not measurable in general. Replacing `assert!`
|
||||
/// with `debug_assert!` is thus only encouraged after thorough profiling, and
|
||||
/// more importantly, only in safe code!
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -144,6 +144,12 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's
|
||||
/// managing some resource besides its own `size_of::<T>()` bytes.
|
||||
///
|
||||
/// ## What if I derive `Copy` on a type that can't?
|
||||
///
|
||||
/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error.
|
||||
/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204)
|
||||
/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205).
|
||||
///
|
||||
/// ## When should my type be `Copy`?
|
||||
///
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing
|
||||
|
|
|
|||
|
|
@ -611,6 +611,31 @@ macro_rules! int_impl {
|
|||
if b {None} else {Some(a)}
|
||||
}
|
||||
|
||||
/// Checked absolute value. Computes `self.abs()`, returning `None` if
|
||||
/// `self == MIN`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(no_panic_abs)]
|
||||
///
|
||||
/// use std::i32;
|
||||
///
|
||||
/// assert_eq!((-5i32).checked_abs(), Some(5));
|
||||
/// assert_eq!(i32::MIN.checked_abs(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "no_panic_abs", issue = "35057")]
|
||||
#[inline]
|
||||
pub fn checked_abs(self) -> Option<Self> {
|
||||
if self.is_negative() {
|
||||
self.checked_neg()
|
||||
} else {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Saturating integer addition. Computes `self + other`, saturating at
|
||||
/// the numeric bounds instead of overflowing.
|
||||
///
|
||||
|
|
@ -863,6 +888,36 @@ macro_rules! int_impl {
|
|||
self.overflowing_shr(rhs).0
|
||||
}
|
||||
|
||||
/// Wrapping (modular) absolute value. Computes `self.abs()`,
|
||||
/// wrapping around at the boundary of the type.
|
||||
///
|
||||
/// The only case where such wrapping can occur is when one takes
|
||||
/// the absolute value of the negative minimal value for the type
|
||||
/// this is a positive value that is too large to represent in the
|
||||
/// type. In such a case, this function returns `MIN` itself.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(no_panic_abs)]
|
||||
///
|
||||
/// assert_eq!(100i8.wrapping_abs(), 100);
|
||||
/// assert_eq!((-100i8).wrapping_abs(), 100);
|
||||
/// assert_eq!((-128i8).wrapping_abs(), -128);
|
||||
/// assert_eq!((-128i8).wrapping_abs() as u8, 128);
|
||||
/// ```
|
||||
#[unstable(feature = "no_panic_abs", issue = "35057")]
|
||||
#[inline(always)]
|
||||
pub fn wrapping_abs(self) -> Self {
|
||||
if self.is_negative() {
|
||||
self.wrapping_neg()
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates `self` + `rhs`
|
||||
///
|
||||
/// Returns a tuple of the addition along with a boolean indicating
|
||||
|
|
@ -1071,6 +1126,35 @@ macro_rules! int_impl {
|
|||
(self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
|
||||
}
|
||||
|
||||
/// Computes the absolute value of `self`.
|
||||
///
|
||||
/// Returns a tuple of the absolute version of self along with a
|
||||
/// boolean indicating whether an overflow happened. If self is the
|
||||
/// minimum value (e.g. i32::MIN for values of type i32), then the
|
||||
/// minimum value will be returned again and true will be returned for
|
||||
/// an overflow happening.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(no_panic_abs)]
|
||||
///
|
||||
/// assert_eq!(10i8.overflowing_abs(), (10,false));
|
||||
/// assert_eq!((-10i8).overflowing_abs(), (10,false));
|
||||
/// assert_eq!((-128i8).overflowing_abs(), (-128,true));
|
||||
/// ```
|
||||
#[unstable(feature = "no_panic_abs", issue = "35057")]
|
||||
#[inline]
|
||||
pub fn overflowing_abs(self) -> (Self, bool) {
|
||||
if self.is_negative() {
|
||||
self.overflowing_neg()
|
||||
} else {
|
||||
(self, false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Raises self to the power of `exp`, using exponentiation by squaring.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@
|
|||
use self::Option::*;
|
||||
|
||||
use clone::Clone;
|
||||
use convert::From;
|
||||
use default::Default;
|
||||
use iter::ExactSizeIterator;
|
||||
use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator};
|
||||
|
|
@ -754,6 +755,13 @@ impl<'a, T> IntoIterator for &'a mut Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(since = "1.12.0", feature = "option_from")]
|
||||
impl<T> From<T> for Option<T> {
|
||||
fn from(val: T) -> Option<T> {
|
||||
Some(val)
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// The Option Iterators
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -902,6 +902,8 @@ macro_rules! make_mut_slice {
|
|||
|
||||
/// Immutable slice iterator
|
||||
///
|
||||
/// This struct is created by the [`iter`] method on [slices].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -915,6 +917,9 @@ macro_rules! make_mut_slice {
|
|||
/// println!("{}", element);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`iter`]: ../../std/primitive.slice.html#method.iter
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Iter<'a, T: 'a> {
|
||||
ptr: *const T,
|
||||
|
|
@ -993,6 +998,8 @@ impl<'a, T> Clone for Iter<'a, T> {
|
|||
|
||||
/// Mutable slice iterator.
|
||||
///
|
||||
/// This struct is created by the [`iter_mut`] method on [slices].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -1010,6 +1017,9 @@ impl<'a, T> Clone for Iter<'a, T> {
|
|||
/// // We now have "[2, 3, 4]":
|
||||
/// println!("{:?}", slice);
|
||||
/// ```
|
||||
///
|
||||
/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IterMut<'a, T: 'a> {
|
||||
ptr: *mut T,
|
||||
|
|
|
|||
|
|
@ -459,6 +459,19 @@ impl<'a> Chars<'a> {
|
|||
///
|
||||
/// This has the same lifetime as the original slice, and so the
|
||||
/// iterator can continue to be used while this exists.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut chars = "abc".chars();
|
||||
///
|
||||
/// assert_eq!(chars.as_str(), "abc");
|
||||
/// chars.next();
|
||||
/// assert_eq!(chars.as_str(), "bc");
|
||||
/// chars.next();
|
||||
/// chars.next();
|
||||
/// assert_eq!(chars.as_str(), "");
|
||||
/// ```
|
||||
#[stable(feature = "iter_to_slice", since = "1.4.0")]
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &'a str {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@
|
|||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![cfg_attr(not(target_has_atomic = "8"), allow(dead_code))]
|
||||
#![cfg_attr(not(target_has_atomic = "8"), allow(unused_imports))]
|
||||
|
||||
use self::Ordering::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,49 @@ fn test_is_digit() {
|
|||
assert!(!'Q'.is_numeric());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_debug() {
|
||||
fn string(c: char) -> String {
|
||||
c.escape_debug().collect()
|
||||
}
|
||||
let s = string('\n');
|
||||
assert_eq!(s, "\\n");
|
||||
let s = string('\r');
|
||||
assert_eq!(s, "\\r");
|
||||
let s = string('\'');
|
||||
assert_eq!(s, "\\'");
|
||||
let s = string('"');
|
||||
assert_eq!(s, "\\\"");
|
||||
let s = string(' ');
|
||||
assert_eq!(s, " ");
|
||||
let s = string('a');
|
||||
assert_eq!(s, "a");
|
||||
let s = string('~');
|
||||
assert_eq!(s, "~");
|
||||
let s = string('é');
|
||||
assert_eq!(s, "é");
|
||||
let s = string('\x00');
|
||||
assert_eq!(s, "\\u{0}");
|
||||
let s = string('\x1f');
|
||||
assert_eq!(s, "\\u{1f}");
|
||||
let s = string('\x7f');
|
||||
assert_eq!(s, "\\u{7f}");
|
||||
let s = string('\u{80}');
|
||||
assert_eq!(s, "\\u{80}");
|
||||
let s = string('\u{ff}');
|
||||
assert_eq!(s, "\u{ff}");
|
||||
let s = string('\u{11b}');
|
||||
assert_eq!(s, "\u{11b}");
|
||||
let s = string('\u{1d4b6}');
|
||||
assert_eq!(s, "\u{1d4b6}");
|
||||
let s = string('\u{200b}'); // zero width space
|
||||
assert_eq!(s, "\\u{200b}");
|
||||
let s = string('\u{e000}'); // private use 1
|
||||
assert_eq!(s, "\\u{e000}");
|
||||
let s = string('\u{100000}'); // private use 2
|
||||
assert_eq!(s, "\\u{100000}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_default() {
|
||||
fn string(c: char) -> String {
|
||||
|
|
@ -142,18 +185,28 @@ fn test_escape_default() {
|
|||
assert_eq!(s, "a");
|
||||
let s = string('~');
|
||||
assert_eq!(s, "~");
|
||||
let s = string('é');
|
||||
assert_eq!(s, "\\u{e9}");
|
||||
let s = string('\x00');
|
||||
assert_eq!(s, "\\u{0}");
|
||||
let s = string('\x1f');
|
||||
assert_eq!(s, "\\u{1f}");
|
||||
let s = string('\x7f');
|
||||
assert_eq!(s, "\\u{7f}");
|
||||
let s = string('\u{80}');
|
||||
assert_eq!(s, "\\u{80}");
|
||||
let s = string('\u{ff}');
|
||||
assert_eq!(s, "\\u{ff}");
|
||||
let s = string('\u{11b}');
|
||||
assert_eq!(s, "\\u{11b}");
|
||||
let s = string('\u{1d4b6}');
|
||||
assert_eq!(s, "\\u{1d4b6}");
|
||||
let s = string('\u{200b}'); // zero width space
|
||||
assert_eq!(s, "\\u{200b}");
|
||||
let s = string('\u{e000}'); // private use 1
|
||||
assert_eq!(s, "\\u{e000}");
|
||||
let s = string('\u{100000}'); // private use 2
|
||||
assert_eq!(s, "\\u{100000}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#![feature(borrow_state)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(cell_extras)]
|
||||
#![feature(char_escape_debug)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(core_private_bignum)]
|
||||
#![feature(core_private_diy_float)]
|
||||
|
|
@ -29,10 +30,9 @@
|
|||
#![feature(slice_patterns)]
|
||||
#![feature(step_by)]
|
||||
#![feature(test)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(try_from)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![feature(try_from)]
|
||||
|
||||
extern crate core;
|
||||
extern crate test;
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ crate-type = ["dylib"]
|
|||
|
||||
[build-dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
gcc = "0.3"
|
||||
gcc = "0.3.27"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit b0d62534d48b711c8978d1bbe8cca0558ae7b1cb
|
||||
Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b
|
||||
|
|
@ -45,16 +45,25 @@ pub const DW_EH_PE_aligned: u8 = 0x50;
|
|||
pub const DW_EH_PE_indirect: u8 = 0x80;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct EHContext {
|
||||
pub struct EHContext<'a> {
|
||||
pub ip: usize, // Current instruction pointer
|
||||
pub func_start: usize, // Address of the current function
|
||||
pub text_start: usize, // Address of the code section
|
||||
pub data_start: usize, // Address of the data section
|
||||
pub get_text_start: &'a Fn() -> usize, // Get address of the code section
|
||||
pub get_data_start: &'a Fn() -> usize, // Get address of the data section
|
||||
}
|
||||
|
||||
pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<usize> {
|
||||
pub enum EHAction {
|
||||
None,
|
||||
Cleanup(usize),
|
||||
Catch(usize),
|
||||
Terminate,
|
||||
}
|
||||
|
||||
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
|
||||
|
||||
pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
|
||||
if lsda.is_null() {
|
||||
return None;
|
||||
return EHAction::None;
|
||||
}
|
||||
|
||||
let func_start = context.func_start;
|
||||
|
|
@ -77,32 +86,61 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<u
|
|||
let call_site_encoding = reader.read::<u8>();
|
||||
let call_site_table_length = reader.read_uleb128();
|
||||
let action_table = reader.ptr.offset(call_site_table_length as isize);
|
||||
// Return addresses point 1 byte past the call instruction, which could
|
||||
// be in the next IP range.
|
||||
let ip = context.ip - 1;
|
||||
let ip = context.ip;
|
||||
|
||||
while reader.ptr < action_table {
|
||||
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
|
||||
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
|
||||
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
|
||||
let cs_action = reader.read_uleb128();
|
||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||
// may stop searching.
|
||||
if ip < func_start + cs_start {
|
||||
break;
|
||||
if !USING_SJLJ_EXCEPTIONS {
|
||||
while reader.ptr < action_table {
|
||||
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
|
||||
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
|
||||
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
|
||||
let cs_action = reader.read_uleb128();
|
||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||
// may stop searching.
|
||||
if ip < func_start + cs_start {
|
||||
break;
|
||||
}
|
||||
if ip < func_start + cs_start + cs_len {
|
||||
if cs_lpad == 0 {
|
||||
return EHAction::None;
|
||||
} else {
|
||||
let lpad = lpad_base + cs_lpad;
|
||||
return interpret_cs_action(cs_action, lpad);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ip < func_start + cs_start + cs_len {
|
||||
if cs_lpad != 0 {
|
||||
return Some(lpad_base + cs_lpad);
|
||||
} else {
|
||||
return None;
|
||||
// Ip is not present in the table. This should not happen... but it does: issue #35011.
|
||||
// So rather than returning EHAction::Terminate, we do this.
|
||||
EHAction::None
|
||||
} else {
|
||||
// SjLj version:
|
||||
// The "IP" is an index into the call-site table, with two exceptions:
|
||||
// -1 means 'no-action', and 0 means 'terminate'.
|
||||
match ip as isize {
|
||||
-1 => return EHAction::None,
|
||||
0 => return EHAction::Terminate,
|
||||
_ => (),
|
||||
}
|
||||
let mut idx = ip;
|
||||
loop {
|
||||
let cs_lpad = reader.read_uleb128();
|
||||
let cs_action = reader.read_uleb128();
|
||||
idx -= 1;
|
||||
if idx == 0 {
|
||||
// Can never have null landing pad for sjlj -- that would have
|
||||
// been indicated by a -1 call site index.
|
||||
let lpad = (cs_lpad + 1) as usize;
|
||||
return interpret_cs_action(cs_action, lpad);
|
||||
}
|
||||
}
|
||||
}
|
||||
// IP range not found: gcc's C++ personality calls terminate() here,
|
||||
// however the rest of the languages treat this the same as cs_lpad == 0.
|
||||
// We follow this suit.
|
||||
None
|
||||
}
|
||||
|
||||
fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
|
||||
if cs_action == 0 {
|
||||
EHAction::Cleanup(lpad)
|
||||
} else {
|
||||
EHAction::Catch(lpad)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -140,18 +178,16 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
|
|||
DW_EH_PE_absptr => 0,
|
||||
// relative to address of the encoded value, despite the name
|
||||
DW_EH_PE_pcrel => reader.ptr as usize,
|
||||
DW_EH_PE_textrel => {
|
||||
assert!(context.text_start != 0);
|
||||
context.text_start
|
||||
}
|
||||
DW_EH_PE_datarel => {
|
||||
assert!(context.data_start != 0);
|
||||
context.data_start
|
||||
}
|
||||
DW_EH_PE_funcrel => {
|
||||
assert!(context.func_start != 0);
|
||||
context.func_start
|
||||
}
|
||||
DW_EH_PE_textrel => {
|
||||
(*context.get_text_start)()
|
||||
}
|
||||
DW_EH_PE_datarel => {
|
||||
(*context.get_data_start)()
|
||||
}
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ use core::ptr;
|
|||
use alloc::boxed::Box;
|
||||
|
||||
use unwind as uw;
|
||||
use libc::{c_int, uintptr_t};
|
||||
use dwarf::eh::{self, EHContext, EHAction};
|
||||
|
||||
#[repr(C)]
|
||||
struct Exception {
|
||||
|
|
@ -106,160 +108,184 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
|||
0x4d4f5a_00_52555354
|
||||
}
|
||||
|
||||
// We could implement our personality routine in Rust, however exception
|
||||
// info decoding is tedious. More importantly, personality routines have to
|
||||
// handle various platform quirks, which are not fun to maintain. For this
|
||||
// reason, we attempt to reuse personality routine of the C language:
|
||||
// __gcc_personality_v0.
|
||||
//
|
||||
// Since C does not support exception catching, __gcc_personality_v0 simply
|
||||
// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
|
||||
// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
|
||||
//
|
||||
// This is pretty close to Rust's exception handling approach, except that Rust
|
||||
// does have a single "catch-all" handler at the bottom of each thread's stack.
|
||||
// So we have two versions of the personality routine:
|
||||
// - rust_eh_personality, used by all cleanup landing pads, which never catches,
|
||||
// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
|
||||
// - rust_eh_personality_catch, used only by rust_try(), which always catches.
|
||||
//
|
||||
// See also: rustc_trans::trans::intrinsic::trans_gnu_try
|
||||
|
||||
#[cfg(all(not(target_arch = "arm"),
|
||||
not(all(windows, target_arch = "x86_64"))))]
|
||||
pub mod eabi {
|
||||
use unwind as uw;
|
||||
use libc::c_int;
|
||||
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
|
||||
// and TargetLowering::getExceptionSelectorRegister() for each architecture,
|
||||
// then mapped to DWARF register numbers via register definition tables
|
||||
// (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
|
||||
// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
|
||||
|
||||
extern "C" {
|
||||
fn __gcc_personality_v0(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
#[cfg(target_arch = "x86")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
|
||||
|
||||
#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
|
||||
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
|
||||
|
||||
// The following code is based on GCC's C and C++ personality routines. For reference, see:
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
|
||||
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
|
||||
|
||||
// The personality routine for most of our targets, except ARM, which has a slightly different ABI
|
||||
// (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation
|
||||
// lives in seh64_gnu.rs
|
||||
#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
#[allow(unused)]
|
||||
unsafe extern "C" fn rust_eh_personality(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
if version != 1 {
|
||||
return uw::_URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_personality(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
|
||||
}
|
||||
|
||||
#[lang = "eh_personality_catch"]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_eh_personality_catch(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
|
||||
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
|
||||
// search phase
|
||||
uw::_URC_HANDLER_FOUND // catch!
|
||||
} else {
|
||||
// cleanup phase
|
||||
unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
|
||||
let eh_action = find_eh_action(context);
|
||||
if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
|
||||
match eh_action {
|
||||
EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
|
||||
}
|
||||
} else {
|
||||
match eh_action {
|
||||
EHAction::None => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
|
||||
uw::_Unwind_SetIP(context, lpad);
|
||||
return uw::_URC_INSTALL_CONTEXT;
|
||||
}
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iOS on armv7 is using SjLj exceptions and therefore requires to use
|
||||
// a specialized personality routine: __gcc_personality_sj0
|
||||
|
||||
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
||||
pub mod eabi {
|
||||
use unwind as uw;
|
||||
use libc::c_int;
|
||||
|
||||
extern "C" {
|
||||
fn __gcc_personality_sj0(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_eh_personality(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
|
||||
}
|
||||
|
||||
#[lang = "eh_personality_catch"]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_eh_personality_catch(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
|
||||
// search phase
|
||||
uw::_URC_HANDLER_FOUND // catch!
|
||||
} else {
|
||||
// cleanup phase
|
||||
unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ARM EHABI uses a slightly different personality routine signature,
|
||||
// but otherwise works the same.
|
||||
// ARM EHABI personality routine.
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
|
||||
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
|
||||
pub mod eabi {
|
||||
use unwind as uw;
|
||||
use libc::c_int;
|
||||
|
||||
extern "C" {
|
||||
fn __gcc_personality_v0(state: uw::_Unwind_State,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe { __gcc_personality_v0(state, ue_header, context) }
|
||||
}
|
||||
|
||||
#[lang = "eh_personality_catch"]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
let state = state as c_int;
|
||||
let action = state & uw::_US_ACTION_MASK as c_int;
|
||||
let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
|
||||
// Backtraces on ARM will call the personality routine with
|
||||
// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
|
||||
// we want to continue unwinding the stack, otherwise all our backtraces
|
||||
// would end at __rust_try.
|
||||
if (state as c_int & uw::_US_ACTION_MASK as c_int) ==
|
||||
uw::_US_VIRTUAL_UNWIND_FRAME as c_int &&
|
||||
(state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 {
|
||||
// search phase
|
||||
uw::_URC_HANDLER_FOUND // catch!
|
||||
} else {
|
||||
// cleanup phase
|
||||
unsafe { __gcc_personality_v0(state, ue_header, context) }
|
||||
// would end at __rust_try
|
||||
if state & uw::_US_FORCE_UNWIND as c_int != 0 {
|
||||
return continue_unwind(exception_object, context)
|
||||
}
|
||||
true
|
||||
} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
|
||||
false
|
||||
} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
|
||||
return continue_unwind(exception_object, context);
|
||||
} else {
|
||||
return uw::_URC_FAILURE;
|
||||
};
|
||||
|
||||
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
|
||||
// and LSDA pointers, however ARM EHABI places them into the exception object.
|
||||
// To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
|
||||
// take only the context pointer, GCC personality routines stash a pointer to exception_object
|
||||
// in the context, using location reserved for ARM's "scratch register" (r12).
|
||||
uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
|
||||
// ...A more principled approach would be to provide the full definition of ARM's
|
||||
// _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
|
||||
// bypassing DWARF compatibility functions.
|
||||
|
||||
let eh_action = find_eh_action(context);
|
||||
if search_phase {
|
||||
match eh_action {
|
||||
EHAction::None |
|
||||
EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
|
||||
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
|
||||
EHAction::Terminate => return uw::_URC_FAILURE,
|
||||
}
|
||||
} else {
|
||||
match eh_action {
|
||||
EHAction::None => return continue_unwind(exception_object, context),
|
||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
|
||||
uw::_Unwind_SetIP(context, lpad);
|
||||
return uw::_URC_INSTALL_CONTEXT;
|
||||
}
|
||||
EHAction::Terminate => return uw::_URC_FAILURE,
|
||||
}
|
||||
}
|
||||
|
||||
// On ARM EHABI the personality routine is responsible for actually
|
||||
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
|
||||
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
|
||||
uw::_URC_CONTINUE_UNWIND
|
||||
} else {
|
||||
uw::_URC_FAILURE
|
||||
}
|
||||
}
|
||||
// defined in libgcc
|
||||
extern "C" {
|
||||
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction {
|
||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||
let mut ip_before_instr: c_int = 0;
|
||||
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
||||
let eh_context = EHContext {
|
||||
// The return address points 1 byte past the call instruction,
|
||||
// which could be in the next IP range in LSDA range table.
|
||||
ip: if ip_before_instr != 0 { ip } else { ip - 1 },
|
||||
func_start: uw::_Unwind_GetRegionStart(context),
|
||||
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
|
||||
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
|
||||
};
|
||||
eh::find_eh_action(lsda, &eh_context)
|
||||
}
|
||||
|
||||
// *** Delete after a new snapshot ***
|
||||
#[cfg(all(stage0, any(target_os = "ios", not(target_arch = "arm"))))]
|
||||
#[lang = "eh_personality_catch"]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
rust_eh_personality(version, actions, exception_class, ue_header, context)
|
||||
}
|
||||
|
||||
// *** Delete after a new snapshot ***
|
||||
#[cfg(all(stage0, target_arch = "arm", not(target_os = "ios")))]
|
||||
#[lang = "eh_personality_catch"]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State,
|
||||
ue_header: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
rust_eh_personality(state, ue_header, context)
|
||||
}
|
||||
|
||||
// See docs in the `unwind` module.
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8),
|
|||
// Entry point for raising an exception, just delegates to the platform-specific
|
||||
// implementation.
|
||||
#[no_mangle]
|
||||
#[unwind]
|
||||
pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
|
||||
imp::panic(mem::transmute(raw::TraitObject {
|
||||
data: data as *mut (),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use alloc::boxed::Box;
|
|||
use core::any::Any;
|
||||
use core::intrinsics;
|
||||
use core::ptr;
|
||||
use dwarf::eh;
|
||||
use dwarf::eh::{EHContext, EHAction, find_eh_action};
|
||||
use windows as c;
|
||||
|
||||
// Define our exception codes:
|
||||
|
|
@ -81,6 +81,8 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
|
|||
// This is considered acceptable, because the behavior of throwing exceptions
|
||||
// through a C ABI boundary is undefined.
|
||||
|
||||
// *** Delete after a new snapshot ***
|
||||
#[cfg(stage0)]
|
||||
#[lang = "eh_personality_catch"]
|
||||
#[cfg(not(test))]
|
||||
unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
|
||||
|
|
@ -132,11 +134,17 @@ unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
|||
}
|
||||
|
||||
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
|
||||
let eh_ctx = eh::EHContext {
|
||||
ip: dc.ControlPc as usize,
|
||||
let eh_ctx = EHContext {
|
||||
// The return address points 1 byte past the call instruction,
|
||||
// which could be in the next IP range in LSDA range table.
|
||||
ip: dc.ControlPc as usize - 1,
|
||||
func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
|
||||
text_start: dc.ImageBase as usize,
|
||||
data_start: 0,
|
||||
get_text_start: &|| dc.ImageBase as usize,
|
||||
get_data_start: &|| unimplemented!(),
|
||||
};
|
||||
eh::find_landing_pad(dc.HandlerData, &eh_ctx)
|
||||
match find_eh_action(dc.HandlerData, &eh_ctx) {
|
||||
EHAction::None => None,
|
||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad),
|
||||
EHAction::Terminate => intrinsics::abort(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
macro_rules! try_opt {
|
||||
($e:expr) => (
|
||||
|
|
@ -45,6 +46,10 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
// in an extern crate.
|
||||
MetaData(D),
|
||||
|
||||
// Represents some artifact that we save to disk. Note that these
|
||||
// do not have a def-id as part of their identifier.
|
||||
WorkProduct(Arc<WorkProductId>),
|
||||
|
||||
// Represents different phases in the compiler.
|
||||
CrateReader,
|
||||
CollectLanguageItems,
|
||||
|
|
@ -189,6 +194,11 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
TransCrate => Some(TransCrate),
|
||||
TransWriteMetadata => Some(TransWriteMetadata),
|
||||
LinkBinary => Some(LinkBinary),
|
||||
|
||||
// work product names do not need to be mapped, because
|
||||
// they are always absolute.
|
||||
WorkProduct(ref id) => Some(WorkProduct(id.clone())),
|
||||
|
||||
Hir(ref d) => op(d).map(Hir),
|
||||
MetaData(ref d) => op(d).map(MetaData),
|
||||
CollectItem(ref d) => op(d).map(CollectItem),
|
||||
|
|
@ -229,3 +239,12 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A "work product" corresponds to a `.o` (or other) file that we
|
||||
/// save in between runs. These ids do not have a DefId but rather
|
||||
/// some independent path or string that persists between runs without
|
||||
/// the need to be mapped or unmapped. (This ensures we can serialize
|
||||
/// them even in the absence of a tcx.)
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct WorkProductId(pub String);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,22 +9,45 @@
|
|||
// except according to those terms.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use session::config::OutputType;
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::dep_node::DepNode;
|
||||
use super::dep_node::{DepNode, WorkProductId};
|
||||
use super::query::DepGraphQuery;
|
||||
use super::raii;
|
||||
use super::thread::{DepGraphThreadData, DepMessage};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DepGraph {
|
||||
data: Rc<DepGraphThreadData>
|
||||
data: Rc<DepGraphData>
|
||||
}
|
||||
|
||||
struct DepGraphData {
|
||||
/// We send messages to the thread to let it build up the dep-graph
|
||||
/// from the current run.
|
||||
thread: DepGraphThreadData,
|
||||
|
||||
/// When we load, there may be `.o` files, cached mir, or other such
|
||||
/// things available to us. If we find that they are not dirty, we
|
||||
/// load the path to the file storing those work-products here into
|
||||
/// this map. We can later look for and extract that data.
|
||||
previous_work_products: RefCell<FnvHashMap<Arc<WorkProductId>, WorkProduct>>,
|
||||
|
||||
/// Work-products that we generate in this run.
|
||||
work_products: RefCell<FnvHashMap<Arc<WorkProductId>, WorkProduct>>,
|
||||
}
|
||||
|
||||
impl DepGraph {
|
||||
pub fn new(enabled: bool) -> DepGraph {
|
||||
DepGraph {
|
||||
data: Rc::new(DepGraphThreadData::new(enabled))
|
||||
data: Rc::new(DepGraphData {
|
||||
thread: DepGraphThreadData::new(enabled),
|
||||
previous_work_products: RefCell::new(FnvHashMap()),
|
||||
work_products: RefCell::new(FnvHashMap())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,19 +55,19 @@ impl DepGraph {
|
|||
/// then the other methods on this `DepGraph` will have no net effect.
|
||||
#[inline]
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.data.enabled()
|
||||
self.data.thread.enabled()
|
||||
}
|
||||
|
||||
pub fn query(&self) -> DepGraphQuery<DefId> {
|
||||
self.data.query()
|
||||
self.data.thread.query()
|
||||
}
|
||||
|
||||
pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
|
||||
raii::IgnoreTask::new(&self.data)
|
||||
raii::IgnoreTask::new(&self.data.thread)
|
||||
}
|
||||
|
||||
pub fn in_task<'graph>(&'graph self, key: DepNode<DefId>) -> raii::DepTask<'graph> {
|
||||
raii::DepTask::new(&self.data, key)
|
||||
raii::DepTask::new(&self.data.thread, key)
|
||||
}
|
||||
|
||||
pub fn with_ignore<OP,R>(&self, op: OP) -> R
|
||||
|
|
@ -62,10 +85,84 @@ impl DepGraph {
|
|||
}
|
||||
|
||||
pub fn read(&self, v: DepNode<DefId>) {
|
||||
self.data.enqueue(DepMessage::Read(v));
|
||||
self.data.thread.enqueue(DepMessage::Read(v));
|
||||
}
|
||||
|
||||
pub fn write(&self, v: DepNode<DefId>) {
|
||||
self.data.enqueue(DepMessage::Write(v));
|
||||
self.data.thread.enqueue(DepMessage::Write(v));
|
||||
}
|
||||
|
||||
/// Indicates that a previous work product exists for `v`. This is
|
||||
/// invoked during initial start-up based on what nodes are clean
|
||||
/// (and what files exist in the incr. directory).
|
||||
pub fn insert_previous_work_product(&self, v: &Arc<WorkProductId>, data: WorkProduct) {
|
||||
debug!("insert_previous_work_product({:?}, {:?})", v, data);
|
||||
self.data.previous_work_products.borrow_mut()
|
||||
.insert(v.clone(), data);
|
||||
}
|
||||
|
||||
/// Indicates that we created the given work-product in this run
|
||||
/// for `v`. This record will be preserved and loaded in the next
|
||||
/// run.
|
||||
pub fn insert_work_product(&self, v: &Arc<WorkProductId>, data: WorkProduct) {
|
||||
debug!("insert_work_product({:?}, {:?})", v, data);
|
||||
self.data.work_products.borrow_mut()
|
||||
.insert(v.clone(), data);
|
||||
}
|
||||
|
||||
/// Check whether a previous work product exists for `v` and, if
|
||||
/// so, return the path that leads to it. Used to skip doing work.
|
||||
pub fn previous_work_product(&self, v: &Arc<WorkProductId>) -> Option<WorkProduct> {
|
||||
self.data.previous_work_products.borrow()
|
||||
.get(v)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// Access the map of work-products created during this run. Only
|
||||
/// used during saving of the dep-graph.
|
||||
pub fn work_products(&self) -> Ref<FnvHashMap<Arc<WorkProductId>, WorkProduct>> {
|
||||
self.data.work_products.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
/// A "work product" is an intermediate result that we save into the
|
||||
/// incremental directory for later re-use. The primary example are
|
||||
/// the object files that we save for each partition at code
|
||||
/// generation time.
|
||||
///
|
||||
/// Each work product is associated with a dep-node, representing the
|
||||
/// process that produced the work-product. If that dep-node is found
|
||||
/// to be dirty when we load up, then we will delete the work-product
|
||||
/// at load time. If the work-product is found to be clean, then we
|
||||
/// will keep a record in the `previous_work_products` list.
|
||||
///
|
||||
/// In addition, work products have an associated hash. This hash is
|
||||
/// an extra hash that can be used to decide if the work-product from
|
||||
/// a previous compilation can be re-used (in addition to the dirty
|
||||
/// edges check).
|
||||
///
|
||||
/// As the primary example, consider the object files we generate for
|
||||
/// each partition. In the first run, we create partitions based on
|
||||
/// the symbols that need to be compiled. For each partition P, we
|
||||
/// hash the symbols in P and create a `WorkProduct` record associated
|
||||
/// with `DepNode::TransPartition(P)`; the hash is the set of symbols
|
||||
/// in P.
|
||||
///
|
||||
/// The next time we compile, if the `DepNode::TransPartition(P)` is
|
||||
/// judged to be clean (which means none of the things we read to
|
||||
/// generate the partition were found to be dirty), it will be loaded
|
||||
/// into previous work products. We will then regenerate the set of
|
||||
/// symbols in the partition P and hash them (note that new symbols
|
||||
/// may be added -- for example, new monomorphizations -- even if
|
||||
/// nothing in P changed!). We will compare that hash against the
|
||||
/// previous hash. If it matches up, we can reuse the object file.
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct WorkProduct {
|
||||
/// Extra hash used to decide if work-product is still suitable;
|
||||
/// note that this is *not* a hash of the work-product itself.
|
||||
/// See documentation on `WorkProduct` type for an example.
|
||||
pub input_hash: u64,
|
||||
|
||||
/// Saved files associated with this CGU
|
||||
pub saved_files: Vec<(OutputType, String)>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ mod visit;
|
|||
|
||||
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
|
||||
pub use self::dep_node::DepNode;
|
||||
pub use self::dep_node::WorkProductId;
|
||||
pub use self::graph::DepGraph;
|
||||
pub use self::graph::WorkProduct;
|
||||
pub use self::query::DepGraphQuery;
|
||||
pub use self::visit::visit_all_items_in_krate;
|
||||
pub use self::raii::DepTask;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ code example:
|
|||
#[deny(const_err)]
|
||||
|
||||
const X: i32 = 42 / 0;
|
||||
// error: attempted to divide by zero in a constant expression
|
||||
// error: attempt to divide by zero in a constant expression
|
||||
```
|
||||
"##,
|
||||
|
||||
|
|
|
|||
|
|
@ -94,11 +94,14 @@ pub trait Visitor<'v> : Sized {
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn visit_id(&mut self, _node_id: NodeId) {
|
||||
// Nothing to do.
|
||||
}
|
||||
fn visit_name(&mut self, _span: Span, _name: Name) {
|
||||
// Nothing to do.
|
||||
}
|
||||
fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) {
|
||||
walk_mod(self, m)
|
||||
fn visit_mod(&mut self, m: &'v Mod, _s: Span, n: NodeId) {
|
||||
walk_mod(self, m, n)
|
||||
}
|
||||
fn visit_foreign_item(&mut self, i: &'v ForeignItem) {
|
||||
walk_foreign_item(self, i)
|
||||
|
|
@ -135,8 +138,8 @@ pub trait Visitor<'v> : Sized {
|
|||
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
|
||||
walk_where_predicate(self, predicate)
|
||||
}
|
||||
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) {
|
||||
walk_fn(self, fk, fd, b, s)
|
||||
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) {
|
||||
walk_fn(self, fk, fd, b, s, id)
|
||||
}
|
||||
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
|
||||
walk_trait_item(self, ti)
|
||||
|
|
@ -157,7 +160,7 @@ pub trait Visitor<'v> : Sized {
|
|||
s: &'v VariantData,
|
||||
_: Name,
|
||||
_: &'v Generics,
|
||||
_: NodeId,
|
||||
_parent_id: NodeId,
|
||||
_: Span) {
|
||||
walk_struct_def(self, s)
|
||||
}
|
||||
|
|
@ -225,24 +228,28 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
|
|||
}
|
||||
|
||||
pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) {
|
||||
visitor.visit_id(macro_def.id);
|
||||
visitor.visit_name(macro_def.span, macro_def.name);
|
||||
walk_opt_name(visitor, macro_def.span, macro_def.imported_from);
|
||||
walk_list!(visitor, visit_attribute, ¯o_def.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
|
||||
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_id: NodeId) {
|
||||
visitor.visit_id(mod_node_id);
|
||||
for &item_id in &module.item_ids {
|
||||
visitor.visit_nested_item(item_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
|
||||
visitor.visit_id(local.id);
|
||||
visitor.visit_pat(&local.pat);
|
||||
walk_list!(visitor, visit_ty, &local.ty);
|
||||
walk_list!(visitor, visit_expr, &local.init);
|
||||
}
|
||||
|
||||
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
|
||||
visitor.visit_id(lifetime.id);
|
||||
visitor.visit_name(lifetime.span, lifetime.name);
|
||||
}
|
||||
|
||||
|
|
@ -263,6 +270,7 @@ pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
|
|||
pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef)
|
||||
where V: Visitor<'v>
|
||||
{
|
||||
visitor.visit_id(trait_ref.ref_id);
|
||||
visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
|
||||
}
|
||||
|
||||
|
|
@ -271,9 +279,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
visitor.visit_name(item.span, item.name);
|
||||
match item.node {
|
||||
ItemExternCrate(opt_name) => {
|
||||
visitor.visit_id(item.id);
|
||||
walk_opt_name(visitor, item.span, opt_name)
|
||||
}
|
||||
ItemUse(ref vp) => {
|
||||
visitor.visit_id(item.id);
|
||||
match vp.node {
|
||||
ViewPathSimple(name, ref path) => {
|
||||
visitor.visit_name(vp.span, name);
|
||||
|
|
@ -292,6 +302,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
}
|
||||
ItemStatic(ref typ, _, ref expr) |
|
||||
ItemConst(ref typ, ref expr) => {
|
||||
visitor.visit_id(item.id);
|
||||
visitor.visit_ty(typ);
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
|
|
@ -309,23 +320,29 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
item.id)
|
||||
}
|
||||
ItemMod(ref module) => {
|
||||
// visit_mod() takes care of visiting the Item's NodeId
|
||||
visitor.visit_mod(module, item.span, item.id)
|
||||
}
|
||||
ItemForeignMod(ref foreign_module) => {
|
||||
visitor.visit_id(item.id);
|
||||
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
|
||||
}
|
||||
ItemTy(ref typ, ref type_parameters) => {
|
||||
visitor.visit_id(item.id);
|
||||
visitor.visit_ty(typ);
|
||||
visitor.visit_generics(type_parameters)
|
||||
}
|
||||
ItemEnum(ref enum_definition, ref type_parameters) => {
|
||||
visitor.visit_generics(type_parameters);
|
||||
// visit_enum_def() takes care of visiting the Item's NodeId
|
||||
visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
|
||||
}
|
||||
ItemDefaultImpl(_, ref trait_ref) => {
|
||||
visitor.visit_id(item.id);
|
||||
visitor.visit_trait_ref(trait_ref)
|
||||
}
|
||||
ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
|
||||
visitor.visit_id(item.id);
|
||||
visitor.visit_generics(type_parameters);
|
||||
walk_list!(visitor, visit_trait_ref, opt_trait_reference);
|
||||
visitor.visit_ty(typ);
|
||||
|
|
@ -333,9 +350,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
}
|
||||
ItemStruct(ref struct_definition, ref generics) => {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_id(item.id);
|
||||
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
|
||||
}
|
||||
ItemTrait(_, ref generics, ref bounds, ref methods) => {
|
||||
visitor.visit_id(item.id);
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_ty_param_bound, bounds);
|
||||
walk_list!(visitor, visit_trait_item, methods);
|
||||
|
|
@ -348,6 +367,7 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
enum_definition: &'v EnumDef,
|
||||
generics: &'v Generics,
|
||||
item_id: NodeId) {
|
||||
visitor.visit_id(item_id);
|
||||
walk_list!(visitor,
|
||||
visit_variant,
|
||||
&enum_definition.variants,
|
||||
|
|
@ -358,18 +378,20 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||
variant: &'v Variant,
|
||||
generics: &'v Generics,
|
||||
item_id: NodeId) {
|
||||
parent_item_id: NodeId) {
|
||||
visitor.visit_name(variant.span, variant.node.name);
|
||||
visitor.visit_variant_data(&variant.node.data,
|
||||
variant.node.name,
|
||||
generics,
|
||||
item_id,
|
||||
parent_item_id,
|
||||
variant.span);
|
||||
walk_list!(visitor, visit_expr, &variant.node.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.node.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
|
||||
visitor.visit_id(typ.id);
|
||||
|
||||
match typ.node {
|
||||
TyVec(ref ty) => {
|
||||
visitor.visit_ty(ty)
|
||||
|
|
@ -421,6 +443,7 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
|
|||
pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||
_prefix: &'v Path,
|
||||
item: &'v PathListItem) {
|
||||
visitor.visit_id(item.node.id());
|
||||
walk_opt_name(visitor, item.span, item.node.name());
|
||||
walk_opt_name(visitor, item.span, item.node.rename());
|
||||
}
|
||||
|
|
@ -450,11 +473,13 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
|
||||
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||
type_binding: &'v TypeBinding) {
|
||||
visitor.visit_id(type_binding.id);
|
||||
visitor.visit_name(type_binding.span, type_binding.name);
|
||||
visitor.visit_ty(&type_binding.ty);
|
||||
}
|
||||
|
||||
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||
visitor.visit_id(pattern.id);
|
||||
match pattern.node {
|
||||
PatKind::TupleStruct(ref path, ref children, _) => {
|
||||
visitor.visit_path(path, pattern.id);
|
||||
|
|
@ -499,6 +524,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
|||
}
|
||||
|
||||
pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) {
|
||||
visitor.visit_id(foreign_item.id);
|
||||
visitor.visit_vis(&foreign_item.vis);
|
||||
visitor.visit_name(foreign_item.span, foreign_item.name);
|
||||
|
||||
|
|
@ -526,11 +552,13 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyPar
|
|||
|
||||
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
|
||||
for param in &generics.ty_params {
|
||||
visitor.visit_id(param.id);
|
||||
visitor.visit_name(param.span, param.name);
|
||||
walk_list!(visitor, visit_ty_param_bound, ¶m.bounds);
|
||||
walk_list!(visitor, visit_ty, ¶m.default);
|
||||
}
|
||||
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
|
||||
visitor.visit_id(generics.where_clause.id);
|
||||
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
|
||||
}
|
||||
|
||||
|
|
@ -557,6 +585,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
|
|||
ref path,
|
||||
ref ty,
|
||||
..}) => {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_path(path, id);
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
|
|
@ -571,6 +600,7 @@ pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionR
|
|||
|
||||
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
|
||||
for argument in &function_declaration.inputs {
|
||||
visitor.visit_id(argument.id);
|
||||
visitor.visit_pat(&argument.pat);
|
||||
visitor.visit_ty(&argument.ty)
|
||||
}
|
||||
|
|
@ -579,6 +609,7 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &
|
|||
|
||||
pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
|
||||
for argument in &function_declaration.inputs {
|
||||
visitor.visit_id(argument.id);
|
||||
visitor.visit_ty(&argument.ty)
|
||||
}
|
||||
walk_fn_ret_ty(visitor, &function_declaration.output)
|
||||
|
|
@ -600,7 +631,9 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
function_kind: FnKind<'v>,
|
||||
function_declaration: &'v FnDecl,
|
||||
function_body: &'v Block,
|
||||
_span: Span) {
|
||||
_span: Span,
|
||||
id: NodeId) {
|
||||
visitor.visit_id(id);
|
||||
walk_fn_decl(visitor, function_declaration);
|
||||
walk_fn_kind(visitor, function_kind);
|
||||
visitor.visit_block(function_body)
|
||||
|
|
@ -611,10 +644,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
|
|||
walk_list!(visitor, visit_attribute, &trait_item.attrs);
|
||||
match trait_item.node {
|
||||
ConstTraitItem(ref ty, ref default) => {
|
||||
visitor.visit_id(trait_item.id);
|
||||
visitor.visit_ty(ty);
|
||||
walk_list!(visitor, visit_expr, default);
|
||||
}
|
||||
MethodTraitItem(ref sig, None) => {
|
||||
visitor.visit_id(trait_item.id);
|
||||
visitor.visit_generics(&sig.generics);
|
||||
walk_fn_decl(visitor, &sig.decl);
|
||||
}
|
||||
|
|
@ -629,6 +664,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
|
|||
trait_item.id);
|
||||
}
|
||||
TypeTraitItem(ref bounds, ref default) => {
|
||||
visitor.visit_id(trait_item.id);
|
||||
walk_list!(visitor, visit_ty_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, default);
|
||||
}
|
||||
|
|
@ -641,6 +677,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
|
|||
walk_list!(visitor, visit_attribute, &impl_item.attrs);
|
||||
match impl_item.node {
|
||||
ImplItemKind::Const(ref ty, ref expr) => {
|
||||
visitor.visit_id(impl_item.id);
|
||||
visitor.visit_ty(ty);
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
|
|
@ -655,16 +692,19 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
|
|||
impl_item.id);
|
||||
}
|
||||
ImplItemKind::Type(ref ty) => {
|
||||
visitor.visit_id(impl_item.id);
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
|
||||
visitor.visit_id(struct_definition.id());
|
||||
walk_list!(visitor, visit_struct_field, struct_definition.fields());
|
||||
}
|
||||
|
||||
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {
|
||||
visitor.visit_id(struct_field.id);
|
||||
visitor.visit_vis(&struct_field.vis);
|
||||
visitor.visit_name(struct_field.span, struct_field.name);
|
||||
visitor.visit_ty(&struct_field.ty);
|
||||
|
|
@ -672,14 +712,20 @@ pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v
|
|||
}
|
||||
|
||||
pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) {
|
||||
visitor.visit_id(block.id);
|
||||
walk_list!(visitor, visit_stmt, &block.stmts);
|
||||
walk_list!(visitor, visit_expr, &block.expr);
|
||||
}
|
||||
|
||||
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
|
||||
match statement.node {
|
||||
StmtDecl(ref declaration, _) => visitor.visit_decl(declaration),
|
||||
StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => {
|
||||
StmtDecl(ref declaration, id) => {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_decl(declaration)
|
||||
}
|
||||
StmtExpr(ref expression, id) |
|
||||
StmtSemi(ref expression, id) => {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_expr(expression)
|
||||
}
|
||||
}
|
||||
|
|
@ -693,6 +739,7 @@ pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
|
|||
}
|
||||
|
||||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
visitor.visit_id(expression.id);
|
||||
match expression.node {
|
||||
ExprBox(ref subexpression) => {
|
||||
visitor.visit_expr(subexpression)
|
||||
|
|
@ -815,11 +862,12 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
|
|||
|
||||
pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
|
||||
if let Visibility::Restricted { ref path, id } = *vis {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_path(path, id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
|
||||
pub struct IdRange {
|
||||
pub min: NodeId,
|
||||
pub max: NodeId,
|
||||
|
|
@ -837,15 +885,17 @@ impl IdRange {
|
|||
self.min >= self.max
|
||||
}
|
||||
|
||||
pub fn contains(&self, id: NodeId) -> bool {
|
||||
id >= self.min && id < self.max
|
||||
}
|
||||
|
||||
pub fn add(&mut self, id: NodeId) {
|
||||
self.min = cmp::min(self.min, id);
|
||||
self.max = cmp::max(self.max, id + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub trait IdVisitingOperation {
|
||||
fn visit_id(&mut self, node_id: NodeId);
|
||||
}
|
||||
|
||||
pub struct IdRangeComputingVisitor {
|
||||
pub result: IdRange,
|
||||
|
|
@ -861,181 +911,12 @@ impl IdRangeComputingVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
impl IdVisitingOperation for IdRangeComputingVisitor {
|
||||
impl<'v> Visitor<'v> for IdRangeComputingVisitor {
|
||||
fn visit_id(&mut self, id: NodeId) {
|
||||
self.result.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IdVisitor<'a, O: 'a> {
|
||||
operation: &'a mut O,
|
||||
|
||||
// In general, the id visitor visits the contents of an item, but
|
||||
// not including nested trait/impl items, nor other nested items.
|
||||
// The base visitor itself always skips nested items, but not
|
||||
// trait/impl items. This means in particular that if you start by
|
||||
// visiting a trait or an impl, you should not visit the
|
||||
// trait/impl items respectively. This is handled by setting
|
||||
// `skip_members` to true when `visit_item` is on the stack. This
|
||||
// way, if the user begins by calling `visit_trait_item`, we will
|
||||
// visit the trait item, but if they begin with `visit_item`, we
|
||||
// won't visit the (nested) trait items.
|
||||
skip_members: bool,
|
||||
}
|
||||
|
||||
impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
|
||||
pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> {
|
||||
IdVisitor { operation: operation, skip_members: false }
|
||||
}
|
||||
|
||||
fn visit_generics_helper(&mut self, generics: &Generics) {
|
||||
for type_parameter in generics.ty_params.iter() {
|
||||
self.operation.visit_id(type_parameter.id)
|
||||
}
|
||||
for lifetime in &generics.lifetimes {
|
||||
self.operation.visit_id(lifetime.lifetime.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
|
||||
fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) {
|
||||
self.operation.visit_id(node_id);
|
||||
walk_mod(self, module)
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
|
||||
self.operation.visit_id(foreign_item.id);
|
||||
walk_foreign_item(self, foreign_item)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &Item) {
|
||||
assert!(!self.skip_members);
|
||||
self.skip_members = true;
|
||||
|
||||
self.operation.visit_id(item.id);
|
||||
match item.node {
|
||||
ItemUse(ref view_path) => {
|
||||
match view_path.node {
|
||||
ViewPathSimple(_, _) |
|
||||
ViewPathGlob(_) => {}
|
||||
ViewPathList(_, ref paths) => {
|
||||
for path in paths {
|
||||
self.operation.visit_id(path.node.id())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
walk_item(self, item);
|
||||
|
||||
self.skip_members = false;
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: &Local) {
|
||||
self.operation.visit_id(local.id);
|
||||
walk_local(self, local)
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &Block) {
|
||||
self.operation.visit_id(block.id);
|
||||
walk_block(self, block)
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, statement: &Stmt) {
|
||||
self.operation.visit_id(statement.node.id());
|
||||
walk_stmt(self, statement)
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pattern: &Pat) {
|
||||
self.operation.visit_id(pattern.id);
|
||||
walk_pat(self, pattern)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expression: &Expr) {
|
||||
self.operation.visit_id(expression.id);
|
||||
walk_expr(self, expression)
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, typ: &Ty) {
|
||||
self.operation.visit_id(typ.id);
|
||||
walk_ty(self, typ)
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &Generics) {
|
||||
self.visit_generics_helper(generics);
|
||||
walk_generics(self, generics)
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self,
|
||||
function_kind: FnKind<'v>,
|
||||
function_declaration: &'v FnDecl,
|
||||
block: &'v Block,
|
||||
span: Span,
|
||||
node_id: NodeId) {
|
||||
self.operation.visit_id(node_id);
|
||||
|
||||
match function_kind {
|
||||
FnKind::ItemFn(_, generics, _, _, _, _, _) => {
|
||||
self.visit_generics_helper(generics)
|
||||
}
|
||||
FnKind::Method(_, sig, _, _) => {
|
||||
self.visit_generics_helper(&sig.generics)
|
||||
}
|
||||
FnKind::Closure(_) => {}
|
||||
}
|
||||
|
||||
for argument in &function_declaration.inputs {
|
||||
self.operation.visit_id(argument.id)
|
||||
}
|
||||
|
||||
walk_fn(self, function_kind, function_declaration, block, span);
|
||||
}
|
||||
|
||||
fn visit_struct_field(&mut self, struct_field: &StructField) {
|
||||
self.operation.visit_id(struct_field.id);
|
||||
walk_struct_field(self, struct_field)
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self,
|
||||
struct_def: &VariantData,
|
||||
_: Name,
|
||||
_: &Generics,
|
||||
_: NodeId,
|
||||
_: Span) {
|
||||
self.operation.visit_id(struct_def.id());
|
||||
walk_struct_def(self, struct_def);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &TraitItem) {
|
||||
if !self.skip_members {
|
||||
self.operation.visit_id(ti.id);
|
||||
walk_trait_item(self, ti);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &ImplItem) {
|
||||
if !self.skip_members {
|
||||
self.operation.visit_id(ii.id);
|
||||
walk_impl_item(self, ii);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &Lifetime) {
|
||||
self.operation.visit_id(lifetime.id);
|
||||
}
|
||||
|
||||
fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
|
||||
self.visit_lifetime(&def.lifetime);
|
||||
}
|
||||
|
||||
fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
|
||||
self.operation.visit_id(trait_ref.ref_id);
|
||||
walk_trait_ref(self, trait_ref);
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the id range for a single fn body, ignoring nested items.
|
||||
pub fn compute_id_range_for_fn_body(fk: FnKind,
|
||||
decl: &FnDecl,
|
||||
|
|
@ -1043,8 +924,7 @@ pub fn compute_id_range_for_fn_body(fk: FnKind,
|
|||
sp: Span,
|
||||
id: NodeId)
|
||||
-> IdRange {
|
||||
let mut visitor = IdRangeComputingVisitor { result: IdRange::max() };
|
||||
let mut id_visitor = IdVisitor::new(&mut visitor);
|
||||
id_visitor.visit_fn(fk, decl, body, sp, id);
|
||||
id_visitor.operation.result
|
||||
let mut visitor = IdRangeComputingVisitor::new();
|
||||
visitor.visit_fn(fk, decl, body, sp, id);
|
||||
visitor.result()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
|||
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
|
||||
b: &'ast Block, s: Span, id: NodeId) {
|
||||
assert_eq!(self.parent_node, id);
|
||||
intravisit::walk_fn(self, fk, fd, b, s);
|
||||
intravisit::walk_fn(self, fk, fd, b, s, id);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &'ast Block) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ use hir::print as pprust;
|
|||
|
||||
use arena::TypedArena;
|
||||
use std::cell::RefCell;
|
||||
use std::cmp;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
|
||||
|
|
@ -127,7 +128,10 @@ impl<'ast> MapEntry<'ast> {
|
|||
EntryStructCtor(id, _) => id,
|
||||
EntryLifetime(id, _) => id,
|
||||
EntryTyParam(id, _) => id,
|
||||
_ => return None
|
||||
|
||||
NotPresent |
|
||||
RootCrate |
|
||||
RootInlinedParent(_) => return None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -196,6 +200,10 @@ pub struct Map<'ast> {
|
|||
map: RefCell<Vec<MapEntry<'ast>>>,
|
||||
|
||||
definitions: RefCell<Definitions>,
|
||||
|
||||
/// All NodeIds that are numerically greater or equal to this value come
|
||||
/// from inlined items.
|
||||
local_node_id_watermark: NodeId,
|
||||
}
|
||||
|
||||
impl<'ast> Map<'ast> {
|
||||
|
|
@ -550,6 +558,13 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
|
||||
match self.find_entry(id) {
|
||||
Some(RootInlinedParent(inlined_item)) => inlined_item,
|
||||
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name associated with the given NodeId's AST.
|
||||
pub fn name(&self, id: NodeId) -> Name {
|
||||
match self.get(id) {
|
||||
|
|
@ -649,6 +664,10 @@ impl<'ast> Map<'ast> {
|
|||
pub fn node_to_user_string(&self, id: NodeId) -> String {
|
||||
node_id_to_string(self, id, false)
|
||||
}
|
||||
|
||||
pub fn is_inlined(&self, id: NodeId) -> bool {
|
||||
id >= self.local_node_id_watermark
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
|
||||
|
|
@ -765,13 +784,37 @@ pub trait FoldOps {
|
|||
}
|
||||
|
||||
/// A Folder that updates IDs and Span's according to fold_ops.
|
||||
struct IdAndSpanUpdater<F> {
|
||||
fold_ops: F
|
||||
pub struct IdAndSpanUpdater<F> {
|
||||
fold_ops: F,
|
||||
min_id_assigned: NodeId,
|
||||
max_id_assigned: NodeId,
|
||||
}
|
||||
|
||||
impl<F: FoldOps> IdAndSpanUpdater<F> {
|
||||
pub fn new(fold_ops: F) -> IdAndSpanUpdater<F> {
|
||||
IdAndSpanUpdater {
|
||||
fold_ops: fold_ops,
|
||||
min_id_assigned: ::std::u32::MAX,
|
||||
max_id_assigned: ::std::u32::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id_range(&self) -> intravisit::IdRange {
|
||||
intravisit::IdRange {
|
||||
min: self.min_id_assigned,
|
||||
max: self.max_id_assigned + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
|
||||
fn new_id(&mut self, id: NodeId) -> NodeId {
|
||||
self.fold_ops.new_id(id)
|
||||
let id = self.fold_ops.new_id(id);
|
||||
|
||||
self.min_id_assigned = cmp::min(self.min_id_assigned, id);
|
||||
self.max_id_assigned = cmp::max(self.max_id_assigned, id);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
fn new_span(&mut self, span: Span) -> Span {
|
||||
|
|
@ -802,11 +845,14 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
|
|||
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
|
||||
}
|
||||
|
||||
let local_node_id_watermark = map.len() as NodeId;
|
||||
|
||||
Map {
|
||||
forest: forest,
|
||||
dep_graph: forest.dep_graph.clone(),
|
||||
map: RefCell::new(map),
|
||||
definitions: RefCell::new(definitions),
|
||||
local_node_id_watermark: local_node_id_watermark
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -818,7 +864,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
|
|||
ii: InlinedItem,
|
||||
fold_ops: F)
|
||||
-> &'ast InlinedItem {
|
||||
let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
|
||||
let mut fld = IdAndSpanUpdater::new(fold_ops);
|
||||
let ii = match ii {
|
||||
II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
|
||||
II::TraitItem(d, ti) => {
|
||||
|
|
@ -835,6 +881,12 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
|
|||
let ii = map.forest.inlined_items.alloc(ii);
|
||||
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
|
||||
|
||||
// Assert that the ii_parent_id is the last NodeId in our reserved range
|
||||
assert!(ii_parent_id == fld.max_id_assigned);
|
||||
// Assert that we did not violate the invariant that all inlined HIR items
|
||||
// have NodeIds greater than or equal to `local_node_id_watermark`
|
||||
assert!(fld.min_id_assigned >= map.local_node_id_watermark);
|
||||
|
||||
let defs = &mut *map.definitions.borrow_mut();
|
||||
let mut def_collector = DefCollector::extend(ii_parent_id,
|
||||
parent_def_path.clone(),
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use hir::def::Def;
|
|||
use hir::def_id::DefId;
|
||||
use util::nodemap::{NodeMap, FnvHashSet};
|
||||
|
||||
use syntax_pos::{mk_sp, Span, ExpnId};
|
||||
use syntax_pos::{BytePos, mk_sp, Span, ExpnId};
|
||||
use syntax::codemap::{self, respan, Spanned};
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
|
||||
|
|
@ -326,6 +326,38 @@ impl Generics {
|
|||
pub fn is_parameterized(&self) -> bool {
|
||||
self.is_lt_parameterized() || self.is_type_parameterized()
|
||||
}
|
||||
|
||||
// Does return a span which includes lifetimes and type parameters,
|
||||
// not where clause.
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
if !self.is_parameterized() {
|
||||
None
|
||||
} else {
|
||||
let mut span: Option<Span> = None;
|
||||
for lifetime in self.lifetimes.iter() {
|
||||
if let Some(ref mut span) = span {
|
||||
let life_span = lifetime.lifetime.span;
|
||||
span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi };
|
||||
span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo };
|
||||
} else {
|
||||
span = Some(lifetime.lifetime.span.clone());
|
||||
}
|
||||
}
|
||||
for ty_param in self.ty_params.iter() {
|
||||
if let Some(ref mut span) = span {
|
||||
span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo };
|
||||
span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi };
|
||||
} else {
|
||||
span = Some(ty_param.span.clone());
|
||||
}
|
||||
}
|
||||
if let Some(ref mut span) = span {
|
||||
span.lo = span.lo - BytePos(1);
|
||||
span.hi = span.hi + BytePos(1);
|
||||
}
|
||||
span
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `where` clause in a definition
|
||||
|
|
@ -1362,9 +1394,9 @@ pub enum ViewPath_ {
|
|||
/// TraitRef's appear in impls.
|
||||
///
|
||||
/// resolve maps each TraitRef's ref_id to its defining trait; that's all
|
||||
/// that the ref_id is for. The impl_id maps to the "self type" of this impl.
|
||||
/// If this impl is an ItemImpl, the impl_id is redundant (it could be the
|
||||
/// same as the impl's node id).
|
||||
/// that the ref_id is for. Note that ref_id's value is not the NodeId of the
|
||||
/// trait being referred to but just a unique NodeId that serves as a key
|
||||
/// within the DefMap.
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct TraitRef {
|
||||
pub path: Path,
|
||||
|
|
|
|||
|
|
@ -32,22 +32,27 @@ use ty::{self, Ty, TyCtxt};
|
|||
use ty::TyVar;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
|
||||
pub struct Bivariate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'gcx, 'tcx>
|
||||
pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Bivariate<'a, 'gcx, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Bivariate<'a, 'gcx, 'tcx> {
|
||||
Bivariate { fields: fields }
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> {
|
||||
pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
|
||||
-> Bivariate<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
Bivariate { fields: fields, a_is_expected: a_is_expected }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
for Bivariate<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn tag(&self) -> &'static str { "Bivariate" }
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
|
||||
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
|
||||
fn a_is_expected(&self) -> bool { self.a_is_expected }
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
|
||||
variance: ty::Variance,
|
||||
|
|
@ -86,12 +91,12 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx>
|
|||
}
|
||||
|
||||
(&ty::TyInfer(TyVar(a_id)), _) => {
|
||||
self.fields.instantiate(b, BiTo, a_id)?;
|
||||
self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(_, &ty::TyInfer(TyVar(b_id))) => {
|
||||
self.fields.instantiate(a, BiTo, b_id)?;
|
||||
self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,21 +52,20 @@ use syntax::ast;
|
|||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
pub a_is_expected: bool,
|
||||
pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>,
|
||||
pub trace: TypeTrace<'tcx>,
|
||||
pub cause: Option<ty::relate::Cause>,
|
||||
pub obligations: PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
|
||||
pub fn super_combine_tys<R>(&self,
|
||||
relation: &mut R,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> RelateResult<'tcx, Ty<'tcx>>
|
||||
where R: TypeRelation<'a, 'gcx, 'tcx>
|
||||
where R: TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
let a_is_expected = relation.a_is_expected();
|
||||
|
||||
|
|
@ -150,42 +149,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
|
||||
pub fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn switch_expected(&self) -> CombineFields<'a, 'gcx, 'tcx> {
|
||||
CombineFields {
|
||||
a_is_expected: !self.a_is_expected,
|
||||
..(*self).clone()
|
||||
}
|
||||
pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> {
|
||||
Equate::new(self, a_is_expected)
|
||||
}
|
||||
|
||||
pub fn equate(&self) -> Equate<'a, 'gcx, 'tcx> {
|
||||
Equate::new(self.clone())
|
||||
pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> {
|
||||
Bivariate::new(self, a_is_expected)
|
||||
}
|
||||
|
||||
pub fn bivariate(&self) -> Bivariate<'a, 'gcx, 'tcx> {
|
||||
Bivariate::new(self.clone())
|
||||
pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> {
|
||||
Sub::new(self, a_is_expected)
|
||||
}
|
||||
|
||||
pub fn sub(&self) -> Sub<'a, 'gcx, 'tcx> {
|
||||
Sub::new(self.clone())
|
||||
pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> {
|
||||
Lub::new(self, a_is_expected)
|
||||
}
|
||||
|
||||
pub fn lub(&self) -> Lub<'a, 'gcx, 'tcx> {
|
||||
Lub::new(self.clone())
|
||||
pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> {
|
||||
Glb::new(self, a_is_expected)
|
||||
}
|
||||
|
||||
pub fn glb(&self) -> Glb<'a, 'gcx, 'tcx> {
|
||||
Glb::new(self.clone())
|
||||
}
|
||||
|
||||
pub fn instantiate(&self,
|
||||
pub fn instantiate(&mut self,
|
||||
a_ty: Ty<'tcx>,
|
||||
dir: RelationDir,
|
||||
b_vid: ty::TyVid)
|
||||
b_vid: ty::TyVid,
|
||||
a_is_expected: bool)
|
||||
-> RelateResult<'tcx, ()>
|
||||
{
|
||||
let mut stack = Vec::new();
|
||||
|
|
@ -255,10 +248,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
// to associate causes/spans with each of the relations in
|
||||
// the stack to get this right.
|
||||
match dir {
|
||||
BiTo => self.bivariate().relate(&a_ty, &b_ty),
|
||||
EqTo => self.equate().relate(&a_ty, &b_ty),
|
||||
SubtypeOf => self.sub().relate(&a_ty, &b_ty),
|
||||
SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
|
||||
BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty),
|
||||
EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty),
|
||||
SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty),
|
||||
SupertypeOf => self.sub(a_is_expected).relate_with_variance(
|
||||
ty::Contravariant, &a_ty, &b_ty),
|
||||
}?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,29 +15,29 @@ use super::type_variable::{EqTo};
|
|||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::TyVar;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use traits::PredicateObligations;
|
||||
|
||||
/// Ensures `a` is made equal to `b`. Returns `a` on success.
|
||||
pub struct Equate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'gcx, 'tcx>
|
||||
pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Equate<'a, 'gcx, 'tcx> {
|
||||
Equate { fields: fields }
|
||||
}
|
||||
|
||||
pub fn obligations(self) -> PredicateObligations<'tcx> {
|
||||
self.fields.obligations
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> {
|
||||
pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
|
||||
-> Equate<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
Equate { fields: fields, a_is_expected: a_is_expected }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
for Equate<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn tag(&self) -> &'static str { "Equate" }
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
|
||||
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
|
||||
fn a_is_expected(&self) -> bool { self.a_is_expected }
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
|
||||
_: ty::Variance,
|
||||
|
|
@ -63,12 +63,12 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
(&ty::TyInfer(TyVar(a_id)), _) => {
|
||||
self.fields.instantiate(b, EqTo, a_id)?;
|
||||
self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(_, &ty::TyInfer(TyVar(b_id))) => {
|
||||
self.fields.instantiate(a, EqTo, b_id)?;
|
||||
self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, ty::Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
self.fields.higher_ranked_sub(a, b)?;
|
||||
self.fields.higher_ranked_sub(b, a)
|
||||
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
|
||||
self.fields.higher_ranked_sub(b, a, self.a_is_expected)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ use hir::def_id::DefId;
|
|||
use infer::{self, TypeOrigin};
|
||||
use middle::region;
|
||||
use ty::subst;
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::{self, TyCtxt, TypeFoldable};
|
||||
use ty::{Region, ReFree};
|
||||
use ty::error::TypeError;
|
||||
|
||||
|
|
@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn report_type_error(&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: &TypeError<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx> {
|
||||
let (expected, found) = match self.values_str(&trace.values) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
|
||||
}
|
||||
};
|
||||
|
||||
let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
|
||||
values.expected.is_primitive() && values.found.is_primitive()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
trace.origin.span(),
|
||||
E0308,
|
||||
"{}",
|
||||
trace.origin);
|
||||
|
||||
if !is_simple_error || check_old_school() {
|
||||
err.note_expected_found(&"type", &expected, &found);
|
||||
}
|
||||
|
||||
err.span_label(trace.origin.span(), &terr);
|
||||
|
||||
self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
|
||||
|
||||
match trace.origin {
|
||||
TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
|
||||
hir::MatchSource::IfLetDesugar{..} => {
|
||||
err.span_note(arm_span, "`if let` arm with an incompatible type");
|
||||
}
|
||||
_ => {
|
||||
err.span_note(arm_span, "match arm with an incompatible type");
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
/// Adds a note if the types come from similarly named crates
|
||||
fn check_and_note_conflicting_crates(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
|
|
@ -550,42 +504,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn note_error_origin(&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
origin: &TypeOrigin)
|
||||
{
|
||||
match origin {
|
||||
&TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
|
||||
hir::MatchSource::IfLetDesugar {..} => {
|
||||
err.span_note(arm_span, "`if let` arm with an incompatible type");
|
||||
}
|
||||
_ => {
|
||||
err.span_note(arm_span, "match arm with an incompatible type");
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn note_type_err(&self,
|
||||
diag: &mut DiagnosticBuilder<'tcx>,
|
||||
origin: TypeOrigin,
|
||||
values: Option<ValuePairs<'tcx>>,
|
||||
terr: &TypeError<'tcx>)
|
||||
{
|
||||
let expected_found = match values {
|
||||
None => None,
|
||||
Some(values) => match self.values_str(&values) {
|
||||
Some((expected, found)) => Some((expected, found)),
|
||||
None => {
|
||||
// Derived error. Cancel the emitter.
|
||||
self.tcx.sess.diagnostic().cancel(diag);
|
||||
return
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let span = origin.span();
|
||||
|
||||
let mut is_simple_error = false;
|
||||
|
||||
if let Some((expected, found)) = expected_found {
|
||||
is_simple_error = if let &TypeError::Sorts(ref values) = terr {
|
||||
values.expected.is_primitive() && values.found.is_primitive()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !is_simple_error || check_old_school() {
|
||||
diag.note_expected_found(&"type", &expected, &found);
|
||||
}
|
||||
}
|
||||
|
||||
if !is_simple_error && check_old_school() {
|
||||
diag.span_note(span, &format!("{}", terr));
|
||||
} else {
|
||||
diag.span_label(span, &terr);
|
||||
}
|
||||
|
||||
self.note_error_origin(diag, &origin);
|
||||
self.check_and_note_conflicting_crates(diag, terr, span);
|
||||
self.tcx.note_and_explain_type_err(diag, terr, span);
|
||||
}
|
||||
|
||||
pub fn report_and_explain_type_error(&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: &TypeError<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx> {
|
||||
let span = trace.origin.span();
|
||||
let mut err = self.report_type_error(trace, terr);
|
||||
self.tcx.note_and_explain_type_err(&mut err, terr, span);
|
||||
err
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
// FIXME: do we want to use a different error code for each origin?
|
||||
let mut diag = struct_span_err!(
|
||||
self.tcx.sess, trace.origin.span(), E0308,
|
||||
"{}", trace.origin.as_failure_str()
|
||||
);
|
||||
self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
|
||||
diag
|
||||
}
|
||||
|
||||
/// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
|
||||
/// error.
|
||||
/// Returns a string of the form "expected `{}`, found `{}`".
|
||||
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
|
||||
match *values {
|
||||
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
|
||||
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
||||
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
|
||||
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
|
||||
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
exp_found: &ty::error::ExpectedFound<T>)
|
||||
-> Option<(String, String)>
|
||||
{
|
||||
let expected = exp_found.expected.resolve(self);
|
||||
if expected.references_error() {
|
||||
let exp_found = self.resolve_type_vars_if_possible(exp_found);
|
||||
if exp_found.references_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let found = exp_found.found.resolve(self);
|
||||
if found.references_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((format!("{}", expected), format!("{}", found)))
|
||||
Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
|
||||
}
|
||||
|
||||
fn report_generic_bound_failure(&self,
|
||||
|
|
@ -1608,59 +1622,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
|
||||
match *origin {
|
||||
infer::Subtype(ref trace) => {
|
||||
let desc = match trace.origin {
|
||||
TypeOrigin::Misc(_) => {
|
||||
"types are compatible"
|
||||
}
|
||||
TypeOrigin::MethodCompatCheck(_) => {
|
||||
"method type is compatible with trait"
|
||||
}
|
||||
TypeOrigin::ExprAssignable(_) => {
|
||||
"expression is assignable"
|
||||
}
|
||||
TypeOrigin::RelateTraitRefs(_) => {
|
||||
"traits are compatible"
|
||||
}
|
||||
TypeOrigin::RelateSelfType(_) => {
|
||||
"self type matches impl self type"
|
||||
}
|
||||
TypeOrigin::RelateOutputImplTypes(_) => {
|
||||
"trait type parameters matches those \
|
||||
specified on the impl"
|
||||
}
|
||||
TypeOrigin::MatchExpressionArm(_, _, _) => {
|
||||
"match arms have compatible types"
|
||||
}
|
||||
TypeOrigin::IfExpression(_) => {
|
||||
"if and else have compatible types"
|
||||
}
|
||||
TypeOrigin::IfExpressionWithNoElse(_) => {
|
||||
"if may be missing an else clause"
|
||||
}
|
||||
TypeOrigin::RangeExpression(_) => {
|
||||
"start and end of range have compatible types"
|
||||
}
|
||||
TypeOrigin::EquatePredicate(_) => {
|
||||
"equality where clause is satisfied"
|
||||
}
|
||||
};
|
||||
if let Some((expected, found)) = self.values_str(&trace.values) {
|
||||
// FIXME: do we want a "the" here?
|
||||
err.span_note(
|
||||
trace.origin.span(),
|
||||
&format!("...so that {} (expected {}, found {})",
|
||||
trace.origin.as_requirement_str(), expected, found));
|
||||
} else {
|
||||
// FIXME: this really should be handled at some earlier stage. Our
|
||||
// handling of region checking when type errors are present is
|
||||
// *terrible*.
|
||||
|
||||
match self.values_str(&trace.values) {
|
||||
Some((expected, found)) => {
|
||||
err.span_note(
|
||||
trace.origin.span(),
|
||||
&format!("...so that {} (expected {}, found {})",
|
||||
desc, expected, found));
|
||||
}
|
||||
None => {
|
||||
// Really should avoid printing this error at
|
||||
// all, since it is derived, but that would
|
||||
// require more refactoring than I feel like
|
||||
// doing right now. - nmatsakis
|
||||
err.span_note(
|
||||
trace.origin.span(),
|
||||
&format!("...so that {}", desc));
|
||||
}
|
||||
err.span_note(
|
||||
trace.origin.span(),
|
||||
&format!("...so that {}",
|
||||
trace.origin.as_requirement_str()));
|
||||
}
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
|
|
@ -1803,32 +1779,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Resolvable<'tcx> {
|
||||
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
|
||||
}
|
||||
|
||||
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
|
||||
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||
infcx.resolve_type_vars_if_possible(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
|
||||
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
|
||||
-> ty::TraitRef<'tcx> {
|
||||
infcx.resolve_type_vars_if_possible(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
|
||||
fn resolve<'a, 'gcx>(&self,
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
infcx.resolve_type_vars_if_possible(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
scope_id: ast::NodeId)
|
||||
-> Vec<hir::LifetimeDef> {
|
||||
|
|
|
|||
|
|
@ -15,29 +15,29 @@ use super::Subtype;
|
|||
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use traits::PredicateObligations;
|
||||
|
||||
/// "Greatest lower bound" (common subtype)
|
||||
pub struct Glb<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'gcx, 'tcx>
|
||||
pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Glb<'a, 'gcx, 'tcx> {
|
||||
Glb { fields: fields }
|
||||
}
|
||||
|
||||
pub fn obligations(self) -> PredicateObligations<'tcx> {
|
||||
self.fields.obligations
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> {
|
||||
pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
|
||||
-> Glb<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
Glb { fields: fields, a_is_expected: a_is_expected }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
for Glb<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn tag(&self) -> &'static str { "Glb" }
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
|
||||
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
|
||||
fn a_is_expected(&self) -> bool { self.a_is_expected }
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
|
||||
variance: ty::Variance,
|
||||
|
|
@ -46,10 +46,10 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, T>
|
||||
{
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate().relate(a, b),
|
||||
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate().relate(a, b),
|
||||
ty::Contravariant => self.fields.lub().relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
|
||||
ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,17 +71,19 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, ty::Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
self.fields.higher_ranked_glb(a, b)
|
||||
self.fields.higher_ranked_glb(a, b, self.a_is_expected)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
|
||||
fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
|
||||
for Glb<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
|
||||
self.fields.infcx
|
||||
}
|
||||
|
||||
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub();
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
sub.relate(&v, &a)?;
|
||||
sub.relate(&v, &b)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ pub struct HrMatchResult<U> {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
|
||||
pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
|
|
@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
debug!("b_prime={:?}", b_prime);
|
||||
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub().relate(&a_prime, &b_prime)?;
|
||||
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
|
||||
|
||||
// Presuming type comparison succeeds, we need to check
|
||||
// that the skolemized regions do not "leak".
|
||||
self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?;
|
||||
self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?;
|
||||
|
||||
// We are finished with the skolemized regions now so pop
|
||||
// them off.
|
||||
|
|
@ -106,10 +106,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
/// NB. It should not happen that there are LBR appearing in `U`
|
||||
/// that do not appear in `T`. If that happens, those regions are
|
||||
/// unconstrained, and this routine replaces them with `'static`.
|
||||
pub fn higher_ranked_match<T, U>(&self,
|
||||
pub fn higher_ranked_match<T, U>(&mut self,
|
||||
span: Span,
|
||||
a_pair: &Binder<(T, U)>,
|
||||
b_match: &T)
|
||||
b_match: &T,
|
||||
a_is_expected: bool)
|
||||
-> RelateResult<'tcx, HrMatchResult<U>>
|
||||
where T: Relate<'tcx>,
|
||||
U: TypeFoldable<'tcx>
|
||||
|
|
@ -129,7 +130,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
debug!("higher_ranked_match: skol_map={:?}", skol_map);
|
||||
|
||||
// Equate types now that bound regions have been replaced.
|
||||
try!(self.equate().relate(&a_match, &b_match));
|
||||
try!(self.equate(a_is_expected).relate(&a_match, &b_match));
|
||||
|
||||
// Map each skolemized region to a vector of other regions that it
|
||||
// must be equated with. (Note that this vector may include other
|
||||
|
|
@ -221,7 +222,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
|
||||
pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
|
|
@ -239,7 +240,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
self.lub().relate(&a_with_fresh, &b_with_fresh)?;
|
||||
self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
|
||||
let result0 =
|
||||
self.infcx.resolve_type_vars_if_possible(&result0);
|
||||
debug!("lub result0 = {:?}", result0);
|
||||
|
|
@ -311,7 +312,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>)
|
||||
pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
|
|
@ -333,7 +334,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
self.glb().relate(&a_with_fresh, &b_with_fresh)?;
|
||||
self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
|
||||
let result0 =
|
||||
self.infcx.resolve_type_vars_if_possible(&result0);
|
||||
debug!("glb result0 = {:?}", result0);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx>
|
|||
|
||||
// Relates the type `v` to `a` and `b` such that `v` represents
|
||||
// the LUB/GLB of `a` and `b` as appropriate.
|
||||
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
|
||||
}
|
||||
|
||||
pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
|
||||
|
|
|
|||
|
|
@ -15,29 +15,29 @@ use super::Subtype;
|
|||
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use traits::PredicateObligations;
|
||||
|
||||
/// "Least upper bound" (common supertype)
|
||||
pub struct Lub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'gcx, 'tcx>
|
||||
pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Lub<'a, 'gcx, 'tcx> {
|
||||
Lub { fields: fields }
|
||||
}
|
||||
|
||||
pub fn obligations(self) -> PredicateObligations<'tcx> {
|
||||
self.fields.obligations
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> {
|
||||
pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
|
||||
-> Lub<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
Lub { fields: fields, a_is_expected: a_is_expected }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
for Lub<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn tag(&self) -> &'static str { "Lub" }
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
|
||||
|
||||
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
|
||||
fn a_is_expected(&self) -> bool { self.a_is_expected }
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
|
||||
variance: ty::Variance,
|
||||
|
|
@ -46,10 +46,10 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, T>
|
||||
{
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate().relate(a, b),
|
||||
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate().relate(a, b),
|
||||
ty::Contravariant => self.fields.glb().relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
|
||||
ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,17 +71,19 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, ty::Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
self.fields.higher_ranked_lub(a, b)
|
||||
self.fields.higher_ranked_lub(a, b, self.a_is_expected)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
|
||||
fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
|
||||
for Lub<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
|
||||
self.fields.infcx
|
||||
}
|
||||
|
||||
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub();
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
sub.relate(&a, &v)?;
|
||||
sub.relate(&b, &v)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use ty::adjustment;
|
|||
use ty::{TyVid, IntVid, FloatVid};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
|
||||
use ty::fold::TypeFoldable;
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use traits::{self, PredicateObligations, ProjectionMode};
|
||||
use rustc_data_structures::unify::{self, UnificationTable};
|
||||
|
|
@ -48,18 +48,18 @@ use self::higher_ranked::HrMatchResult;
|
|||
use self::region_inference::{RegionVarBindings, RegionSnapshot};
|
||||
use self::unify_key::ToType;
|
||||
|
||||
pub mod bivariate;
|
||||
pub mod combine;
|
||||
pub mod equate;
|
||||
mod bivariate;
|
||||
mod combine;
|
||||
mod equate;
|
||||
pub mod error_reporting;
|
||||
pub mod glb;
|
||||
mod glb;
|
||||
mod higher_ranked;
|
||||
pub mod lattice;
|
||||
pub mod lub;
|
||||
mod lub;
|
||||
pub mod region_inference;
|
||||
pub mod resolve;
|
||||
mod freshen;
|
||||
pub mod sub;
|
||||
mod sub;
|
||||
pub mod type_variable;
|
||||
pub mod unify_key;
|
||||
|
||||
|
|
@ -196,12 +196,6 @@ pub enum TypeOrigin {
|
|||
// FIXME(eddyb) #11161 is the original Expr required?
|
||||
ExprAssignable(Span),
|
||||
|
||||
// Relating trait refs when resolving vtables
|
||||
RelateTraitRefs(Span),
|
||||
|
||||
// Relating self types when resolving vtables
|
||||
RelateSelfType(Span),
|
||||
|
||||
// Relating trait type parameters to those found in impl etc
|
||||
RelateOutputImplTypes(Span),
|
||||
|
||||
|
|
@ -219,16 +213,26 @@ pub enum TypeOrigin {
|
|||
|
||||
// `where a == b`
|
||||
EquatePredicate(Span),
|
||||
|
||||
// `main` has wrong type
|
||||
MainFunctionType(Span),
|
||||
|
||||
// `start` has wrong type
|
||||
StartFunctionType(Span),
|
||||
|
||||
// intrinsic has wrong type
|
||||
IntrinsicType(Span),
|
||||
|
||||
// method receiver
|
||||
MethodReceiver(Span),
|
||||
}
|
||||
|
||||
impl TypeOrigin {
|
||||
fn as_str(&self) -> &'static str {
|
||||
fn as_failure_str(&self) -> &'static str {
|
||||
match self {
|
||||
&TypeOrigin::Misc(_) |
|
||||
&TypeOrigin::RelateSelfType(_) |
|
||||
&TypeOrigin::RelateOutputImplTypes(_) |
|
||||
&TypeOrigin::ExprAssignable(_) => "mismatched types",
|
||||
&TypeOrigin::RelateTraitRefs(_) => "mismatched traits",
|
||||
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
|
||||
&TypeOrigin::MatchExpressionArm(_, _, source) => match source {
|
||||
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
|
||||
|
|
@ -238,13 +242,31 @@ impl TypeOrigin {
|
|||
&TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
|
||||
&TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types",
|
||||
&TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
|
||||
&TypeOrigin::MainFunctionType(_) => "main function has wrong type",
|
||||
&TypeOrigin::StartFunctionType(_) => "start function has wrong type",
|
||||
&TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
|
||||
&TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypeOrigin {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
|
||||
fmt::Display::fmt(self.as_str(), f)
|
||||
fn as_requirement_str(&self) -> &'static str {
|
||||
match self {
|
||||
&TypeOrigin::Misc(_) => "types are compatible",
|
||||
&TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
|
||||
&TypeOrigin::ExprAssignable(_) => "expression is assignable",
|
||||
&TypeOrigin::RelateOutputImplTypes(_) => {
|
||||
"trait type parameters matches those specified on the impl"
|
||||
}
|
||||
&TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
|
||||
&TypeOrigin::IfExpression(_) => "if and else have compatible types",
|
||||
&TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
|
||||
&TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
|
||||
&TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
|
||||
&TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
|
||||
&TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
|
||||
&TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
|
||||
&TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -799,11 +821,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
return variables;
|
||||
}
|
||||
|
||||
fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
fn combine_fields(&'a self, trace: TypeTrace<'tcx>)
|
||||
-> CombineFields<'a, 'gcx, 'tcx> {
|
||||
CombineFields {
|
||||
infcx: self,
|
||||
a_is_expected: a_is_expected,
|
||||
trace: trace,
|
||||
cause: None,
|
||||
obligations: PredicateObligations::new(),
|
||||
|
|
@ -814,36 +835,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
-> InferResult<'tcx, T>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
let mut equate = self.combine_fields(a_is_expected, trace).equate();
|
||||
let result = equate.relate(a, b);
|
||||
result.map(|t| InferOk { value: t, obligations: equate.obligations() })
|
||||
let mut fields = self.combine_fields(trace);
|
||||
let result = fields.equate(a_is_expected).relate(a, b);
|
||||
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
|
||||
-> InferResult<'tcx, T>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
let mut sub = self.combine_fields(a_is_expected, trace).sub();
|
||||
let result = sub.relate(a, b);
|
||||
result.map(|t| InferOk { value: t, obligations: sub.obligations() })
|
||||
let mut fields = self.combine_fields(trace);
|
||||
let result = fields.sub(a_is_expected).relate(a, b);
|
||||
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
|
||||
-> InferResult<'tcx, T>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
let mut lub = self.combine_fields(a_is_expected, trace).lub();
|
||||
let result = lub.relate(a, b);
|
||||
result.map(|t| InferOk { value: t, obligations: lub.obligations() })
|
||||
let mut fields = self.combine_fields(trace);
|
||||
let result = fields.lub(a_is_expected).relate(a, b);
|
||||
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
|
||||
-> InferResult<'tcx, T>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
let mut glb = self.combine_fields(a_is_expected, trace).glb();
|
||||
let result = glb.relate(a, b);
|
||||
result.map(|t| InferOk { value: t, obligations: glb.obligations() })
|
||||
let mut fields = self.combine_fields(trace);
|
||||
let result = fields.glb(a_is_expected).relate(a, b);
|
||||
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
fn start_snapshot(&self) -> CombinedSnapshot {
|
||||
|
|
@ -1468,104 +1489,50 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// error type, meaning that an error occurred when typechecking this expression),
|
||||
// this is a derived error. The error cascaded from another error (that was already
|
||||
// reported), so it's not useful to display it to the user.
|
||||
// The following four methods -- type_error_message_str, type_error_message_str_with_expected,
|
||||
// type_error_message, and report_mismatched_types -- implement this logic.
|
||||
// The following methods implement this logic.
|
||||
// They check if either the actual or expected type is TyError, and don't print the error
|
||||
// in this case. The typechecker should only ever report type errors involving mismatched
|
||||
// types using one of these four methods, and should not call span_err directly for such
|
||||
// types using one of these methods, and should not call span_err directly for such
|
||||
// errors.
|
||||
pub fn type_error_message_str<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
|
||||
}
|
||||
|
||||
pub fn type_error_struct_str<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
|
||||
}
|
||||
|
||||
pub fn type_error_message_str_with_expected<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
expected_ty: Option<Ty<'tcx>>,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn type_error_struct_str_with_expected<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
expected_ty: Option<Ty<'tcx>>,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
|
||||
|
||||
let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty));
|
||||
|
||||
if !resolved_expected.references_error() {
|
||||
let error_str = err.map_or("".to_string(), |t_err| {
|
||||
format!(" ({})", t_err)
|
||||
});
|
||||
|
||||
let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}",
|
||||
mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
|
||||
error_str));
|
||||
|
||||
if let Some(err) = err {
|
||||
self.tcx.note_and_explain_type_err(&mut db, err, sp);
|
||||
}
|
||||
db
|
||||
} else {
|
||||
self.tcx.sess.diagnostic().struct_dummy()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_error_message<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
actual_ty: Ty<'tcx>)
|
||||
where M: FnOnce(String) -> String,
|
||||
{
|
||||
self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
|
||||
self.type_error_struct(sp, mk_msg, actual_ty).emit();
|
||||
}
|
||||
|
||||
// FIXME: this results in errors without an error code. Deprecate?
|
||||
pub fn type_error_struct<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
actual_ty: Ty<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(String) -> String,
|
||||
{
|
||||
self.type_error_struct_with_diag(sp, |actual_ty| {
|
||||
self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty))
|
||||
}, actual_ty)
|
||||
}
|
||||
|
||||
pub fn type_error_struct_with_diag<M>(&self,
|
||||
sp: Span,
|
||||
mk_diag: M,
|
||||
actual_ty: Ty<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
|
||||
{
|
||||
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
|
||||
debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
|
||||
|
||||
// Don't report an error if actual type is TyError.
|
||||
if actual_ty.references_error() {
|
||||
return self.tcx.sess.diagnostic().struct_dummy();
|
||||
}
|
||||
|
||||
self.type_error_struct_str(sp,
|
||||
move |_e, a| { mk_msg(a) },
|
||||
self.ty_to_string(actual_ty), err)
|
||||
mk_diag(self.ty_to_string(actual_ty))
|
||||
}
|
||||
|
||||
pub fn report_mismatched_types(&self,
|
||||
|
|
@ -1646,8 +1613,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
|
||||
let combine = self.combine_fields(true, trace);
|
||||
let result = combine.higher_ranked_match(span, &match_pair, &match_b)?;
|
||||
let mut combine = self.combine_fields(trace);
|
||||
let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
|
||||
Ok(InferOk { value: result, obligations: combine.obligations })
|
||||
}
|
||||
|
||||
|
|
@ -1833,14 +1800,16 @@ impl TypeOrigin {
|
|||
TypeOrigin::MethodCompatCheck(span) => span,
|
||||
TypeOrigin::ExprAssignable(span) => span,
|
||||
TypeOrigin::Misc(span) => span,
|
||||
TypeOrigin::RelateTraitRefs(span) => span,
|
||||
TypeOrigin::RelateSelfType(span) => span,
|
||||
TypeOrigin::RelateOutputImplTypes(span) => span,
|
||||
TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
|
||||
TypeOrigin::IfExpression(span) => span,
|
||||
TypeOrigin::IfExpressionWithNoElse(span) => span,
|
||||
TypeOrigin::RangeExpression(span) => span,
|
||||
TypeOrigin::EquatePredicate(span) => span,
|
||||
TypeOrigin::MainFunctionType(span) => span,
|
||||
TypeOrigin::StartFunctionType(span) => span,
|
||||
TypeOrigin::IntrinsicType(span) => span,
|
||||
TypeOrigin::MethodReceiver(span) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1891,3 +1860,50 @@ impl RegionVariableOrigin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
ValuePairs::Types(ref ef) => {
|
||||
ValuePairs::Types(ef.fold_with(folder))
|
||||
}
|
||||
ValuePairs::TraitRefs(ref ef) => {
|
||||
ValuePairs::TraitRefs(ef.fold_with(folder))
|
||||
}
|
||||
ValuePairs::PolyTraitRefs(ref ef) => {
|
||||
ValuePairs::PolyTraitRefs(ef.fold_with(folder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
ValuePairs::Types(ref ef) => ef.visit_with(visitor),
|
||||
ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor),
|
||||
ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
TypeTrace {
|
||||
origin: self.origin.fold_with(folder),
|
||||
values: self.values.fold_with(folder)
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.origin.visit_with(visitor) || self.values.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,28 +15,35 @@ use super::type_variable::{SubtypeOf, SupertypeOf};
|
|||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::TyVar;
|
||||
use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
|
||||
use traits::PredicateObligations;
|
||||
use std::mem;
|
||||
|
||||
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
|
||||
pub struct Sub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'gcx, 'tcx>,
|
||||
pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> {
|
||||
pub fn new(f: CombineFields<'a, 'gcx, 'tcx>) -> Sub<'a, 'gcx, 'tcx> {
|
||||
Sub { fields: f }
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> {
|
||||
pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
|
||||
-> Sub<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
Sub { fields: f, a_is_expected: a_is_expected }
|
||||
}
|
||||
|
||||
pub fn obligations(self) -> PredicateObligations<'tcx> {
|
||||
self.fields.obligations
|
||||
fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
|
||||
self.a_is_expected = !self.a_is_expected;
|
||||
let result = f(self);
|
||||
self.a_is_expected = !self.a_is_expected;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
|
||||
impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
for Sub<'combine, 'infcx, 'gcx, 'tcx>
|
||||
{
|
||||
fn tag(&self) -> &'static str { "Sub" }
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.infcx.tcx }
|
||||
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
|
||||
fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx }
|
||||
fn a_is_expected(&self) -> bool { self.a_is_expected }
|
||||
|
||||
fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
|
||||
where F: FnOnce(&mut Self) -> R
|
||||
|
|
@ -56,10 +63,10 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, T>
|
||||
{
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate().relate(a, b),
|
||||
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate().relate(a, b),
|
||||
ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
|
||||
ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
|
||||
ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,12 +87,11 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
(&ty::TyInfer(TyVar(a_id)), _) => {
|
||||
self.fields
|
||||
.switch_expected()
|
||||
.instantiate(b, SupertypeOf, a_id)?;
|
||||
.instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
(_, &ty::TyInfer(TyVar(b_id))) => {
|
||||
self.fields.instantiate(a, SubtypeOf, b_id)?;
|
||||
self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +122,6 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
|
|||
-> RelateResult<'tcx, ty::Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
self.fields.higher_ranked_sub(a, b)
|
||||
self.fields.higher_ranked_sub(a, b, self.a_is_expected)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use dep_graph::DepNode;
|
|||
use middle::privacy::AccessLevels;
|
||||
use ty::TyCtxt;
|
||||
use session::{config, early_error, Session};
|
||||
use lint::{Level, LevelSource, Lint, LintId, LintPass};
|
||||
use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
|
||||
use lint::{EarlyLintPassObject, LateLintPassObject};
|
||||
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
|
||||
use lint::builtin;
|
||||
|
|
@ -45,7 +45,6 @@ use syntax_pos::Span;
|
|||
use errors::DiagnosticBuilder;
|
||||
use hir;
|
||||
use hir::intravisit as hir_visit;
|
||||
use hir::intravisit::{IdVisitor, IdVisitingOperation};
|
||||
use syntax::visit as ast_visit;
|
||||
|
||||
/// Information about the registered lints.
|
||||
|
|
@ -366,18 +365,18 @@ pub fn gather_attr(attr: &ast::Attribute)
|
|||
attr::mark_used(attr);
|
||||
|
||||
let meta = &attr.node.value;
|
||||
let metas = match meta.node {
|
||||
ast::MetaItemKind::List(_, ref metas) => metas,
|
||||
_ => {
|
||||
out.push(Err(meta.span));
|
||||
return out;
|
||||
}
|
||||
let metas = if let Some(metas) = meta.meta_item_list() {
|
||||
metas
|
||||
} else {
|
||||
out.push(Err(meta.span));
|
||||
return out;
|
||||
};
|
||||
|
||||
for meta in metas {
|
||||
out.push(match meta.node {
|
||||
ast::MetaItemKind::Word(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
|
||||
_ => Err(meta.span),
|
||||
out.push(if meta.is_word() {
|
||||
Ok((meta.name().clone(), level, meta.span))
|
||||
} else {
|
||||
Err(meta.span)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -600,13 +599,23 @@ pub trait LintContext: Sized {
|
|||
};
|
||||
|
||||
for (lint_id, level, span) in v {
|
||||
let now = self.lints().get_level_source(lint_id).0;
|
||||
let (now, now_source) = self.lints().get_level_source(lint_id);
|
||||
if now == Forbid && level != Forbid {
|
||||
let lint_name = lint_id.as_str();
|
||||
span_err!(self.sess(), span, E0453,
|
||||
"{}({}) overruled by outer forbid({})",
|
||||
level.as_str(), lint_name,
|
||||
lint_name);
|
||||
let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
|
||||
"{}({}) overruled by outer forbid({})",
|
||||
level.as_str(), lint_name,
|
||||
lint_name);
|
||||
match now_source {
|
||||
LintSource::Default => &mut diag_builder,
|
||||
LintSource::Node(forbid_source_span) => {
|
||||
diag_builder.span_note(forbid_source_span,
|
||||
"`forbid` lint level set here")
|
||||
},
|
||||
LintSource::CommandLine => {
|
||||
diag_builder.note("`forbid` lint level was set on command line")
|
||||
}
|
||||
}.emit()
|
||||
} else if now != level {
|
||||
let src = self.lints().get_level_source(lint_id).1;
|
||||
self.level_stack().push((lint_id, (now, src)));
|
||||
|
|
@ -663,9 +672,11 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_ids<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut IdVisitor<LateContext>)
|
||||
where F: FnOnce(&mut IdVisitor)
|
||||
{
|
||||
let mut v = IdVisitor::new(self);
|
||||
let mut v = IdVisitor {
|
||||
cx: self
|
||||
};
|
||||
f(&mut v);
|
||||
}
|
||||
}
|
||||
|
|
@ -779,7 +790,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
|
|||
fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
|
||||
body: &'v hir::Block, span: Span, id: ast::NodeId) {
|
||||
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
|
||||
hir_visit::walk_fn(self, fk, decl, body, span);
|
||||
hir_visit::walk_fn(self, fk, decl, body, span, id);
|
||||
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
|
||||
}
|
||||
|
||||
|
|
@ -820,7 +831,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
|
|||
|
||||
fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
|
||||
run_lints!(self, check_mod, late_passes, m, s, n);
|
||||
hir_visit::walk_mod(self, m);
|
||||
hir_visit::walk_mod(self, m, n);
|
||||
run_lints!(self, check_mod_post, late_passes, m, s, n);
|
||||
}
|
||||
|
||||
|
|
@ -859,7 +870,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
|
|||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
|
||||
self.with_lint_attrs(&trait_item.attrs, |cx| {
|
||||
run_lints!(cx, check_trait_item, late_passes, trait_item);
|
||||
cx.visit_ids(|v| v.visit_trait_item(trait_item));
|
||||
cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
|
||||
hir_visit::walk_trait_item(cx, trait_item);
|
||||
run_lints!(cx, check_trait_item_post, late_passes, trait_item);
|
||||
});
|
||||
|
|
@ -868,7 +879,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
|
|||
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
|
||||
self.with_lint_attrs(&impl_item.attrs, |cx| {
|
||||
run_lints!(cx, check_impl_item, late_passes, impl_item);
|
||||
cx.visit_ids(|v| v.visit_impl_item(impl_item));
|
||||
cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
|
||||
hir_visit::walk_impl_item(cx, impl_item);
|
||||
run_lints!(cx, check_impl_item_post, late_passes, impl_item);
|
||||
});
|
||||
|
|
@ -1046,16 +1057,30 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
|
||||
cx: &'a mut LateContext<'b, 'tcx>
|
||||
}
|
||||
|
||||
// Output any lints that were previously added to the session.
|
||||
impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
|
||||
impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
|
||||
|
||||
fn visit_id(&mut self, id: ast::NodeId) {
|
||||
if let Some(lints) = self.sess().lints.borrow_mut().remove(&id) {
|
||||
if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
|
||||
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
|
||||
for (lint_id, span, msg) in lints {
|
||||
self.span_lint(lint_id.lint, span, &msg[..])
|
||||
self.cx.span_lint(lint_id.lint, span, &msg[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _ti: &hir::TraitItem) {
|
||||
// Do not recurse into trait or impl items automatically. These are
|
||||
// processed separately by calling hir_visit::walk_trait_item()
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _ii: &hir::ImplItem) {
|
||||
// See visit_trait_item()
|
||||
}
|
||||
}
|
||||
|
||||
enum CheckLintNameResult {
|
||||
|
|
@ -1172,7 +1197,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
// Visit the whole crate.
|
||||
cx.with_lint_attrs(&krate.attrs, |cx| {
|
||||
cx.visit_id(ast::CRATE_NODE_ID);
|
||||
cx.visit_ids(|v| {
|
||||
hir_visit::walk_crate(v, krate);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,13 +24,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) {
|
||||
for segment in segments {
|
||||
for typ in segment.parameters.types() {
|
||||
span_err!(self.sess, typ.span, E0109,
|
||||
"type parameters are not allowed on this type");
|
||||
struct_span_err!(self.sess, typ.span, E0109,
|
||||
"type parameters are not allowed on this type")
|
||||
.span_label(typ.span, &format!("type parameter not allowed"))
|
||||
.emit();
|
||||
break;
|
||||
}
|
||||
for lifetime in segment.parameters.lifetimes() {
|
||||
span_err!(self.sess, lifetime.span, E0110,
|
||||
"lifetime parameters are not allowed on this type");
|
||||
struct_span_err!(self.sess, lifetime.span, E0110,
|
||||
"lifetime parameters are not allowed on this type")
|
||||
.span_label(lifetime.span,
|
||||
&format!("lifetime parameter not allowed on this type"))
|
||||
.emit();
|
||||
break;
|
||||
}
|
||||
for binding in segment.parameters.bindings() {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ use syntax::parse::token::InternedString;
|
|||
use syntax_pos::Span;
|
||||
use rustc_back::target::Target;
|
||||
use hir;
|
||||
use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor};
|
||||
use hir::intravisit::Visitor;
|
||||
|
||||
pub use self::DefLike::{DlDef, DlField, DlImpl};
|
||||
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
|
||||
|
|
@ -120,12 +120,6 @@ pub struct ChildItem {
|
|||
pub vis: ty::Visibility,
|
||||
}
|
||||
|
||||
pub enum FoundAst<'ast> {
|
||||
Found(&'ast InlinedItem),
|
||||
FoundParent(DefId, &'ast hir::Item),
|
||||
NotFound,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ExternCrate {
|
||||
/// def_id of an `extern crate` in the current crate that caused
|
||||
|
|
@ -250,7 +244,10 @@ pub trait CrateStore<'tcx> {
|
|||
|
||||
// misc. metadata
|
||||
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
-> FoundAst<'tcx>;
|
||||
-> Option<(&'tcx InlinedItem, ast::NodeId)>;
|
||||
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
|
||||
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
|
||||
|
||||
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
-> Option<Mir<'tcx>>;
|
||||
fn is_item_mir_available(&self, def: DefId) -> bool;
|
||||
|
|
@ -292,11 +289,6 @@ impl InlinedItem {
|
|||
InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_ids<O: IdVisitingOperation>(&self, operation: &mut O) {
|
||||
let mut id_visitor = IdVisitor::new(operation);
|
||||
self.visit(&mut id_visitor);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: find a better place for this?
|
||||
|
|
@ -452,7 +444,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
|||
|
||||
// misc. metadata
|
||||
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
-> FoundAst<'tcx> { bug!("maybe_get_item_ast") }
|
||||
-> Option<(&'tcx InlinedItem, ast::NodeId)> {
|
||||
bug!("maybe_get_item_ast")
|
||||
}
|
||||
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
|
||||
bug!("local_node_for_inlined_defid")
|
||||
}
|
||||
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
|
||||
bug!("defid_for_inlined_node")
|
||||
}
|
||||
|
||||
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
-> Option<Mir<'tcx>> { bug!("maybe_get_item_mir") }
|
||||
fn is_item_mir_available(&self, def: DefId) -> bool {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl,
|
||||
block: &'v hir::Block, span: Span, _: ast::NodeId) {
|
||||
block: &'v hir::Block, span: Span, id: ast::NodeId) {
|
||||
|
||||
let (is_item_fn, is_unsafe_fn) = match fn_kind {
|
||||
FnKind::ItemFn(_, _, unsafety, _, _, _, _) =>
|
||||
|
|
@ -96,7 +96,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
|
|||
self.unsafe_context = UnsafeContext::new(SafeContext)
|
||||
}
|
||||
|
||||
intravisit::walk_fn(self, fn_kind, fn_decl, block, span);
|
||||
intravisit::walk_fn(self, fn_kind, fn_decl, block, span, id);
|
||||
|
||||
self.unsafe_context = old_unsafe_context
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,8 +121,11 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) {
|
|||
if ctxt.attr_main_fn.is_none() {
|
||||
ctxt.attr_main_fn = Some((item.id, item.span));
|
||||
} else {
|
||||
span_err!(ctxt.session, item.span, E0137,
|
||||
"multiple functions with a #[main] attribute");
|
||||
struct_span_err!(ctxt.session, item.span, E0137,
|
||||
"multiple functions with a #[main] attribute")
|
||||
.span_label(item.span, &format!("additional #[main] function"))
|
||||
.span_label(ctxt.attr_main_fn.unwrap().1, &format!("first #[main] function"))
|
||||
.emit();
|
||||
}
|
||||
},
|
||||
EntryPointType::Start => {
|
||||
|
|
|
|||
|
|
@ -271,10 +271,19 @@ enum PassArgs {
|
|||
|
||||
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Self
|
||||
{
|
||||
ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default())
|
||||
}
|
||||
|
||||
pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
options: mc::MemCategorizationOptions)
|
||||
-> Self
|
||||
{
|
||||
ExprUseVisitor {
|
||||
mc: mc::MemCategorizationContext::new(infcx),
|
||||
mc: mc::MemCategorizationContext::with_options(infcx, options),
|
||||
delegate: delegate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,7 +359,6 @@ language_item_table! {
|
|||
StartFnLangItem, "start", start_fn;
|
||||
|
||||
EhPersonalityLangItem, "eh_personality", eh_personality;
|
||||
EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch;
|
||||
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume;
|
||||
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;
|
||||
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ fn visit_fn(ir: &mut IrMaps,
|
|||
|
||||
// gather up the various local variables, significant expressions,
|
||||
// and so forth:
|
||||
intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp);
|
||||
intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp, id);
|
||||
|
||||
// Special nodes and variables:
|
||||
// - exit_ln represents the end of the fn, either by return or panic
|
||||
|
|
|
|||
|
|
@ -259,6 +259,18 @@ impl ast_node for hir::Pat {
|
|||
#[derive(Copy, Clone)]
|
||||
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
options: MemCategorizationOptions,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct MemCategorizationOptions {
|
||||
// If true, then when analyzing a closure upvar, if the closure
|
||||
// has a missing kind, we treat it like a Fn closure. When false,
|
||||
// we ICE if the closure has a missing kind. Should be false
|
||||
// except during closure kind inference. It is used by the
|
||||
// mem-categorization code to be able to have stricter assertions
|
||||
// (which are always true except during upvar inference).
|
||||
pub during_closure_kind_inference: bool,
|
||||
}
|
||||
|
||||
pub type McResult<T> = Result<T, ()>;
|
||||
|
|
@ -362,7 +374,16 @@ impl MutabilityCategory {
|
|||
impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
|
||||
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
MemCategorizationContext { infcx: infcx }
|
||||
MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default())
|
||||
}
|
||||
|
||||
pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
options: MemCategorizationOptions)
|
||||
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
MemCategorizationContext {
|
||||
infcx: infcx,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
|
|
@ -584,10 +605,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
self.cat_upvar(id, span, var_id, fn_node_id, kind)
|
||||
}
|
||||
None => {
|
||||
span_bug!(
|
||||
span,
|
||||
"No closure kind for {:?}",
|
||||
closure_id);
|
||||
if !self.options.during_closure_kind_inference {
|
||||
span_bug!(
|
||||
span,
|
||||
"No closure kind for {:?}",
|
||||
closure_id);
|
||||
}
|
||||
|
||||
// during closure kind inference, we
|
||||
// don't know the closure kind yet, but
|
||||
// it's ok because we detect that we are
|
||||
// accessing an upvar and handle that
|
||||
// case specially anyhow. Use Fn
|
||||
// arbitrarily.
|
||||
self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use session::Session;
|
|||
use lint;
|
||||
use middle::cstore::LOCAL_CRATE;
|
||||
use hir::def::Def;
|
||||
use hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
|
||||
use ty::{self, TyCtxt};
|
||||
use middle::privacy::AccessLevels;
|
||||
use syntax::parse::token::InternedString;
|
||||
|
|
@ -61,12 +61,46 @@ enum AnnotationKind {
|
|||
Container,
|
||||
}
|
||||
|
||||
/// An entry in the `depr_map`.
|
||||
#[derive(Clone)]
|
||||
pub struct DeprecationEntry {
|
||||
/// The metadata of the attribute associated with this entry.
|
||||
pub attr: Deprecation,
|
||||
/// The def id where the attr was originally attached. `None` for non-local
|
||||
/// `DefId`'s.
|
||||
origin: Option<DefIndex>,
|
||||
}
|
||||
|
||||
impl DeprecationEntry {
|
||||
fn local(attr: Deprecation, id: DefId) -> DeprecationEntry {
|
||||
assert!(id.is_local());
|
||||
DeprecationEntry {
|
||||
attr: attr,
|
||||
origin: Some(id.index),
|
||||
}
|
||||
}
|
||||
|
||||
fn external(attr: Deprecation) -> DeprecationEntry {
|
||||
DeprecationEntry {
|
||||
attr: attr,
|
||||
origin: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn same_origin(&self, other: &DeprecationEntry) -> bool {
|
||||
match (self.origin, other.origin) {
|
||||
(Some(o1), Some(o2)) => o1 == o2,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A stability index, giving the stability level for items and methods.
|
||||
pub struct Index<'tcx> {
|
||||
/// This is mostly a cache, except the stabilities of local items
|
||||
/// are filled by the annotator.
|
||||
stab_map: DefIdMap<Option<&'tcx Stability>>,
|
||||
depr_map: DefIdMap<Option<Deprecation>>,
|
||||
depr_map: DefIdMap<Option<DeprecationEntry>>,
|
||||
|
||||
/// Maps for each crate whether it is part of the staged API.
|
||||
staged_api: FnvHashMap<ast::CrateNum, bool>
|
||||
|
|
@ -77,7 +111,7 @@ struct Annotator<'a, 'tcx: 'a> {
|
|||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
index: &'a mut Index<'tcx>,
|
||||
parent_stab: Option<&'tcx Stability>,
|
||||
parent_depr: Option<Deprecation>,
|
||||
parent_depr: Option<DeprecationEntry>,
|
||||
access_levels: &'a AccessLevels,
|
||||
in_trait_impl: bool,
|
||||
}
|
||||
|
|
@ -184,14 +218,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
|
|||
|
||||
// `Deprecation` is just two pointers, no need to intern it
|
||||
let def_id = self.tcx.map.local_def_id(id);
|
||||
self.index.depr_map.insert(def_id, Some(depr.clone()));
|
||||
let depr_entry = Some(DeprecationEntry::local(depr, def_id));
|
||||
self.index.depr_map.insert(def_id, depr_entry.clone());
|
||||
|
||||
let orig_parent_depr = replace(&mut self.parent_depr, Some(depr));
|
||||
let orig_parent_depr = replace(&mut self.parent_depr, depr_entry);
|
||||
visit_children(self);
|
||||
self.parent_depr = orig_parent_depr;
|
||||
} else if let Some(depr) = self.parent_depr.clone() {
|
||||
} else if let parent_depr @ Some(_) = self.parent_depr.clone() {
|
||||
let def_id = self.tcx.map.local_def_id(id);
|
||||
self.index.depr_map.insert(def_id, Some(depr));
|
||||
self.index.depr_map.insert(def_id, parent_depr);
|
||||
visit_children(self);
|
||||
} else {
|
||||
visit_children(self);
|
||||
|
|
@ -351,7 +386,7 @@ struct Checker<'a, 'tcx: 'a> {
|
|||
|
||||
impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||
fn check(&mut self, id: DefId, span: Span,
|
||||
stab: &Option<&Stability>, _depr: &Option<Deprecation>) {
|
||||
stab: &Option<&Stability>, _depr: &Option<DeprecationEntry>) {
|
||||
if !is_staged_api(self.tcx, id) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -476,7 +511,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
warn_about_defns: bool,
|
||||
cb: &mut FnMut(DefId, Span,
|
||||
&Option<&Stability>,
|
||||
&Option<Deprecation>)) {
|
||||
&Option<DeprecationEntry>)) {
|
||||
match item.node {
|
||||
hir::ItemExternCrate(_) => {
|
||||
// compiler-generated `extern crate` items have a dummy span.
|
||||
|
|
@ -515,7 +550,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
|
||||
cb: &mut FnMut(DefId, Span,
|
||||
&Option<&Stability>,
|
||||
&Option<Deprecation>)) {
|
||||
&Option<DeprecationEntry>)) {
|
||||
let span;
|
||||
let id = match e.node {
|
||||
hir::ExprMethodCall(i, _, _) => {
|
||||
|
|
@ -579,7 +614,7 @@ pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
path: &hir::Path, id: ast::NodeId,
|
||||
cb: &mut FnMut(DefId, Span,
|
||||
&Option<&Stability>,
|
||||
&Option<Deprecation>)) {
|
||||
&Option<DeprecationEntry>)) {
|
||||
// Paths in import prefixes may have no resolution.
|
||||
match tcx.expect_def_or_none(id) {
|
||||
Some(Def::PrimTy(..)) => {}
|
||||
|
|
@ -595,7 +630,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
item: &hir::PathListItem,
|
||||
cb: &mut FnMut(DefId, Span,
|
||||
&Option<&Stability>,
|
||||
&Option<Deprecation>)) {
|
||||
&Option<DeprecationEntry>)) {
|
||||
match tcx.expect_def(item.node.id()) {
|
||||
Def::PrimTy(..) => {}
|
||||
def => {
|
||||
|
|
@ -607,7 +642,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
|
||||
cb: &mut FnMut(DefId, Span,
|
||||
&Option<&Stability>,
|
||||
&Option<Deprecation>)) {
|
||||
&Option<DeprecationEntry>)) {
|
||||
debug!("check_pat(pat = {:?})", pat);
|
||||
if is_internal(tcx, pat.span) { return; }
|
||||
|
||||
|
|
@ -638,7 +673,7 @@ fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
id: DefId, span: Span,
|
||||
cb: &mut FnMut(DefId, Span,
|
||||
&Option<&Stability>,
|
||||
&Option<Deprecation>)) {
|
||||
&Option<DeprecationEntry>)) {
|
||||
if is_internal(tcx, span) {
|
||||
debug!("maybe_do_stability_check: \
|
||||
skipping span={:?} since it is internal", span);
|
||||
|
|
@ -647,7 +682,7 @@ fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let (stability, deprecation) = if is_staged_api(tcx, id) {
|
||||
(tcx.lookup_stability(id), None)
|
||||
} else {
|
||||
(None, tcx.lookup_deprecation(id))
|
||||
(None, tcx.lookup_deprecation_entry(id))
|
||||
};
|
||||
debug!("maybe_do_stability_check: \
|
||||
inspecting id={:?} span={:?} of stability={:?}", id, span, stability);
|
||||
|
|
@ -685,6 +720,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
|
||||
self.lookup_deprecation_entry(id).map(|depr| depr.attr)
|
||||
}
|
||||
|
||||
pub fn lookup_deprecation_entry(self, id: DefId) -> Option<DeprecationEntry> {
|
||||
if let Some(depr) = self.stability.borrow().depr_map.get(&id) {
|
||||
return depr.clone();
|
||||
}
|
||||
|
|
@ -703,12 +742,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lookup_deprecation_uncached(self, id: DefId) -> Option<Deprecation> {
|
||||
fn lookup_deprecation_uncached(self, id: DefId) -> Option<DeprecationEntry> {
|
||||
debug!("lookup(id={:?})", id);
|
||||
if id.is_local() {
|
||||
None // The stability cache is filled partially lazily
|
||||
} else {
|
||||
self.sess.cstore.deprecation(id)
|
||||
self.sess.cstore.deprecation(id).map(DeprecationEntry::external)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use syntax::parse;
|
|||
use syntax::parse::token::InternedString;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
|
||||
use errors::{ColorConfig, Handler};
|
||||
use errors::{ColorConfig, FatalError, Handler};
|
||||
|
||||
use getopts;
|
||||
use std::collections::HashMap;
|
||||
|
|
@ -61,7 +61,7 @@ pub enum DebugInfoLevel {
|
|||
FullDebugInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum OutputType {
|
||||
Bitcode,
|
||||
Assembly,
|
||||
|
|
@ -105,6 +105,17 @@ impl OutputType {
|
|||
OutputType::DepInfo => "dep-info",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extension(&self) -> &'static str {
|
||||
match *self {
|
||||
OutputType::Bitcode => "bc",
|
||||
OutputType::Assembly => "s",
|
||||
OutputType::LlvmAssembly => "ll",
|
||||
OutputType::Object => "o",
|
||||
OutputType::DepInfo => "d",
|
||||
OutputType::Exe => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -219,15 +230,7 @@ impl OutputFilenames {
|
|||
flavor: OutputType,
|
||||
codegen_unit_name: Option<&str>)
|
||||
-> PathBuf {
|
||||
let extension = match flavor {
|
||||
OutputType::Bitcode => "bc",
|
||||
OutputType::Assembly => "s",
|
||||
OutputType::LlvmAssembly => "ll",
|
||||
OutputType::Object => "o",
|
||||
OutputType::DepInfo => "d",
|
||||
OutputType::Exe => "",
|
||||
};
|
||||
|
||||
let extension = flavor.extension();
|
||||
self.temp_path_ext(extension, codegen_unit_name)
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +334,11 @@ impl Options {
|
|||
self.debugging_opts.dump_dep_graph ||
|
||||
self.debugging_opts.query_dep_graph
|
||||
}
|
||||
|
||||
pub fn single_codegen_unit(&self) -> bool {
|
||||
self.incremental.is_none() ||
|
||||
self.cg.codegen_units == 1
|
||||
}
|
||||
}
|
||||
|
||||
// The type of entry function, so
|
||||
|
|
@ -459,6 +467,8 @@ macro_rules! options {
|
|||
pub const parse_bool: Option<&'static str> = None;
|
||||
pub const parse_opt_bool: Option<&'static str> =
|
||||
Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
|
||||
pub const parse_all_bool: Option<&'static str> =
|
||||
Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
|
||||
pub const parse_string: Option<&'static str> = Some("a string");
|
||||
pub const parse_opt_string: Option<&'static str> = Some("a string");
|
||||
pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
|
||||
|
|
@ -508,6 +518,25 @@ macro_rules! options {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some(s) => {
|
||||
match s {
|
||||
"n" | "no" | "off" => {
|
||||
*slot = false;
|
||||
}
|
||||
"y" | "yes" | "on" => {
|
||||
*slot = true;
|
||||
}
|
||||
_ => { return false; }
|
||||
}
|
||||
|
||||
true
|
||||
},
|
||||
None => { *slot = true; true }
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some(s) => { *slot = Some(s.to_string()); true },
|
||||
|
|
@ -656,7 +685,6 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
|||
"panic strategy to compile crate with"),
|
||||
}
|
||||
|
||||
|
||||
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
build_debugging_options, "Z", "debugging",
|
||||
DB_OPTIONS, db_type_desc, dbsetters,
|
||||
|
|
@ -751,7 +779,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"set the MIR optimization level (0-3)"),
|
||||
dump_mir: Option<String> = (None, parse_opt_string,
|
||||
"dump MIR state at various points in translation"),
|
||||
orbit: bool = (false, parse_bool,
|
||||
dump_mir_dir: Option<String> = (None, parse_opt_string,
|
||||
"the directory the MIR is dumped into"),
|
||||
orbit: bool = (true, parse_all_bool,
|
||||
"get MIR where it belongs - everywhere; most importantly, in orbit"),
|
||||
}
|
||||
|
||||
|
|
@ -835,7 +865,10 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
|
|||
let target = match Target::search(&opts.target_triple) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
panic!(sp.fatal(&format!("Error loading target specification: {}", e)));
|
||||
sp.struct_fatal(&format!("Error loading target specification: {}", e))
|
||||
.help("Use `--print target-list` for a list of built-in targets")
|
||||
.emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1140,7 +1173,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
})
|
||||
});
|
||||
|
||||
let debugging_opts = build_debugging_options(matches, error_format);
|
||||
let mut debugging_opts = build_debugging_options(matches, error_format);
|
||||
|
||||
// Incremental compilation only works reliably when translation is done via
|
||||
// MIR, so let's enable -Z orbit if necessary (see #34973).
|
||||
if debugging_opts.incremental.is_some() && !debugging_opts.orbit {
|
||||
early_warn(error_format, "Automatically enabling `-Z orbit` because \
|
||||
`-Z incremental` was specified");
|
||||
debugging_opts.orbit = true;
|
||||
}
|
||||
|
||||
let parse_only = debugging_opts.parse_only;
|
||||
let no_trans = debugging_opts.no_trans;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ pub struct Session {
|
|||
// forms a unique global identifier for the crate. It is used to allow
|
||||
// multiple crates with the same name to coexist. See the
|
||||
// trans::back::symbol_names module for more information.
|
||||
pub crate_disambiguator: Cell<ast::Name>,
|
||||
pub crate_disambiguator: RefCell<token::InternedString>,
|
||||
pub features: RefCell<feature_gate::Features>,
|
||||
|
||||
/// The maximum recursion limit for potentially infinitely recursive
|
||||
|
|
@ -106,6 +106,9 @@ pub struct Session {
|
|||
}
|
||||
|
||||
impl Session {
|
||||
pub fn local_crate_disambiguator(&self) -> token::InternedString {
|
||||
self.crate_disambiguator.borrow().clone()
|
||||
}
|
||||
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
|
|
@ -126,20 +129,14 @@ impl Session {
|
|||
sp: S,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(ref msg) => self.diagnostic().struct_span_err(sp, msg),
|
||||
None => self.diagnostic().struct_span_err(sp, msg),
|
||||
}
|
||||
self.diagnostic().struct_span_err(sp, msg)
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code),
|
||||
None => self.diagnostic().struct_span_err_with_code(sp, msg, code),
|
||||
}
|
||||
self.diagnostic().struct_span_err_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_err(msg)
|
||||
|
|
@ -178,16 +175,10 @@ impl Session {
|
|||
}
|
||||
}
|
||||
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(msg) => self.diagnostic().span_err(sp, &msg),
|
||||
None => self.diagnostic().span_err(sp, msg)
|
||||
}
|
||||
self.diagnostic().span_err(sp, msg)
|
||||
}
|
||||
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
|
||||
None => self.diagnostic().span_err_with_code(sp, msg, code)
|
||||
}
|
||||
self.diagnostic().span_err_with_code(sp, &msg, code)
|
||||
}
|
||||
pub fn err(&self, msg: &str) {
|
||||
self.diagnostic().err(msg)
|
||||
|
|
@ -343,67 +334,6 @@ impl Session {
|
|||
}
|
||||
}
|
||||
|
||||
fn split_msg_into_multilines(msg: &str) -> Option<String> {
|
||||
// Conditions for enabling multi-line errors:
|
||||
if !msg.contains("mismatched types") &&
|
||||
!msg.contains("type mismatch resolving") &&
|
||||
!msg.contains("if and else have incompatible types") &&
|
||||
!msg.contains("if may be missing an else clause") &&
|
||||
!msg.contains("match arms have incompatible types") &&
|
||||
!msg.contains("structure constructor specifies a structure of type") &&
|
||||
!msg.contains("has an incompatible type for trait") {
|
||||
return None
|
||||
}
|
||||
let first = msg.match_indices("expected").filter(|s| {
|
||||
let last = msg[..s.0].chars().rev().next();
|
||||
last == Some(' ') || last == Some('(')
|
||||
}).map(|(a, b)| (a - 1, a + b.len()));
|
||||
let second = msg.match_indices("found").filter(|s| {
|
||||
msg[..s.0].chars().rev().next() == Some(' ')
|
||||
}).map(|(a, b)| (a - 1, a + b.len()));
|
||||
|
||||
let mut new_msg = String::new();
|
||||
let mut head = 0;
|
||||
|
||||
// Insert `\n` before expected and found.
|
||||
for (pos1, pos2) in first.zip(second) {
|
||||
new_msg = new_msg +
|
||||
// A `(` may be preceded by a space and it should be trimmed
|
||||
msg[head..pos1.0].trim_right() + // prefix
|
||||
"\n" + // insert before first
|
||||
&msg[pos1.0..pos1.1] + // insert what first matched
|
||||
&msg[pos1.1..pos2.0] + // between matches
|
||||
"\n " + // insert before second
|
||||
// 123
|
||||
// `expected` is 3 char longer than `found`. To align the types,
|
||||
// `found` gets 3 spaces prepended.
|
||||
&msg[pos2.0..pos2.1]; // insert what second matched
|
||||
|
||||
head = pos2.1;
|
||||
}
|
||||
|
||||
let mut tail = &msg[head..];
|
||||
let third = tail.find("(values differ")
|
||||
.or(tail.find("(lifetime"))
|
||||
.or(tail.find("(cyclic type of infinite size"));
|
||||
// Insert `\n` before any remaining messages which match.
|
||||
if let Some(pos) = third {
|
||||
// The end of the message may just be wrapped in `()` without
|
||||
// `expected`/`found`. Push this also to a new line and add the
|
||||
// final tail after.
|
||||
new_msg = new_msg +
|
||||
// `(` is usually preceded by a space and should be trimmed.
|
||||
tail[..pos].trim_right() + // prefix
|
||||
"\n" + // insert before paren
|
||||
&tail[pos..]; // append the tail
|
||||
|
||||
tail = "";
|
||||
}
|
||||
|
||||
new_msg.push_str(tail);
|
||||
return Some(new_msg);
|
||||
}
|
||||
|
||||
pub fn build_session(sopts: config::Options,
|
||||
dep_graph: &DepGraph,
|
||||
local_crate_source_file: Option<PathBuf>,
|
||||
|
|
@ -511,7 +441,7 @@ pub fn build_session_(sopts: config::Options,
|
|||
plugin_attributes: RefCell::new(Vec::new()),
|
||||
crate_types: RefCell::new(Vec::new()),
|
||||
dependency_formats: RefCell::new(FnvHashMap()),
|
||||
crate_disambiguator: Cell::new(token::intern("")),
|
||||
crate_disambiguator: RefCell::new(token::intern("").as_str()),
|
||||
features: RefCell::new(feature_gate::Features::new()),
|
||||
recursion_limit: Cell::new(64),
|
||||
next_node_id: Cell::new(1),
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ use super::{
|
|||
|
||||
use fmt_macros::{Parser, Piece, Position};
|
||||
use hir::def_id::DefId;
|
||||
use infer::{InferCtxt};
|
||||
use infer::{self, InferCtxt, TypeOrigin};
|
||||
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::error::ExpectedFound;
|
||||
use ty::fast_reject;
|
||||
use ty::fold::TypeFolder;
|
||||
use ty::subst::{self, Subst, TypeSpace};
|
||||
|
|
@ -107,24 +108,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let predicate =
|
||||
self.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
|
||||
if !predicate.references_error() {
|
||||
if let Some(warning_node_id) = warning_node_id {
|
||||
self.tcx.sess.add_lint(
|
||||
::lint::builtin::UNSIZED_IN_TUPLE,
|
||||
warning_node_id,
|
||||
obligation.cause.span,
|
||||
format!("type mismatch resolving `{}`: {}",
|
||||
predicate,
|
||||
error.err));
|
||||
} else {
|
||||
let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
|
||||
"type mismatch resolving `{}`: {}",
|
||||
predicate,
|
||||
error.err);
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
if predicate.references_error() {
|
||||
return
|
||||
}
|
||||
if let Some(warning_node_id) = warning_node_id {
|
||||
self.tcx.sess.add_lint(
|
||||
::lint::builtin::UNSIZED_IN_TUPLE,
|
||||
warning_node_id,
|
||||
obligation.cause.span,
|
||||
format!("type mismatch resolving `{}`: {}",
|
||||
predicate,
|
||||
error.err));
|
||||
return
|
||||
}
|
||||
self.probe(|_| {
|
||||
let origin = TypeOrigin::Misc(obligation.cause.span);
|
||||
let err_buf;
|
||||
let mut err = &error.err;
|
||||
let mut values = None;
|
||||
|
||||
// try to find the mismatched types to report the error with.
|
||||
//
|
||||
// this can fail if the problem was higher-ranked, in which
|
||||
// cause I have no idea for a good error message.
|
||||
if let ty::Predicate::Projection(ref data) = predicate {
|
||||
let mut selcx = SelectionContext::new(self);
|
||||
let (data, _) = self.replace_late_bound_regions_with_fresh_var(
|
||||
obligation.cause.span,
|
||||
infer::LateBoundRegionConversionTime::HigherRankedType,
|
||||
data);
|
||||
let normalized = super::normalize_projection_type(
|
||||
&mut selcx,
|
||||
data.projection_ty,
|
||||
obligation.cause.clone(),
|
||||
0
|
||||
);
|
||||
let origin = TypeOrigin::Misc(obligation.cause.span);
|
||||
if let Err(error) = self.eq_types(
|
||||
false, origin,
|
||||
data.ty, normalized.value
|
||||
) {
|
||||
values = Some(infer::ValuePairs::Types(ExpectedFound {
|
||||
expected: normalized.value,
|
||||
found: data.ty,
|
||||
}));
|
||||
err_buf = error;
|
||||
err = &err_buf;
|
||||
}
|
||||
}
|
||||
|
||||
let mut diag = struct_span_err!(
|
||||
self.tcx.sess, origin.span(), E0271,
|
||||
"type mismatch resolving `{}`", predicate
|
||||
);
|
||||
self.note_type_err(&mut diag, origin, values, err);
|
||||
self.note_obligation_cause(&mut diag, obligation);
|
||||
diag.emit();
|
||||
});
|
||||
}
|
||||
|
||||
fn impl_substs(&self,
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
pub fn crate_disambiguator(self, cnum: ast::CrateNum) -> token::InternedString {
|
||||
if cnum == LOCAL_CRATE {
|
||||
self.sess.crate_disambiguator.get().as_str()
|
||||
self.sess.local_crate_disambiguator()
|
||||
} else {
|
||||
self.sess.cstore.crate_disambiguator(cnum)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1018,3 +1018,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> {
|
|||
self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::error::ExpectedFound {
|
||||
expected: self.expected.fold_with(folder),
|
||||
found: self.found.fold_with(folder),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.expected.visit_with(visitor) || self.found.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
pat_util::arm_contains_ref_binding(arm)
|
||||
}
|
||||
|
||||
pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
|
||||
for field in def.all_fields() {
|
||||
let field_ty = field.ty(self, substs);
|
||||
if let TyError = field_ty.sty {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns the type of element at index `i` in tuple or tuple-like type `t`.
|
||||
/// For an enum `t`, `variant` is None only if `t` is a univariant enum.
|
||||
pub fn positional_element_ty(self,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue