Merge branch 'master' into 35123-map3
This commit is contained in:
commit
20c10913ff
757 changed files with 23893 additions and 20370 deletions
|
|
@ -269,6 +269,7 @@ class RustBuild:
|
|||
sys.exit(ret)
|
||||
|
||||
def build_triple(self):
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
config = self.get_toml('build')
|
||||
if config:
|
||||
return config
|
||||
|
|
@ -276,8 +277,8 @@ class RustBuild:
|
|||
if config:
|
||||
return config
|
||||
try:
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip()
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip()
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding)
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding)
|
||||
except (subprocess.CalledProcessError, WindowsError):
|
||||
if sys.platform == 'win32':
|
||||
return 'x86_64-pc-windows-msvc'
|
||||
|
|
@ -289,7 +290,8 @@ class RustBuild:
|
|||
# Darwin's `uname -s` lies and always returns i386. We have to use
|
||||
# sysctl instead.
|
||||
if ostype == 'Darwin' and cputype == 'i686':
|
||||
sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64'])
|
||||
args = ['sysctl', 'hw.optional.x86_64']
|
||||
sysctl = subprocess.check_output(args).decode(default_encoding)
|
||||
if ': 1' in sysctl:
|
||||
cputype = 'x86_64'
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@ pub fn compiletest(build: &Build,
|
|||
if let Some(ref dir) = build.lldb_python_dir {
|
||||
cmd.arg("--lldb-python-dir").arg(dir);
|
||||
}
|
||||
let llvm_config = build.llvm_config(target);
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
|
||||
cmd.args(&build.flags.args);
|
||||
|
||||
|
|
@ -158,7 +161,6 @@ pub fn compiletest(build: &Build,
|
|||
// Only pass correct values for these flags for the `run-make` suite as it
|
||||
// requires that a C++ compiler was configured which isn't always the case.
|
||||
if suite == "run-make" {
|
||||
let llvm_config = build.llvm_config(target);
|
||||
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
|
||||
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
|
||||
cmd.arg("--cc").arg(build.cc(target))
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ pub fn clean(build: &Build) {
|
|||
|
||||
let out = build.out.join(host);
|
||||
|
||||
rm_rf(build, &out.join("compiler-rt"));
|
||||
rm_rf(build, &out.join("doc"));
|
||||
|
||||
for stage in 0..4 {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@
|
|||
//! compiler. This module is also responsible for assembling the sysroot as it
|
||||
//! goes along from the output of the previous stage.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::output;
|
||||
use filetime::FileTime;
|
||||
|
||||
use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
|
||||
use {Build, Compiler, Mode};
|
||||
|
|
@ -35,13 +37,23 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
|
||||
compiler.host, target);
|
||||
|
||||
// Move compiler-rt into place as it'll be required by the compiler when
|
||||
// building the standard library to link the dylib of libstd
|
||||
let libdir = build.sysroot_libdir(compiler, target);
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
copy(&build.compiler_rt_built.borrow()[target],
|
||||
&libdir.join(staticlib("compiler-rt", target)));
|
||||
// FIXME(stage0) remove this `if` after the next snapshot
|
||||
// The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
|
||||
// never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
|
||||
// `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
|
||||
// an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
|
||||
// it to the final binary because now `libcore.rlib` also contains the symbols that
|
||||
// `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
|
||||
// symbols are used instead of `libcompiler-rt.a`'s.
|
||||
if compiler.stage == 0 {
|
||||
let rtlib = &staticlib("compiler-rt", target);
|
||||
let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
|
||||
.join(target).join("lib").join(rtlib);
|
||||
copy(&src, &libdir.join(rtlib));
|
||||
}
|
||||
|
||||
// Some platforms have startup objects that may be required to produce the
|
||||
// libstd dynamic library, for example.
|
||||
|
|
@ -59,13 +71,14 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
}
|
||||
}
|
||||
if let Some(ref p) = build.config.musl_root {
|
||||
if target.contains("musl") {
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
}
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libstd_stamp(build, compiler, target));
|
||||
std_link(build, target, compiler, compiler.host);
|
||||
}
|
||||
|
||||
|
|
@ -83,26 +96,24 @@ pub fn std_link(build: &Build,
|
|||
|
||||
// If we're linking one compiler host's output into another, then we weren't
|
||||
// called from the `std` method above. In that case we clean out what's
|
||||
// already there and then also link compiler-rt into place.
|
||||
// already there.
|
||||
if host != compiler.host {
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
copy(&build.compiler_rt_built.borrow()[target],
|
||||
&libdir.join(staticlib("compiler-rt", target)));
|
||||
}
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
copy_third_party_objects(build, target, &libdir);
|
||||
copy_musl_third_party_objects(build, &libdir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the crt(1,i,n).o startup objects
|
||||
///
|
||||
/// Only required for musl targets that statically link to libc
|
||||
fn copy_third_party_objects(build: &Build, target: &str, into: &Path) {
|
||||
fn copy_musl_third_party_objects(build: &Build, into: &Path) {
|
||||
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
|
||||
copy(&compiler_file(build.cc(target), obj), &into.join(obj));
|
||||
copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,14 +128,16 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
|
|||
return
|
||||
}
|
||||
let compiler = Compiler::new(0, &build.config.build);
|
||||
let compiler = build.compiler_path(&compiler);
|
||||
let compiler_path = build.compiler_path(&compiler);
|
||||
|
||||
for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
|
||||
let file = t!(file);
|
||||
build.run(Command::new(&compiler)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
.arg(file.path()));
|
||||
let mut cmd = Command::new(&compiler_path);
|
||||
build.add_bootstrap_key(&compiler, &mut cmd);
|
||||
build.run(cmd.arg("--target").arg(target)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
.arg(file.path()));
|
||||
}
|
||||
|
||||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
|
|
@ -141,11 +154,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
|
||||
compiler.host, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
|
||||
build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target));
|
||||
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
|
||||
let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libtest_stamp(build, compiler, target));
|
||||
test_link(build, target, compiler, compiler.host);
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +187,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
compiler.stage, compiler.host, target);
|
||||
|
||||
let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
|
||||
build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target));
|
||||
build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target));
|
||||
|
||||
let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build");
|
||||
cargo.arg("--features").arg(build.rustc_features())
|
||||
|
|
@ -203,6 +217,10 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
cargo.env("LLVM_RUSTLLVM", "1");
|
||||
}
|
||||
cargo.env("LLVM_CONFIG", build.llvm_config(target));
|
||||
let target_config = build.config.target_config.get(target);
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
cargo.env("CFG_LLVM_ROOT", s);
|
||||
}
|
||||
if build.config.llvm_static_stdcpp {
|
||||
cargo.env("LLVM_STATIC_STDCPP",
|
||||
compiler_file(build.cxx(target), "libstdc++.a"));
|
||||
|
|
@ -234,14 +252,14 @@ pub fn rustc_link(build: &Build,
|
|||
|
||||
/// Cargo's output path for the standard library in a given stage, compiled
|
||||
/// by a particular compiler for the specified target.
|
||||
fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib")
|
||||
fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
|
||||
}
|
||||
|
||||
/// Cargo's output path for libtest in a given stage, compiled by a particular
|
||||
/// compiler for the specified target.
|
||||
fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib")
|
||||
fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
|
||||
}
|
||||
|
||||
fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
|
||||
|
|
@ -354,10 +372,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
|
|||
// Maybe when libstd is compiled it should clear out the rustc of the
|
||||
// corresponding stage?
|
||||
// let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target);
|
||||
// build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
|
||||
// build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target));
|
||||
|
||||
let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool)));
|
||||
build.run(&mut cargo);
|
||||
}
|
||||
|
||||
/// Updates the mtime of a stamp file if necessary, only changing it if it's
|
||||
/// older than some other file in the same directory.
|
||||
///
|
||||
/// We don't know what file Cargo is going to output (because there's a hash in
|
||||
/// the file name) but we know where it's going to put it. We use this helper to
|
||||
/// detect changes to that output file by looking at the modification time for
|
||||
/// all files in a directory and updating the stamp if any are newer.
|
||||
fn update_mtime(path: &Path) {
|
||||
let mut max = None;
|
||||
if let Ok(entries) = path.parent().unwrap().read_dir() {
|
||||
for entry in entries.map(|e| t!(e)) {
|
||||
if t!(entry.file_type()).is_file() {
|
||||
let meta = t!(entry.metadata());
|
||||
let time = FileTime::from_last_modification_time(&meta);
|
||||
max = cmp::max(max, Some(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !max.is_none() && max <= Some(mtime(path)) {
|
||||
return
|
||||
}
|
||||
t!(File::create(path));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@ pub struct Config {
|
|||
|
||||
// misc
|
||||
pub channel: String,
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub prefix: Option<String>,
|
||||
pub codegen_tests: bool,
|
||||
pub nodejs: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
|
|
@ -89,6 +91,7 @@ pub struct Target {
|
|||
pub cc: Option<PathBuf>,
|
||||
pub cxx: Option<PathBuf>,
|
||||
pub ndk: Option<PathBuf>,
|
||||
pub musl_root: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Structure of the `config.toml` file that configuration is read from.
|
||||
|
|
@ -144,6 +147,7 @@ struct Rust {
|
|||
rpath: Option<bool>,
|
||||
optimize_tests: Option<bool>,
|
||||
debuginfo_tests: Option<bool>,
|
||||
codegen_tests: Option<bool>,
|
||||
}
|
||||
|
||||
/// TOML representation of how each build target is configured.
|
||||
|
|
@ -232,6 +236,7 @@ impl Config {
|
|||
set(&mut config.rust_optimize, rust.optimize);
|
||||
set(&mut config.rust_optimize_tests, rust.optimize_tests);
|
||||
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
|
||||
set(&mut config.codegen_tests, rust.codegen_tests);
|
||||
set(&mut config.rust_rpath, rust.rpath);
|
||||
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
|
||||
set(&mut config.use_jemalloc, rust.use_jemalloc);
|
||||
|
|
@ -391,6 +396,9 @@ impl Config {
|
|||
self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
|
||||
self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
|
||||
}
|
||||
"CFG_NODEJS" if value.len() > 0 => {
|
||||
self.nodejs = Some(PathBuf::from(value));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
# Sample TOML configuration file for building Rust.
|
||||
#
|
||||
# To configure rustbuild, copy this file to the directory from which you will be
|
||||
# running the build, and name it config.toml.
|
||||
#
|
||||
# All options are commented out by default in this file, and they're commented
|
||||
# out with their default values. The build system by default looks for
|
||||
# `config.toml` in the current directory of a build for build configuration, but
|
||||
|
|
@ -115,10 +118,6 @@
|
|||
# nightly features
|
||||
#channel = "dev"
|
||||
|
||||
# The root location of the MUSL installation directory. The library directory
|
||||
# will also need to contain libunwind.a for an unwinding implementation.
|
||||
#musl-root = "..."
|
||||
|
||||
# By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix
|
||||
# platforms to ensure that the compiler is usable by default from the build
|
||||
# directory (as it links to a number of dynamic libraries). This may not be
|
||||
|
|
@ -130,6 +129,10 @@
|
|||
#optimize-tests = true
|
||||
#debuginfo-tests = true
|
||||
|
||||
# Flag indicating whether codegen tests will be run or not. If you get an error
|
||||
# saying that the FileCheck executable is missing, you may want to disable this.
|
||||
#codegen-tests = true
|
||||
|
||||
# =============================================================================
|
||||
# Options for specific targets
|
||||
#
|
||||
|
|
@ -160,3 +163,9 @@
|
|||
# the NDK for the target lives. This is used to find the C compiler to link and
|
||||
# build native code.
|
||||
#android-ndk = "/path/to/ndk"
|
||||
|
||||
# The root location of the MUSL installation directory. The library directory
|
||||
# will also need to contain libunwind.a for an unwinding implementation. Note
|
||||
# that this option only makes sense for MUSL targets that produce statically
|
||||
# linked binaries
|
||||
#musl-root = "..."
|
||||
|
|
|
|||
|
|
@ -388,6 +388,9 @@ pub fn rust_src(build: &Build) {
|
|||
// Rename directory, so that root folder of tarball has the correct name
|
||||
t!(fs::rename(&dst_src, &plain_dst_src));
|
||||
|
||||
// Create the version file
|
||||
write_file(&plain_dst_src.join("version"), build.version.as_bytes());
|
||||
|
||||
// Create plain source tarball
|
||||
let mut cmd = Command::new("tar");
|
||||
cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name))))
|
||||
|
|
@ -431,3 +434,8 @@ fn sanitize_sh(path: &Path) -> String {
|
|||
Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
|
||||
}
|
||||
}
|
||||
|
||||
fn write_file(path: &Path, data: &[u8]) {
|
||||
let mut vf = t!(fs::File::create(path));
|
||||
t!(vf.write_all(data));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ extern crate rustc_serialize;
|
|||
extern crate toml;
|
||||
extern crate regex;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
|
|
@ -46,7 +45,7 @@ use util::{exe, mtime, libdir, add_lib_path};
|
|||
/// * The error itself
|
||||
///
|
||||
/// This is currently used judiciously throughout the build system rather than
|
||||
/// using a `Result` with `try!`, but this may change on day...
|
||||
/// using a `Result` with `try!`, but this may change one day...
|
||||
macro_rules! t {
|
||||
($e:expr) => (match $e {
|
||||
Ok(e) => e,
|
||||
|
|
@ -131,7 +130,6 @@ pub struct Build {
|
|||
// Runtime state filled in later on
|
||||
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
|
||||
cxx: HashMap<String, gcc::Tool>,
|
||||
compiler_rt_built: RefCell<HashMap<String, PathBuf>>,
|
||||
}
|
||||
|
||||
/// The various "modes" of invoking Cargo.
|
||||
|
|
@ -198,7 +196,6 @@ impl Build {
|
|||
package_vers: String::new(),
|
||||
cc: HashMap::new(),
|
||||
cxx: HashMap::new(),
|
||||
compiler_rt_built: RefCell::new(HashMap::new()),
|
||||
gdb_version: None,
|
||||
lldb_version: None,
|
||||
lldb_python_dir: None,
|
||||
|
|
@ -252,9 +249,6 @@ impl Build {
|
|||
Llvm { _dummy } => {
|
||||
native::llvm(self, target.target);
|
||||
}
|
||||
CompilerRt { _dummy } => {
|
||||
native::compiler_rt(self, target.target);
|
||||
}
|
||||
TestHelpers { _dummy } => {
|
||||
native::test_helpers(self, target.target);
|
||||
}
|
||||
|
|
@ -585,6 +579,8 @@ impl Build {
|
|||
if mtime(&stamp) < mtime(input) {
|
||||
self.verbose(&format!("Dirty - {}", dir.display()));
|
||||
let _ = fs::remove_dir_all(dir);
|
||||
} else if stamp.exists() {
|
||||
return
|
||||
}
|
||||
t!(fs::create_dir_all(dir));
|
||||
t!(File::create(stamp));
|
||||
|
|
@ -839,11 +835,6 @@ impl Build {
|
|||
}
|
||||
}
|
||||
|
||||
/// Root output directory for compiler-rt compiled for `target`
|
||||
fn compiler_rt_out(&self, target: &str) -> PathBuf {
|
||||
self.out.join(target).join("compiler-rt")
|
||||
}
|
||||
|
||||
/// Root output directory for rust_test_helpers library compiled for
|
||||
/// `target`
|
||||
fn test_helpers_out(&self, target: &str) -> PathBuf {
|
||||
|
|
@ -977,6 +968,13 @@ impl Build {
|
|||
}
|
||||
return base
|
||||
}
|
||||
|
||||
/// Returns the "musl root" for this `target`, if defined
|
||||
fn musl_root(&self, target: &str) -> Option<&Path> {
|
||||
self.config.target_config[target].musl_root.as_ref()
|
||||
.or(self.config.musl_root.as_ref())
|
||||
.map(|p| &**p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Compiler<'a> {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use cmake;
|
|||
use gcc;
|
||||
|
||||
use Build;
|
||||
use util::{staticlib, up_to_date};
|
||||
use util::up_to_date;
|
||||
|
||||
/// Compile LLVM for `target`.
|
||||
pub fn llvm(build: &Build, target: &str) {
|
||||
|
|
@ -131,401 +131,6 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
|
|||
panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
|
||||
}
|
||||
|
||||
/// Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
///
|
||||
/// 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 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());
|
||||
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
|
||||
}
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
||||
|
||||
/// Compiles the `rust_test_helpers.c` library which we used in various
|
||||
/// `run-pass` test suites for ABI testing.
|
||||
pub fn test_helpers(build: &Build, target: &str) {
|
||||
|
|
|
|||
|
|
@ -75,6 +75,12 @@ pub fn check(build: &mut Build) {
|
|||
|
||||
need_cmd("python".as_ref());
|
||||
|
||||
// If a manual nodejs was added to the config,
|
||||
// of if a nodejs install is detected through config, use it.
|
||||
if let Some(ref s) = build.config.nodejs {
|
||||
need_cmd(s.as_ref());
|
||||
}
|
||||
|
||||
// We're gonna build some custom C code here and there, host triples
|
||||
// also build some C++ shims for LLVM so we need a C++ compiler.
|
||||
for target in build.config.target.iter() {
|
||||
|
|
@ -111,8 +117,8 @@ pub fn check(build: &mut Build) {
|
|||
|
||||
// Make sure musl-root is valid if specified
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
match build.config.musl_root {
|
||||
Some(ref root) => {
|
||||
match build.musl_root(target) {
|
||||
Some(root) => {
|
||||
if fs::metadata(root.join("lib/libc.a")).is_err() {
|
||||
panic!("couldn't find libc.a in musl dir: {}",
|
||||
root.join("lib").display());
|
||||
|
|
@ -123,8 +129,9 @@ pub fn check(build: &mut Build) {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
panic!("when targeting MUSL the build.musl-root option \
|
||||
must be specified in config.toml")
|
||||
panic!("when targeting MUSL either the build.musl-root \
|
||||
option or the target.$TARGET.musl-root one must \
|
||||
be specified in config.toml")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ macro_rules! targets {
|
|||
// There aren't really any parameters to this, but empty structs
|
||||
// with braces are unstable so we just pick something that works.
|
||||
(llvm, Llvm { _dummy: () }),
|
||||
(compiler_rt, CompilerRt { _dummy: () }),
|
||||
(test_helpers, TestHelpers { _dummy: () }),
|
||||
(debugger_scripts, DebuggerScripts { stage: u32 }),
|
||||
|
||||
|
|
@ -334,8 +333,7 @@ impl<'a> Step<'a> {
|
|||
vec![self.libstd(compiler)]
|
||||
}
|
||||
Source::Libstd { compiler } => {
|
||||
vec![self.compiler_rt(()),
|
||||
self.rustc(compiler.stage).target(compiler.host)]
|
||||
vec![self.rustc(compiler.stage).target(compiler.host)]
|
||||
}
|
||||
Source::LibrustcLink { compiler, host } => {
|
||||
vec![self.librustc(compiler),
|
||||
|
|
@ -348,7 +346,6 @@ impl<'a> Step<'a> {
|
|||
vec![self.libstd(compiler),
|
||||
self.target(host).rustc(compiler.stage)]
|
||||
}
|
||||
Source::CompilerRt { _dummy } => Vec::new(),
|
||||
Source::Llvm { _dummy } => Vec::new(),
|
||||
Source::TestHelpers { _dummy } => Vec::new(),
|
||||
Source::DebuggerScripts { stage: _ } => Vec::new(),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use filetime::FileTime;
|
|||
|
||||
/// Returns the `name` as the filename of a static library for `target`.
|
||||
pub fn staticlib(name: &str, target: &str) -> String {
|
||||
if target.contains("windows-msvc") {
|
||||
if target.contains("windows") {
|
||||
format!("{}.lib", name)
|
||||
} else {
|
||||
format!("lib{}.a", name)
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ extern {
|
|||
|
||||
fn main() {
|
||||
println!("You have readline version {} installed.",
|
||||
rl_readline_version as i32);
|
||||
unsafe { rl_readline_version as i32 });
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan
|
|||
* `system`
|
||||
* `C`
|
||||
* `win64`
|
||||
* `sysv64`
|
||||
|
||||
Most of the abis in this list are self-explanatory, but the `system` abi may
|
||||
seem a little odd. This constraint selects whatever the appropriate ABI is for
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ binary downloads][install-page].
|
|||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
* Windows (7, 8, Server 2008 R2)
|
||||
* Windows (7+)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well
|
|||
If it wasn’t, we couldn’t take a mutable borrow to an immutable value.
|
||||
|
||||
You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`,
|
||||
this is because `y` is a `&mut` reference. You'll need to use astrisks to
|
||||
this is because `y` is a `&mut` reference. You'll need to use asterisks to
|
||||
access the contents of a reference as well.
|
||||
|
||||
Otherwise, `&mut` references are like references. There _is_ a large
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ won’t have its methods:
|
|||
[write]: ../std/io/trait.Write.html
|
||||
|
||||
```rust,ignore
|
||||
let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||
let buf = b"whatever"; // byte string literal. buf: &[u8; 8]
|
||||
let result = f.write(buf);
|
||||
# result.unwrap(); // ignore the error
|
||||
|
|
@ -291,10 +291,10 @@ let result = f.write(buf);
|
|||
|
||||
We need to `use` the `Write` trait first:
|
||||
|
||||
```rust,ignore
|
||||
```rust,no_run
|
||||
use std::io::Write;
|
||||
|
||||
let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||
let buf = b"whatever";
|
||||
let result = f.write(buf);
|
||||
# result.unwrap(); // ignore the error
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ let mut data = vec![1, 2, 3];
|
|||
let x = &data[0];
|
||||
|
||||
// OH NO! `push` causes the backing storage of `data` to be reallocated.
|
||||
// Dangling pointer! User after free! Alas!
|
||||
// Dangling pointer! Use after free! Alas!
|
||||
// (this does not compile in Rust)
|
||||
data.push(4);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ can therefore be trusted. You can use `unsafe` on a trait implementation
|
|||
to declare that the implementation of that trait has adhered to whatever
|
||||
contracts the trait's documentation requires.
|
||||
|
||||
There is also the `#[unsafe_no_drop_flag]` attribute, which exists for
|
||||
historic reasons and is being phased out. See the section on [drop flags]
|
||||
for details.
|
||||
|
||||
The standard library has a number of unsafe functions, including:
|
||||
|
||||
* `slice::get_unchecked`, which performs unchecked indexing, allowing
|
||||
|
|
|
|||
|
|
@ -1677,6 +1677,7 @@ 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 "sysv64"` -- The default for C code on non-Windows x86\_64.
|
||||
* `extern "aapcs"` -- The default for ARM.
|
||||
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
|
||||
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
|
||||
|
|
@ -2058,10 +2059,6 @@ macro scope.
|
|||
outside of its dynamic extent), and thus this attribute has the word
|
||||
"unsafe" in its name. To use this, the
|
||||
`unsafe_destructor_blind_to_params` feature gate must be enabled.
|
||||
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
|
||||
destructors from being run twice. Destructors might be run multiple times on
|
||||
the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
|
||||
gate must be enabled.
|
||||
- `doc` - Doc comments such as `/// foo` are equivalent to `#[doc = "foo"]`.
|
||||
- `rustc_on_unimplemented` - Write a custom note to be shown along with the error
|
||||
when the trait is found to be unimplemented on a type.
|
||||
|
|
@ -2070,6 +2067,9 @@ macro scope.
|
|||
trait of the same name. `{Self}` will be replaced with the type that is supposed
|
||||
to implement the trait but doesn't. To use this, the `on_unimplemented` feature gate
|
||||
must be enabled.
|
||||
- `must_use` - on structs and enums, will warn if a value of this type isn't used or
|
||||
assigned to a variable. You may also include an optional message by using
|
||||
`#[must_use = "message"]` which will be given alongside the warning.
|
||||
|
||||
### Conditional compilation
|
||||
|
||||
|
|
@ -2441,6 +2441,9 @@ The currently implemented features of the reference compiler are:
|
|||
into a Rust program. This capability, especially the signature for the
|
||||
annotated function, is subject to change.
|
||||
|
||||
* `static_in_const` - Enables lifetime elision with a `'static` default for
|
||||
`const` and `static` item declarations.
|
||||
|
||||
* `thread_local` - The usage of the `#[thread_local]` attribute is experimental
|
||||
and should be seen as unstable. This attribute is used to
|
||||
declare a `static` as being unique per-thread leveraging
|
||||
|
|
@ -2454,12 +2457,6 @@ The currently implemented features of the reference compiler are:
|
|||
* `unboxed_closures` - Rust's new closure design, which is currently a work in
|
||||
progress feature with many known bugs.
|
||||
|
||||
* `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute,
|
||||
which removes hidden flag added to a type that
|
||||
implements the `Drop` trait. The design for the
|
||||
`Drop` flag is subject to change, and this feature
|
||||
may be removed in the future.
|
||||
|
||||
* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
|
||||
which have not been marked with a stability marker.
|
||||
Such items should not be allowed by the compiler to exist,
|
||||
|
|
@ -2485,6 +2482,9 @@ The currently implemented features of the reference compiler are:
|
|||
|
||||
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
|
||||
|
||||
* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention
|
||||
(e.g. `extern "sysv64" func fn_();`)
|
||||
|
||||
If a feature is promoted to a language feature, then all existing programs will
|
||||
start to receive compilation warnings about `#![feature]` directives which enabled
|
||||
the new feature (because the directive is no longer necessary). However, if a
|
||||
|
|
|
|||
|
|
@ -331,6 +331,33 @@ impl<T: ?Sized> Arc<T> {
|
|||
deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable(feature = "ptr_eq",
|
||||
reason = "newly added",
|
||||
issue = "36497")]
|
||||
/// Return whether two `Arc` references point to the same value
|
||||
/// (not just values that compare equal).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_eq)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5);
|
||||
/// let same_five = five.clone();
|
||||
/// let other_five = Arc::new(5);
|
||||
///
|
||||
/// assert!(Arc::ptr_eq(&five, &same_five));
|
||||
/// assert!(!Arc::ptr_eq(&five, &other_five));
|
||||
/// ```
|
||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||
let this_ptr: *const ArcInner<T> = *this.ptr;
|
||||
let other_ptr: *const ArcInner<T> = *other.ptr;
|
||||
this_ptr == other_ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -718,6 +745,7 @@ impl<T: ?Sized> Clone for Weak<T> {
|
|||
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
impl<T> Default for Weak<T> {
|
||||
/// Constructs a new `Weak<T>` without an accompanying instance of T.
|
||||
fn default() -> Weak<T> {
|
||||
Weak::new()
|
||||
}
|
||||
|
|
@ -923,6 +951,7 @@ impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Arc<T> {
|
||||
/// Creates a new `Arc<T>`, with the `Default` value for T.
|
||||
fn default() -> Arc<T> {
|
||||
Arc::new(Default::default())
|
||||
}
|
||||
|
|
@ -1198,6 +1227,16 @@ mod tests {
|
|||
let foo: Weak<usize> = Weak::new();
|
||||
assert!(foo.upgrade().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ptr_eq() {
|
||||
let five = Arc::new(5);
|
||||
let same_five = five.clone();
|
||||
let other_five = Arc::new(5);
|
||||
|
||||
assert!(Arc::ptr_eq(&five, &same_five));
|
||||
assert!(!Arc::ptr_eq(&five, &other_five));
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ impl<T: ?Sized> Box<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Box<T> {
|
||||
/// Creates a `Box<T>`, with the `Default` value for T.
|
||||
fn default() -> Box<T> {
|
||||
box Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,6 +376,33 @@ impl<T: ?Sized> Rc<T> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable(feature = "ptr_eq",
|
||||
reason = "newly added",
|
||||
issue = "36497")]
|
||||
/// Return whether two `Rc` references point to the same value
|
||||
/// (not just values that compare equal).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_eq)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// let same_five = five.clone();
|
||||
/// let other_five = Rc::new(5);
|
||||
///
|
||||
/// assert!(Rc::ptr_eq(&five, &same_five));
|
||||
/// assert!(!Rc::ptr_eq(&five, &other_five));
|
||||
/// ```
|
||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||
let this_ptr: *const RcBox<T> = *this.ptr;
|
||||
let other_ptr: *const RcBox<T> = *other.ptr;
|
||||
this_ptr == other_ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Rc<T> {
|
||||
|
|
@ -870,6 +897,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
|
|||
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
impl<T> Default for Weak<T> {
|
||||
/// Creates a new `Weak<T>`.
|
||||
fn default() -> Weak<T> {
|
||||
Weak::new()
|
||||
}
|
||||
|
|
@ -1173,6 +1201,16 @@ mod tests {
|
|||
let foo: Weak<usize> = Weak::new();
|
||||
assert!(foo.upgrade().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ptr_eq() {
|
||||
let five = Rc::new(5);
|
||||
let same_five = five.clone();
|
||||
let other_five = Rc::new(5);
|
||||
|
||||
assert!(Rc::ptr_eq(&five, &same_five));
|
||||
assert!(!Rc::ptr_eq(&five, &other_five));
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ const MIN_ALIGN: usize = 8;
|
|||
#[cfg(all(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc64")))]
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
// MALLOCX_ALIGN(a) macro
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@
|
|||
target_arch = "asmjs")))]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(target_arch = "x86_64",
|
||||
target_arch = "aarch64")))]
|
||||
target_arch = "aarch64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@
|
|||
//! of individual objects while the arena itself is still alive. The benefit
|
||||
//! of an arena is very fast allocation; just a pointer bump.
|
||||
//!
|
||||
//! This crate has two arenas implemented: `TypedArena`, which is a simpler
|
||||
//! arena but can only hold objects of a single type, and `Arena`, which is a
|
||||
//! more complex, slower arena which can hold objects of any type.
|
||||
//! This crate implements `TypedArena`, a simple arena that can only hold
|
||||
//! objects of a single type.
|
||||
|
||||
#![crate_name = "arena"]
|
||||
#![unstable(feature = "rustc_private", issue = "27812")]
|
||||
|
|
@ -51,8 +50,11 @@ use std::ptr;
|
|||
use alloc::heap;
|
||||
use alloc::raw_vec::RawVec;
|
||||
|
||||
/// A faster arena that can hold objects of only one type.
|
||||
/// An arena that can hold objects of only one type.
|
||||
pub struct TypedArena<T> {
|
||||
/// The capacity of the first chunk (once it is allocated).
|
||||
first_chunk_capacity: usize,
|
||||
|
||||
/// A pointer to the next object to be allocated.
|
||||
ptr: Cell<*mut T>,
|
||||
|
||||
|
|
@ -60,7 +62,7 @@ pub struct TypedArena<T> {
|
|||
/// reached, a new chunk is allocated.
|
||||
end: Cell<*mut T>,
|
||||
|
||||
/// A vector arena segments.
|
||||
/// A vector of arena chunks.
|
||||
chunks: RefCell<Vec<TypedArenaChunk<T>>>,
|
||||
|
||||
/// Marker indicating that dropping the arena causes its owned
|
||||
|
|
@ -69,7 +71,7 @@ pub struct TypedArena<T> {
|
|||
}
|
||||
|
||||
struct TypedArenaChunk<T> {
|
||||
/// Pointer to the next arena segment.
|
||||
/// The raw storage for the arena chunk.
|
||||
storage: RawVec<T>,
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +119,7 @@ impl<T> TypedArenaChunk<T> {
|
|||
const PAGE: usize = 4096;
|
||||
|
||||
impl<T> TypedArena<T> {
|
||||
/// Creates a new `TypedArena` with preallocated space for many objects.
|
||||
/// Creates a new `TypedArena`.
|
||||
#[inline]
|
||||
pub fn new() -> TypedArena<T> {
|
||||
// Reserve at least one page.
|
||||
|
|
@ -125,18 +127,18 @@ impl<T> TypedArena<T> {
|
|||
TypedArena::with_capacity(PAGE / elem_size)
|
||||
}
|
||||
|
||||
/// Creates a new `TypedArena` with preallocated space for the given number of
|
||||
/// objects.
|
||||
/// Creates a new `TypedArena`. Each chunk used within the arena will have
|
||||
/// space for at least the given number of objects.
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> TypedArena<T> {
|
||||
unsafe {
|
||||
let chunk = TypedArenaChunk::<T>::new(cmp::max(1, capacity));
|
||||
TypedArena {
|
||||
ptr: Cell::new(chunk.start()),
|
||||
end: Cell::new(chunk.end()),
|
||||
chunks: RefCell::new(vec![chunk]),
|
||||
_own: PhantomData,
|
||||
}
|
||||
TypedArena {
|
||||
first_chunk_capacity: cmp::max(1, capacity),
|
||||
// We set both `ptr` and `end` to 0 so that the first call to
|
||||
// alloc() will trigger a grow().
|
||||
ptr: Cell::new(0 as *mut T),
|
||||
end: Cell::new(0 as *mut T),
|
||||
chunks: RefCell::new(vec![]),
|
||||
_own: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,16 +173,22 @@ impl<T> TypedArena<T> {
|
|||
fn grow(&self) {
|
||||
unsafe {
|
||||
let mut chunks = self.chunks.borrow_mut();
|
||||
let prev_capacity = chunks.last().unwrap().storage.cap();
|
||||
let new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
if chunks.last_mut().unwrap().storage.double_in_place() {
|
||||
self.end.set(chunks.last().unwrap().end());
|
||||
let (chunk, new_capacity);
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
if last_chunk.storage.double_in_place() {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
let prev_capacity = last_chunk.storage.cap();
|
||||
new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
}
|
||||
} else {
|
||||
let chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
new_capacity = self.first_chunk_capacity;
|
||||
}
|
||||
chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
/// Clears the arena. Deallocates all but the longest chunk which may be reused.
|
||||
|
|
@ -188,12 +196,14 @@ impl<T> TypedArena<T> {
|
|||
unsafe {
|
||||
// Clear the last chunk, which is partially filled.
|
||||
let mut chunks_borrow = self.chunks.borrow_mut();
|
||||
let last_idx = chunks_borrow.len() - 1;
|
||||
self.clear_last_chunk(&mut chunks_borrow[last_idx]);
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..last_idx) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
if let Some(mut last_chunk) = chunks_borrow.pop() {
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
}
|
||||
chunks_borrow.push(last_chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -230,13 +240,14 @@ impl<T> Drop for TypedArena<T> {
|
|||
unsafe {
|
||||
// Determine how much was filled.
|
||||
let mut chunks_borrow = self.chunks.borrow_mut();
|
||||
let mut last_chunk = chunks_borrow.pop().unwrap();
|
||||
// Drop the contents of the last chunk.
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
if let Some(mut last_chunk) = chunks_borrow.pop() {
|
||||
// Drop the contents of the last chunk.
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
}
|
||||
}
|
||||
// RawVec handles deallocation of `last_chunk` and `self.chunks`.
|
||||
}
|
||||
|
|
@ -260,6 +271,12 @@ mod tests {
|
|||
z: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_unused() {
|
||||
let arena: TypedArena<Point> = TypedArena::new();
|
||||
assert!(arena.chunks.borrow().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arena_alloc_nested() {
|
||||
struct Inner {
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ impl<T: Clone> Clone for BinaryHeap<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord> Default for BinaryHeap<T> {
|
||||
/// Creates an empty `BinaryHeap<T>`.
|
||||
#[inline]
|
||||
fn default() -> BinaryHeap<T> {
|
||||
BinaryHeap::new()
|
||||
|
|
@ -884,58 +885,61 @@ struct Hole<'a, T: 'a> {
|
|||
|
||||
impl<'a, T> Hole<'a, T> {
|
||||
/// Create a new Hole at index `pos`.
|
||||
fn new(data: &'a mut [T], pos: usize) -> Self {
|
||||
unsafe {
|
||||
let elt = ptr::read(&data[pos]);
|
||||
Hole {
|
||||
data: data,
|
||||
elt: Some(elt),
|
||||
pos: pos,
|
||||
}
|
||||
///
|
||||
/// Unsafe because pos must be within the data slice.
|
||||
#[inline]
|
||||
unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
|
||||
debug_assert!(pos < data.len());
|
||||
let elt = ptr::read(&data[pos]);
|
||||
Hole {
|
||||
data: data,
|
||||
elt: Some(elt),
|
||||
pos: pos,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn pos(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
|
||||
/// Return a reference to the element removed
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn element(&self) -> &T {
|
||||
self.elt.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Return a reference to the element at `index`.
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
///
|
||||
/// Unsafe because index must not equal pos.
|
||||
#[inline(always)]
|
||||
/// Unsafe because index must be within the data slice and not equal to pos.
|
||||
#[inline]
|
||||
unsafe fn get(&self, index: usize) -> &T {
|
||||
debug_assert!(index != self.pos);
|
||||
&self.data[index]
|
||||
debug_assert!(index < self.data.len());
|
||||
self.data.get_unchecked(index)
|
||||
}
|
||||
|
||||
/// Move hole to new location
|
||||
///
|
||||
/// Unsafe because index must not equal pos.
|
||||
#[inline(always)]
|
||||
/// Unsafe because index must be within the data slice and not equal to pos.
|
||||
#[inline]
|
||||
unsafe fn move_to(&mut self, index: usize) {
|
||||
debug_assert!(index != self.pos);
|
||||
let index_ptr: *const _ = &self.data[index];
|
||||
let hole_ptr = &mut self.data[self.pos];
|
||||
debug_assert!(index < self.data.len());
|
||||
let index_ptr: *const _ = self.data.get_unchecked(index);
|
||||
let hole_ptr = self.data.get_unchecked_mut(self.pos);
|
||||
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
|
||||
self.pos = index;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for Hole<'a, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// fill the hole again
|
||||
unsafe {
|
||||
let pos = self.pos;
|
||||
ptr::write(&mut self.data[pos], self.elt.take().unwrap());
|
||||
ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ impl<'a, B: ?Sized> Default for Cow<'a, B>
|
|||
where B: ToOwned,
|
||||
<B as ToOwned>::Owned: Default
|
||||
{
|
||||
/// Creates an owned Cow<'a, B> with the default value for the contained owned value.
|
||||
fn default() -> Cow<'a, B> {
|
||||
Owned(<B as ToOwned>::Owned::default())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,12 @@ use self::Entry::*;
|
|||
/// however, performance is excellent.
|
||||
///
|
||||
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
|
||||
/// any other key, as determined by the `Ord` trait, changes while it is in the map. This is
|
||||
/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
|
||||
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
|
||||
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
|
||||
///
|
||||
/// [`Ord`]: ../../std/cmp/trait.Ord.html
|
||||
/// [`Cell`]: ../../std/cell/struct.Cell.html
|
||||
/// [`RefCell`]: ../../std/cell/struct.RefCell.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1663,6 +1667,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
|
|||
}
|
||||
|
||||
impl<K: Ord, V> Default for BTreeMap<K, V> {
|
||||
/// Creates an empty `BTreeMap<K, V>`.
|
||||
fn default() -> BTreeMap<K, V> {
|
||||
BTreeMap::new()
|
||||
}
|
||||
|
|
@ -2020,7 +2025,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
|
|||
self.key
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the VacantEntry's key,
|
||||
/// Sets the value of the entry with the `VacantEntry`'s key,
|
||||
/// and returns a mutable reference to it.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -2192,7 +2197,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
|
|||
self.handle.into_kv_mut().1
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the OccupiedEntry's key,
|
||||
/// Sets the value of the entry with the `OccupiedEntry`'s key,
|
||||
/// and returns the entry's old value.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -674,6 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord> Default for BTreeSet<T> {
|
||||
/// Makes an empty `BTreeSet<T>` with a reasonable choice of B.
|
||||
fn default() -> BTreeSet<T> {
|
||||
BTreeSet::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ impl<T> LinkedList<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for LinkedList<T> {
|
||||
/// Creates an empty `LinkedList<T>`.
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
|
|
|
|||
|
|
@ -1594,6 +1594,49 @@ impl str {
|
|||
result
|
||||
}
|
||||
|
||||
/// Replaces first N matches of a pattern with another string.
|
||||
///
|
||||
/// `replacen` creates a new [`String`], and copies the data from this string slice into it.
|
||||
/// While doing so, it attempts to find matches of a pattern. If it finds any, it
|
||||
/// replaces them with the replacement string slice at most `N` times.
|
||||
///
|
||||
/// [`String`]: string/struct.String.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(str_replacen)]
|
||||
/// let s = "foo foo 123 foo";
|
||||
/// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
|
||||
/// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3));
|
||||
/// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1));
|
||||
/// ```
|
||||
///
|
||||
/// When the pattern doesn't match:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(str_replacen)]
|
||||
/// let s = "this is old";
|
||||
/// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
|
||||
/// ```
|
||||
#[unstable(feature = "str_replacen",
|
||||
issue = "36436",
|
||||
reason = "only need to replace first N matches")]
|
||||
pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
|
||||
// Hope to reduce the times of re-allocation
|
||||
let mut result = String::with_capacity(32);
|
||||
let mut last_end = 0;
|
||||
for (start, part) in self.match_indices(pat).take(count) {
|
||||
result.push_str(unsafe { self.slice_unchecked(last_end, start) });
|
||||
result.push_str(to);
|
||||
last_end = start + part.len();
|
||||
}
|
||||
result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the lowercase equivalent of this string slice, as a new [`String`].
|
||||
///
|
||||
/// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
|
||||
|
|
|
|||
|
|
@ -1567,6 +1567,7 @@ impl_eq! { Cow<'a, str>, String }
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Default for String {
|
||||
/// Creates an empty `String`.
|
||||
#[inline]
|
||||
fn default() -> String {
|
||||
String::new()
|
||||
|
|
|
|||
|
|
@ -1046,21 +1046,27 @@ impl<T: Clone> Vec<T> {
|
|||
self.reserve(n);
|
||||
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let mut ptr = self.as_mut_ptr().offset(len as isize);
|
||||
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
|
||||
// Use SetLenOnDrop to work around bug where compiler
|
||||
// may not realize the store through `ptr` trough self.set_len()
|
||||
// don't alias.
|
||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||
|
||||
// Write all elements except the last one
|
||||
for i in 1..n {
|
||||
for _ in 1..n {
|
||||
ptr::write(ptr, value.clone());
|
||||
ptr = ptr.offset(1);
|
||||
// Increment the length in every step in case clone() panics
|
||||
self.set_len(len + i);
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, value);
|
||||
self.set_len(len + n);
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
// len set by scope guard
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1085,20 +1091,56 @@ impl<T: Clone> Vec<T> {
|
|||
pub fn extend_from_slice(&mut self, other: &[T]) {
|
||||
self.reserve(other.len());
|
||||
|
||||
for i in 0..other.len() {
|
||||
// Unsafe code so this can be optimised to a memcpy (or something
|
||||
// similarly fast) when T is Copy. LLVM is easily confused, so any
|
||||
// extra operations during the loop can prevent this optimisation.
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let ptr = self.get_unchecked_mut(len) as *mut T;
|
||||
// Use SetLenOnDrop to work around bug where compiler
|
||||
// may not realize the store through `ptr` trough self.set_len()
|
||||
// don't alias.
|
||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||
|
||||
// Unsafe code so this can be optimised to a memcpy (or something
|
||||
// similarly fast) when T is Copy. LLVM is easily confused, so any
|
||||
// extra operations during the loop can prevent this optimisation.
|
||||
unsafe {
|
||||
ptr::write(self.get_unchecked_mut(len), other.get_unchecked(i).clone());
|
||||
self.set_len(len + 1);
|
||||
for i in 0..other.len() {
|
||||
ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone());
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
// len set by scope guard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
|
||||
//
|
||||
// The idea is: The length field in SetLenOnDrop is a local variable
|
||||
// that the optimizer will see does not alias with any stores through the Vec's data
|
||||
// pointer. This is a workaround for alias analysis issue #32155
|
||||
struct SetLenOnDrop<'a> {
|
||||
len: &'a mut usize,
|
||||
local_len: usize,
|
||||
}
|
||||
|
||||
impl<'a> SetLenOnDrop<'a> {
|
||||
#[inline]
|
||||
fn new(len: &'a mut usize) -> Self {
|
||||
SetLenOnDrop { local_len: *len, len: len }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn increment_len(&mut self, increment: usize) {
|
||||
self.local_len += increment;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for SetLenOnDrop<'a> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
*self.len = self.local_len;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> Vec<T> {
|
||||
/// Removes consecutive repeated elements in the vector.
|
||||
///
|
||||
|
|
@ -1610,6 +1652,7 @@ impl<T> Drop for Vec<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for Vec<T> {
|
||||
/// Creates an empty `Vec<T>`.
|
||||
fn default() -> Vec<T> {
|
||||
Vec::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ impl<T> Drop for VecDeque<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for VecDeque<T> {
|
||||
/// Creates an empty `VecDeque<T>`.
|
||||
#[inline]
|
||||
fn default() -> VecDeque<T> {
|
||||
VecDeque::new()
|
||||
|
|
|
|||
|
|
@ -39,30 +39,8 @@ fn test_hash() {
|
|||
assert!(::hash(&x) == ::hash(&y));
|
||||
}
|
||||
|
||||
struct Counter<'a, 'b> {
|
||||
i: &'a mut usize,
|
||||
expected: &'b [i32],
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
|
||||
extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool {
|
||||
assert_eq!(x, self.expected[*self.i]);
|
||||
*self.i += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> {
|
||||
type Output = bool;
|
||||
|
||||
extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool {
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
|
||||
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
|
||||
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
|
||||
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, Counter) -> bool,
|
||||
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool,
|
||||
{
|
||||
let mut set_a = BTreeSet::new();
|
||||
let mut set_b = BTreeSet::new();
|
||||
|
|
@ -71,7 +49,11 @@ fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
|
|||
for y in b { assert!(set_b.insert(*y)) }
|
||||
|
||||
let mut i = 0;
|
||||
f(&set_a, &set_b, Counter { i: &mut i, expected: expected });
|
||||
f(&set_a, &set_b, &mut |&x| {
|
||||
assert_eq!(x, expected[i]);
|
||||
i += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
#![feature(collections)]
|
||||
#![feature(collections_bound)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(enumset)]
|
||||
#![feature(pattern)]
|
||||
#![feature(rand)]
|
||||
#![feature(step_by)]
|
||||
#![feature(str_escape)]
|
||||
#![feature(str_replacen)]
|
||||
#![feature(test)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode)]
|
||||
|
|
|
|||
|
|
@ -218,6 +218,20 @@ fn test_is_empty() {
|
|||
assert!(!"a".is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replacen() {
|
||||
assert_eq!("".replacen('a', "b", 5), "");
|
||||
assert_eq!("acaaa".replacen("a", "b", 3), "bcbba");
|
||||
assert_eq!("aaaa".replacen("a", "b", 0), "aaaa");
|
||||
|
||||
let test = "test";
|
||||
assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast ");
|
||||
assert_eq!(" test test ".replacen(test, "toast", 0), " test test ");
|
||||
assert_eq!(" test test ".replacen(test, "", 5), " ");
|
||||
|
||||
assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace() {
|
||||
let a = "a";
|
||||
|
|
|
|||
15
src/libcompiler_builtins/Cargo.toml
Normal file
15
src/libcompiler_builtins/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
name = "compiler_builtins"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "compiler_builtins"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../libcore" }
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3.27"
|
||||
404
src/libcompiler_builtins/build.rs
Normal file
404
src/libcompiler_builtins/build.rs
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
//!
|
||||
//! 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.
|
||||
|
||||
extern crate gcc;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
struct Sources {
|
||||
// SYMBOL -> PATH TO SOURCE
|
||||
map: BTreeMap<&'static str, &'static str>,
|
||||
}
|
||||
|
||||
impl Sources {
|
||||
fn new() -> Sources {
|
||||
Sources { map: BTreeMap::new() }
|
||||
}
|
||||
|
||||
fn extend(&mut self, sources: &[&'static str]) {
|
||||
// NOTE Some intrinsics have both a generic implementation (e.g.
|
||||
// `floatdidf.c`) and an arch optimized implementation
|
||||
// (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized
|
||||
// implementation and discard the generic implementation. If we don't
|
||||
// and keep both implementations, the linker will yell at us about
|
||||
// duplicate symbols!
|
||||
for &src in sources {
|
||||
let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap();
|
||||
if src.contains("/") {
|
||||
// Arch-optimized implementation (preferred)
|
||||
self.map.insert(symbol, src);
|
||||
} else {
|
||||
// Generic implementation
|
||||
if !self.map.contains_key(symbol) {
|
||||
self.map.insert(symbol, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let cfg = &mut gcc::Config::new();
|
||||
|
||||
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 = Sources::new();
|
||||
sources.extend(&["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(&["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(&["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.extend(&["emutls.c"]);
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
|
||||
}
|
||||
} else {
|
||||
if !target.contains("freebsd") {
|
||||
sources.extend(&["gcc_personality_v0.c"]);
|
||||
}
|
||||
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["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(&["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(&["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(&["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(&["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(&["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"]);
|
||||
}
|
||||
|
||||
for src in sources.map.values() {
|
||||
cfg.file(Path::new("../compiler-rt/lib/builtins").join(src));
|
||||
}
|
||||
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
||||
19
src/libcompiler_builtins/lib.rs
Normal file
19
src/libcompiler_builtins/lib.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(not(stage0), feature(compiler_builtins))]
|
||||
#![no_std]
|
||||
#![cfg_attr(not(stage0), compiler_builtins)]
|
||||
#![unstable(feature = "compiler_builtins_lib",
|
||||
reason = "internal implementation detail of rustc right now",
|
||||
issue = "0")]
|
||||
#![crate_name = "compiler_builtins"]
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(staged_api)]
|
||||
|
|
@ -317,6 +317,7 @@ impl<T:Copy> Clone for Cell<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T:Default + Copy> Default for Cell<T> {
|
||||
/// Creates a `Cell<T>`, with the `Default` value for T.
|
||||
#[inline]
|
||||
fn default() -> Cell<T> {
|
||||
Cell::new(Default::default())
|
||||
|
|
@ -758,6 +759,7 @@ impl<T: Clone> Clone for RefCell<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T:Default> Default for RefCell<T> {
|
||||
/// Creates a `RefCell<T>`, with the `Default` value for T.
|
||||
#[inline]
|
||||
fn default() -> RefCell<T> {
|
||||
RefCell::new(Default::default())
|
||||
|
|
@ -1139,6 +1141,7 @@ impl<T: ?Sized> UnsafeCell<T> {
|
|||
|
||||
#[stable(feature = "unsafe_cell_default", since = "1.9.0")]
|
||||
impl<T: Default> Default for UnsafeCell<T> {
|
||||
/// Creates an `UnsafeCell`, with the `Default` value for T.
|
||||
fn default() -> UnsafeCell<T> {
|
||||
UnsafeCell::new(Default::default())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@
|
|||
//! assign them or pass them as arguments, the receiver will get a copy,
|
||||
//! leaving the original value in place. These types do not require
|
||||
//! allocation to copy and do not have finalizers (i.e. they do not
|
||||
//! contain owned boxes or implement `Drop`), so the compiler considers
|
||||
//! contain owned boxes or implement [`Drop`]), so the compiler considers
|
||||
//! them cheap and safe to copy. For other types copies must be made
|
||||
//! explicitly, by convention implementing the `Clone` trait and calling
|
||||
//! the `clone` method.
|
||||
//! explicitly, by convention implementing the [`Clone`] trait and calling
|
||||
//! the [`clone`][clone] method.
|
||||
//!
|
||||
//! [`Clone`]: trait.Clone.html
|
||||
//! [clone]: trait.Clone.html#tymethod.clone
|
||||
//! [`Drop`]: ../../std/ops/trait.Drop.html
|
||||
//!
|
||||
//! Basic usage example:
|
||||
//!
|
||||
|
|
@ -46,22 +50,22 @@
|
|||
|
||||
/// A common trait for the ability to explicitly duplicate an object.
|
||||
///
|
||||
/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while
|
||||
/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while
|
||||
/// `Clone` is always explicit and may or may not be expensive. In order to enforce
|
||||
/// these characteristics, Rust does not allow you to reimplement `Copy`, but you
|
||||
/// these characteristics, Rust does not allow you to reimplement [`Copy`], but you
|
||||
/// may reimplement `Clone` and run arbitrary code.
|
||||
///
|
||||
/// Since `Clone` is more general than `Copy`, you can automatically make anything
|
||||
/// `Copy` be `Clone` as well.
|
||||
/// Since `Clone` is more general than [`Copy`], you can automatically make anything
|
||||
/// [`Copy`] be `Clone` as well.
|
||||
///
|
||||
/// ## Derivable
|
||||
///
|
||||
/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d
|
||||
/// implementation of `clone()` calls `clone()` on each field.
|
||||
/// implementation of [`clone()`] calls [`clone()`] on each field.
|
||||
///
|
||||
/// ## How can I implement `Clone`?
|
||||
///
|
||||
/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally:
|
||||
/// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally:
|
||||
/// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`.
|
||||
/// Manual implementations should be careful to uphold this invariant; however, unsafe code
|
||||
/// must not rely on it to ensure memory safety.
|
||||
|
|
@ -70,6 +74,9 @@
|
|||
/// library only implements `Clone` up until arrays of size 32. In this case, the implementation of
|
||||
/// `Clone` cannot be `derive`d, but can be implemented as:
|
||||
///
|
||||
/// [`Copy`]: ../../std/marker/trait.Copy.html
|
||||
/// [`clone()`]: trait.Clone.html#tymethod.clone
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy)]
|
||||
/// struct Stats {
|
||||
|
|
@ -106,10 +113,23 @@ pub trait Clone : Sized {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(aburka): this method is used solely by #[derive] to
|
||||
// assert that every component of a type implements Clone.
|
||||
// FIXME(aburka): these structs are used solely by #[derive] to
|
||||
// assert that every component of a type implements Clone or Copy.
|
||||
//
|
||||
// This should never be called by user code.
|
||||
// These structs should never appear in user code.
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
|||
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
|
||||
/// no extra methods, it is only informing the compiler that this is an
|
||||
/// equivalence relation rather than a partial equivalence relation. Note that
|
||||
/// the `derive` strategy requires all fields are `PartialEq`, which isn't
|
||||
/// the `derive` strategy requires all fields are `Eq`, which isn't
|
||||
/// always desired.
|
||||
///
|
||||
/// ## How can I implement `Eq`?
|
||||
|
|
@ -165,6 +165,17 @@ pub trait Eq: PartialEq<Self> {
|
|||
fn assert_receiver_is_total_eq(&self) {}
|
||||
}
|
||||
|
||||
// FIXME: this struct is used solely by #[derive] to
|
||||
// assert that every component of a type implements Eq.
|
||||
//
|
||||
// This struct should never appear in user code.
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_eq",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsEq<T: Eq + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
|
||||
/// An `Ordering` is the result of a comparison between two values.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -92,6 +92,22 @@ pub trait AsRef<T: ?Sized> {
|
|||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`Box<T>`] implements `AsMut<T>`:
|
||||
///
|
||||
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
///
|
||||
/// ```
|
||||
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
|
||||
/// *num.as_mut() += 1;
|
||||
/// }
|
||||
///
|
||||
/// let mut boxed_num = Box::new(0);
|
||||
/// add_one(&mut boxed_num);
|
||||
/// assert_eq!(*boxed_num, 1);
|
||||
/// ```
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
|
||||
|
|
|
|||
|
|
@ -272,10 +272,14 @@ impl<'a> Arguments<'a> {
|
|||
/// safely be done so, so no constructors are given and the fields are private
|
||||
/// to prevent modification.
|
||||
///
|
||||
/// The `format_args!` macro will safely create an instance of this structure
|
||||
/// The [`format_args!`] macro will safely create an instance of this structure
|
||||
/// and pass it to a function or closure, passed as the first argument. The
|
||||
/// macro validates the format string at compile-time so usage of the `write`
|
||||
/// and `format` functions can be safely performed.
|
||||
/// macro validates the format string at compile-time so usage of the [`write`]
|
||||
/// and [`format`] functions can be safely performed.
|
||||
///
|
||||
/// [`format_args!`]: ../../std/macro.format_args.html
|
||||
/// [`format`]: ../../std/fmt/fn.format.html
|
||||
/// [`write`]: ../../std/fmt/fn.write.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Arguments<'a> {
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ impl<S: Sip> Clone for Hasher<S> {
|
|||
}
|
||||
|
||||
impl<S: Sip> Default for Hasher<S> {
|
||||
/// Creates a `Hasher<S>` with the two initial keys set to 0.
|
||||
#[inline]
|
||||
fn default() -> Hasher<S> {
|
||||
Hasher::new_with_keys(0, 0)
|
||||
|
|
|
|||
|
|
@ -194,6 +194,20 @@ extern "rust-intrinsic" {
|
|||
/// own, or if it does not enable any significant optimizations.
|
||||
pub fn assume(b: bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
pub fn likely(b: bool) -> bool;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
pub fn unlikely(b: bool) -> bool;
|
||||
|
||||
/// Executes a breakpoint trap, for inspection by a debugger.
|
||||
pub fn breakpoint();
|
||||
|
||||
|
|
@ -262,22 +276,25 @@ extern "rust-intrinsic" {
|
|||
/// Moves a value out of scope without running drop glue.
|
||||
pub fn forget<T>(_: T) -> ();
|
||||
|
||||
/// 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).
|
||||
/// 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).
|
||||
///
|
||||
/// `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`.
|
||||
/// into another. It copies the bits from the source value into the
|
||||
/// destination value, 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
|
||||
/// `transmute` is **incredibly** unsafe. There are a vast number of ways to
|
||||
/// cause [undefined behavior][ub] with this function. `transmute` should be
|
||||
/// the absolute last resort.
|
||||
///
|
||||
/// The [nomicon](../../nomicon/transmutes.html) has additional
|
||||
/// documentation.
|
||||
///
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// There are a few things that `transmute` is really useful for.
|
||||
|
|
@ -292,7 +309,8 @@ extern "rust-intrinsic" {
|
|||
/// assert_eq!(bitpattern, 0x3F800000);
|
||||
/// ```
|
||||
///
|
||||
/// Turning a pointer into a function pointer:
|
||||
/// Turning a pointer into a function pointer. This is *not* portable to
|
||||
/// machines where function pointers and data pointers have different sizes.
|
||||
///
|
||||
/// ```
|
||||
/// fn foo() -> i32 {
|
||||
|
|
@ -305,8 +323,8 @@ extern "rust-intrinsic" {
|
|||
/// assert_eq!(function(), 0);
|
||||
/// ```
|
||||
///
|
||||
/// Extending a lifetime, or shortening an invariant lifetime; this is
|
||||
/// advanced, very unsafe rust:
|
||||
/// Extending a lifetime, or shortening an invariant lifetime. This is
|
||||
/// advanced, very unsafe Rust!
|
||||
///
|
||||
/// ```
|
||||
/// struct R<'a>(&'a i32);
|
||||
|
|
@ -322,11 +340,9 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// # 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`:
|
||||
/// Don't despair: many uses of `transmute` can be achieved through other means.
|
||||
/// Below are common applications of `transmute` which can be replaced with safer
|
||||
/// constructs.
|
||||
///
|
||||
/// Turning a pointer into a `usize`:
|
||||
///
|
||||
|
|
@ -335,6 +351,7 @@ extern "rust-intrinsic" {
|
|||
/// 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;
|
||||
/// ```
|
||||
|
|
@ -346,6 +363,7 @@ extern "rust-intrinsic" {
|
|||
/// let ref_transmuted = unsafe {
|
||||
/// std::mem::transmute::<*mut i32, &mut i32>(ptr)
|
||||
/// };
|
||||
///
|
||||
/// // Use a reborrow instead
|
||||
/// let ref_casted = unsafe { &mut *ptr };
|
||||
/// ```
|
||||
|
|
@ -357,6 +375,7 @@ extern "rust-intrinsic" {
|
|||
/// 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) };
|
||||
|
|
@ -368,9 +387,11 @@ extern "rust-intrinsic" {
|
|||
/// // 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]);
|
||||
|
|
@ -381,18 +402,21 @@ extern "rust-intrinsic" {
|
|||
/// ```
|
||||
/// 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.
|
||||
/// // 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
|
||||
|
|
@ -412,6 +436,7 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// ```
|
||||
/// 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)
|
||||
|
|
@ -426,6 +451,7 @@ extern "rust-intrinsic" {
|
|||
/// (&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)
|
||||
|
|
@ -439,6 +465,7 @@ extern "rust-intrinsic" {
|
|||
/// (&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)
|
||||
|
|
|
|||
|
|
@ -1657,6 +1657,32 @@ pub trait Iterator {
|
|||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the maximum value with respect to the
|
||||
/// specified comparison function.
|
||||
///
|
||||
/// Returns the rightmost element if the comparison determines two elements
|
||||
/// to be equally maximum.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_max_by)]
|
||||
/// let a = [-3_i32, 0, 1, 5, -10];
|
||||
/// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_max_by", issue="36105")]
|
||||
fn max_by<F>(self, mut compare: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
|
||||
{
|
||||
select_fold1(self,
|
||||
|_| (),
|
||||
// switch to y even if it is only equal, to preserve
|
||||
// stability.
|
||||
|_, x, _, y| Ordering::Greater != compare(x, y))
|
||||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the minimum value from the
|
||||
/// specified function.
|
||||
///
|
||||
|
|
@ -1681,6 +1707,33 @@ pub trait Iterator {
|
|||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the minimum value with respect to the
|
||||
/// specified comparison function.
|
||||
///
|
||||
/// Returns the latest element if the comparison determines two elements
|
||||
/// to be equally minimum.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_min_by)]
|
||||
/// let a = [-3_i32, 0, 1, 5, -10];
|
||||
/// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_min_by", issue="36105")]
|
||||
fn min_by<F>(self, mut compare: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
|
||||
{
|
||||
select_fold1(self,
|
||||
|_| (),
|
||||
// switch to y even if it is strictly smaller, to
|
||||
// preserve stability.
|
||||
|_, x, _, y| Ordering::Greater == compare(x, y))
|
||||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
|
||||
/// Reverses an iterator's direction.
|
||||
///
|
||||
/// Usually, iterators iterate from left to right. After using `rev()`,
|
||||
|
|
@ -1814,7 +1867,8 @@ pub trait Iterator {
|
|||
/// # Panics
|
||||
///
|
||||
/// When calling `sum` and a primitive integer type is being returned, this
|
||||
/// method will panic if the computation overflows.
|
||||
/// method will panic if the computation overflows and debug assertions are
|
||||
/// enabled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1841,7 +1895,8 @@ pub trait Iterator {
|
|||
/// # Panics
|
||||
///
|
||||
/// When calling `product` and a primitive integer type is being returned,
|
||||
/// this method will panic if the computation overflows.
|
||||
/// method will panic if the computation overflows and debug assertions are
|
||||
/// enabled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -643,7 +643,9 @@ impl<A, B> FusedIterator for Chain<A, B>
|
|||
pub struct Zip<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
spec: <(A, B) as ZipImplData>::Data,
|
||||
// index and len are only used by the specialized version of zip
|
||||
index: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -685,17 +687,6 @@ trait ZipImpl<A, B> {
|
|||
B: DoubleEndedIterator + ExactSizeIterator;
|
||||
}
|
||||
|
||||
// Zip specialization data members
|
||||
#[doc(hidden)]
|
||||
trait ZipImplData {
|
||||
type Data: 'static + Clone + Default + fmt::Debug;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> ZipImplData for T {
|
||||
default type Data = ();
|
||||
}
|
||||
|
||||
// General Zip impl
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
|
|
@ -706,7 +697,8 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
Zip {
|
||||
a: a,
|
||||
b: b,
|
||||
spec: Default::default(), // unused
|
||||
index: 0, // unused
|
||||
len: 0, // unused
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -759,20 +751,6 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct ZipImplFields {
|
||||
index: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImplData for (A, B)
|
||||
where A: TrustedRandomAccess, B: TrustedRandomAccess
|
||||
{
|
||||
type Data = ZipImplFields;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
where A: TrustedRandomAccess, B: TrustedRandomAccess
|
||||
|
|
@ -782,18 +760,16 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
Zip {
|
||||
a: a,
|
||||
b: b,
|
||||
spec: ZipImplFields {
|
||||
index: 0,
|
||||
len: len,
|
||||
}
|
||||
index: 0,
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(A::Item, B::Item)> {
|
||||
if self.spec.index < self.spec.len {
|
||||
let i = self.spec.index;
|
||||
self.spec.index += 1;
|
||||
if self.index < self.len {
|
||||
let i = self.index;
|
||||
self.index += 1;
|
||||
unsafe {
|
||||
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
|
||||
}
|
||||
|
|
@ -804,7 +780,7 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.spec.len - self.spec.index;
|
||||
let len = self.len - self.index;
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
|
|
@ -813,9 +789,9 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
where A: DoubleEndedIterator + ExactSizeIterator,
|
||||
B: DoubleEndedIterator + ExactSizeIterator
|
||||
{
|
||||
if self.spec.index < self.spec.len {
|
||||
self.spec.len -= 1;
|
||||
let i = self.spec.len;
|
||||
if self.index < self.len {
|
||||
self.len -= 1;
|
||||
let i = self.len;
|
||||
unsafe {
|
||||
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use ops::{Mul, Add};
|
||||
|
||||
/// Conversion from an `Iterator`.
|
||||
///
|
||||
|
|
@ -581,41 +582,34 @@ pub trait Product<A = Self>: Sized {
|
|||
fn product<I: Iterator<Item=A>>(iter: I) -> Self;
|
||||
}
|
||||
|
||||
// NB: explicitly use Add and Mul here to inherit overflow checks
|
||||
macro_rules! integer_sum_product {
|
||||
($($a:ident)*) => ($(
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl Sum for $a {
|
||||
fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
|
||||
iter.fold(0, |a, b| {
|
||||
a.checked_add(b).expect("overflow in sum")
|
||||
})
|
||||
iter.fold(0, Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl Product for $a {
|
||||
fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
|
||||
iter.fold(1, |a, b| {
|
||||
a.checked_mul(b).expect("overflow in product")
|
||||
})
|
||||
iter.fold(1, Mul::mul)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl<'a> Sum<&'a $a> for $a {
|
||||
fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
|
||||
iter.fold(0, |a, b| {
|
||||
a.checked_add(*b).expect("overflow in sum")
|
||||
})
|
||||
iter.cloned().fold(0, Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl<'a> Product<&'a $a> for $a {
|
||||
fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
|
||||
iter.fold(1, |a, b| {
|
||||
a.checked_mul(*b).expect("overflow in product")
|
||||
})
|
||||
iter.cloned().fold(1, Mul::mul)
|
||||
}
|
||||
}
|
||||
)*)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,44 @@ macro_rules! assert_eq {
|
|||
});
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let a = 3;
|
||||
/// let b = 2;
|
||||
/// assert_ne!(a, b);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.12.0")]
|
||||
macro_rules! assert_ne {
|
||||
($left:expr , $right:expr) => ({
|
||||
match (&$left, &$right) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
panic!("assertion failed: `(left != right)` \
|
||||
(left: `{:?}`, right: `{:?}`)", left_val, right_val)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
($left:expr , $right:expr, $($arg:tt)*) => ({
|
||||
match (&($left), &($right)) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
panic!("assertion failed: `(left != right)` \
|
||||
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val,
|
||||
format_args!($($arg)*))
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Ensure that a boolean expression is `true` at runtime.
|
||||
///
|
||||
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||
|
|
@ -189,10 +227,44 @@ macro_rules! debug_assert_eq {
|
|||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Helper macro for unwrapping `Result` values while returning early with an
|
||||
/// error if the value of the expression is `Err`. Can only be used in
|
||||
/// functions that return `Result` because of the early return of `Err` that
|
||||
/// it provides.
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
///
|
||||
/// Unlike `assert_ne!`, `debug_assert_ne!` statements are only enabled in non
|
||||
/// optimized builds by default. An optimized build will omit all
|
||||
/// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the
|
||||
/// compiler. This makes `debug_assert_ne!` useful for checks that are too
|
||||
/// expensive to be present in a release build but may be helpful during
|
||||
/// development.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let a = 3;
|
||||
/// let b = 2;
|
||||
/// debug_assert_ne!(a, b);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.12.0")]
|
||||
macro_rules! debug_assert_ne {
|
||||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Helper macro for reducing boilerplate code for matching `Result` together
|
||||
/// with converting downstream errors.
|
||||
///
|
||||
/// `try!` matches the given `Result`. In case of the `Ok` variant, the
|
||||
/// expression has the value of the wrapped value.
|
||||
///
|
||||
/// In case of the `Err` variant, it retrieves the inner error. `try!` then
|
||||
/// performs conversion using `From`. This provides automatic conversion
|
||||
/// between specialized errors and more general ones. The resulting
|
||||
/// error is then immediately returned.
|
||||
///
|
||||
/// Because of the early return, `try!` can only be used in functions that
|
||||
/// return `Result`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -201,18 +273,28 @@ macro_rules! debug_assert_eq {
|
|||
/// use std::fs::File;
|
||||
/// use std::io::prelude::*;
|
||||
///
|
||||
/// fn write_to_file_using_try() -> Result<(), io::Error> {
|
||||
/// enum MyError {
|
||||
/// FileWriteError
|
||||
/// }
|
||||
///
|
||||
/// impl From<io::Error> for MyError {
|
||||
/// fn from(e: io::Error) -> MyError {
|
||||
/// MyError::FileWriteError
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn write_to_file_using_try() -> Result<(), MyError> {
|
||||
/// let mut file = try!(File::create("my_best_friends.txt"));
|
||||
/// try!(file.write_all(b"This is a list of my best friends."));
|
||||
/// println!("I wrote to the file");
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// // This is equivalent to:
|
||||
/// fn write_to_file_using_match() -> Result<(), io::Error> {
|
||||
/// fn write_to_file_using_match() -> Result<(), MyError> {
|
||||
/// let mut file = try!(File::create("my_best_friends.txt"));
|
||||
/// match file.write_all(b"This is a list of my best friends.") {
|
||||
/// Ok(v) => v,
|
||||
/// Err(e) => return Err(e),
|
||||
/// Err(e) => return Err(From::from(e)),
|
||||
/// }
|
||||
/// println!("I wrote to the file");
|
||||
/// Ok(())
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Primitive traits and marker types representing basic 'kinds' of types.
|
||||
//! Primitive traits and types representing basic properties of types.
|
||||
//!
|
||||
//! Rust types can be classified in various useful ways according to
|
||||
//! intrinsic properties of the type. These classifications, often called
|
||||
//! 'kinds', are represented as traits.
|
||||
//! their intrinsic properties. These classifications are represented
|
||||
//! as traits.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -22,7 +22,21 @@ use hash::Hasher;
|
|||
|
||||
/// Types that can be transferred across thread boundaries.
|
||||
///
|
||||
/// This trait is automatically derived when the compiler determines it's appropriate.
|
||||
/// This trait is automatically implemented when the compiler determines it's
|
||||
/// appropriate.
|
||||
///
|
||||
/// An example of a non-`Send` type is the reference-counting pointer
|
||||
/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same
|
||||
/// reference-counted value, they might try to update the reference count at the
|
||||
/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic
|
||||
/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring
|
||||
/// some overhead) and thus is `Send`.
|
||||
///
|
||||
/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details.
|
||||
///
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "send"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||
|
|
@ -38,10 +52,10 @@ impl<T: ?Sized> !Send for *const T { }
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> !Send for *mut T { }
|
||||
|
||||
/// Types with a constant size known at compile-time.
|
||||
/// Types with a constant size known at compile time.
|
||||
///
|
||||
/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax
|
||||
/// `?Sized` can be used to remove this bound if it is not appropriate.
|
||||
/// All type parameters have an implicit bound of `Sized`. The special syntax
|
||||
/// `?Sized` can be used to remove this bound if it's not appropriate.
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
@ -51,6 +65,26 @@ impl<T: ?Sized> !Send for *mut T { }
|
|||
/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
|
||||
/// struct BarUse(Bar<[i32]>); // OK
|
||||
/// ```
|
||||
///
|
||||
/// The one exception is the implicit `Self` type of a trait, which does not
|
||||
/// get an implicit `Sized` bound. This is because a `Sized` bound prevents
|
||||
/// the trait from being used to form a [trait object]:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(unused_variables)]
|
||||
/// trait Foo { }
|
||||
/// trait Bar: Sized { }
|
||||
///
|
||||
/// struct Impl;
|
||||
/// impl Foo for Impl { }
|
||||
/// impl Bar for Impl { }
|
||||
///
|
||||
/// let x: &Foo = &Impl; // OK
|
||||
/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot
|
||||
/// // be made into an object
|
||||
/// ```
|
||||
///
|
||||
/// [trait object]: ../../book/trait-objects.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sized"]
|
||||
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
|
||||
|
|
@ -59,14 +93,27 @@ pub trait Sized {
|
|||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be "unsized" to a dynamically sized type.
|
||||
/// Types that can be "unsized" to a dynamically-sized type.
|
||||
///
|
||||
/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
|
||||
/// `Unsize<fmt::Debug>`.
|
||||
///
|
||||
/// All implementations of `Unsize` are provided automatically by the compiler.
|
||||
///
|
||||
/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow
|
||||
/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized
|
||||
/// types. See the [DST coercion RFC][RFC982] for more details.
|
||||
///
|
||||
/// [coerceunsized]: ../ops/trait.CoerceUnsized.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
#[unstable(feature = "unsize", issue = "27732")]
|
||||
#[lang="unsize"]
|
||||
pub trait Unsize<T: ?Sized> {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
||||
/// Types whose values can be duplicated simply by copying bits.
|
||||
///
|
||||
/// By default, variable bindings have 'move semantics.' In other
|
||||
/// words:
|
||||
|
|
@ -87,7 +134,8 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// However, if a type implements `Copy`, it instead has 'copy semantics':
|
||||
///
|
||||
/// ```
|
||||
/// // we can just derive a `Copy` implementation
|
||||
/// // We can derive a `Copy` implementation. `Clone` is also required, as it's
|
||||
/// // a supertrait of `Copy`.
|
||||
/// #[derive(Debug, Copy, Clone)]
|
||||
/// struct Foo;
|
||||
///
|
||||
|
|
@ -100,13 +148,59 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// println!("{:?}", x); // A-OK!
|
||||
/// ```
|
||||
///
|
||||
/// It's important to note that in these two examples, the only difference is if you are allowed to
|
||||
/// access `x` after the assignment: a move is also a bitwise copy under the hood.
|
||||
/// It's important to note that in these two examples, the only difference is whether you
|
||||
/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move
|
||||
/// can result in bits being copied in memory, although this is sometimes optimized away.
|
||||
///
|
||||
/// ## How can I implement `Copy`?
|
||||
///
|
||||
/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct MyStruct;
|
||||
/// ```
|
||||
///
|
||||
/// You can also implement `Copy` and `Clone` manually:
|
||||
///
|
||||
/// ```
|
||||
/// struct MyStruct;
|
||||
///
|
||||
/// impl Copy for MyStruct { }
|
||||
///
|
||||
/// impl Clone for MyStruct {
|
||||
/// fn clone(&self) -> MyStruct {
|
||||
/// *self
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||
/// bound on type parameters, which isn't always desired.
|
||||
///
|
||||
/// ## What's the difference between `Copy` and `Clone`?
|
||||
///
|
||||
/// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of
|
||||
/// `Copy` is not overloadable; it is always a simple bit-wise copy.
|
||||
///
|
||||
/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can
|
||||
/// provide any type-specific behavior necessary to duplicate values safely. For example,
|
||||
/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string
|
||||
/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the
|
||||
/// pointer, leading to a double free down the line. For this reason, `String` is `Clone`
|
||||
/// but not `Copy`.
|
||||
///
|
||||
/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement
|
||||
/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self`
|
||||
/// (see the example above).
|
||||
///
|
||||
/// [clone]: ../clone/trait.Clone.html
|
||||
/// [string]: ../../std/string/struct.String.html
|
||||
///
|
||||
/// ## When can my type be `Copy`?
|
||||
///
|
||||
/// A type can implement `Copy` if all of its components implement `Copy`. For example, this
|
||||
/// `struct` can be `Copy`:
|
||||
/// struct can be `Copy`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[allow(dead_code)]
|
||||
|
|
@ -116,7 +210,8 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`.
|
||||
/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`.
|
||||
/// By contrast, consider
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
@ -126,107 +221,114 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `PointList` `struct` cannot implement `Copy`, because `Vec<T>` is not `Copy`. If we
|
||||
/// The struct `PointList` cannot implement `Copy`, because [`Vec<T>`] is not `Copy`. If we
|
||||
/// attempt to derive a `Copy` implementation, we'll get an error:
|
||||
///
|
||||
/// ```text
|
||||
/// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
|
||||
/// ```
|
||||
///
|
||||
/// ## When can my type _not_ be `Copy`?
|
||||
/// ## When *can't* my type be `Copy`?
|
||||
///
|
||||
/// Some types can't be copied safely. For example, copying `&mut T` would create an aliased
|
||||
/// mutable reference, and copying `String` would result in two attempts to free the same buffer.
|
||||
/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s
|
||||
/// buffer, leading to a double free.
|
||||
///
|
||||
/// 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.
|
||||
/// 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 implement `Copy` on a struct or enum containing non-`Copy` data, you will get a
|
||||
/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get
|
||||
/// [E0205].
|
||||
///
|
||||
/// 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).
|
||||
/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204
|
||||
/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205
|
||||
///
|
||||
/// ## When should my type be `Copy`?
|
||||
/// ## When *should* my type be `Copy`?
|
||||
///
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing
|
||||
/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future,
|
||||
/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking
|
||||
/// change: that second example would fail to compile if we made `Foo` non-`Copy`.
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. Keep in mind, though,
|
||||
/// that implementing `Copy` is part of the public API of your type. If the type might become
|
||||
/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to
|
||||
/// avoid a breaking API change.
|
||||
///
|
||||
/// ## Derivable
|
||||
///
|
||||
/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type
|
||||
/// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`.
|
||||
///
|
||||
/// ## How can I implement `Copy`?
|
||||
///
|
||||
/// There are two ways to implement `Copy` on your type:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct MyStruct;
|
||||
/// ```
|
||||
///
|
||||
/// and
|
||||
///
|
||||
/// ```
|
||||
/// struct MyStruct;
|
||||
/// impl Copy for MyStruct {}
|
||||
/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } }
|
||||
/// ```
|
||||
///
|
||||
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||
/// bound on type parameters, which isn't always desired.
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`Drop`]: ../../std/ops/trait.Drop.html
|
||||
/// [`size_of::<T>()`]: ../../std/mem/fn.size_of.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "copy"]
|
||||
pub trait Copy : Clone {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be safely shared between threads when aliased.
|
||||
/// Types for which it is safe to share references between threads.
|
||||
///
|
||||
/// This trait is automatically implemented when the compiler determines
|
||||
/// it's appropriate.
|
||||
///
|
||||
/// The precise definition is: a type `T` is `Sync` if `&T` is
|
||||
/// thread-safe. In other words, there is no possibility of data races
|
||||
/// when passing `&T` references between threads.
|
||||
/// [`Send`][send]. In other words, if there is no possibility of
|
||||
/// [undefined behavior][ub] (including data races) when passing
|
||||
/// `&T` references between threads.
|
||||
///
|
||||
/// As one would expect, primitive types like `u8` and `f64` are all
|
||||
/// `Sync`, and so are simple aggregate types containing them (like
|
||||
/// tuples, structs and enums). More instances of basic `Sync` types
|
||||
/// include "immutable" types like `&T` and those with simple
|
||||
/// inherited mutability, such as `Box<T>`, `Vec<T>` and most other
|
||||
/// collection types. (Generic parameters need to be `Sync` for their
|
||||
/// container to be `Sync`.)
|
||||
/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64]
|
||||
/// are all `Sync`, and so are simple aggregate types containing them,
|
||||
/// like tuples, structs and enums. More examples of basic `Sync`
|
||||
/// types include "immutable" types like `&T`, and those with simple
|
||||
/// inherited mutability, such as [`Box<T>`][box], [`Vec<T>`][vec] and
|
||||
/// most other collection types. (Generic parameters need to be `Sync`
|
||||
/// for their container to be `Sync`.)
|
||||
///
|
||||
/// A somewhat surprising consequence of the definition is `&mut T` is
|
||||
/// `Sync` (if `T` is `Sync`) even though it seems that it might
|
||||
/// provide unsynchronized mutation. The trick is a mutable reference
|
||||
/// stored in an aliasable reference (that is, `& &mut T`) becomes
|
||||
/// read-only, as if it were a `& &T`, hence there is no risk of a data
|
||||
/// race.
|
||||
/// A somewhat surprising consequence of the definition is that `&mut T`
|
||||
/// is `Sync` (if `T` is `Sync`) even though it seems like that might
|
||||
/// provide unsynchronized mutation. The trick is that a mutable
|
||||
/// reference behind a shared reference (that is, `& &mut T`)
|
||||
/// becomes read-only, as if it were a `& &T`. Hence there is no risk
|
||||
/// of a data race.
|
||||
///
|
||||
/// Types that are not `Sync` are those that have "interior
|
||||
/// mutability" in a non-thread-safe way, such as `Cell` and `RefCell`
|
||||
/// in `std::cell`. These types allow for mutation of their contents
|
||||
/// even when in an immutable, aliasable slot, e.g. the contents of
|
||||
/// `&Cell<T>` can be `.set`, and do not ensure data races are
|
||||
/// impossible, hence they cannot be `Sync`. A higher level example
|
||||
/// of a non-`Sync` type is the reference counted pointer
|
||||
/// `std::rc::Rc`, because any reference `&Rc<T>` can clone a new
|
||||
/// reference, which modifies the reference counts in a non-atomic
|
||||
/// way.
|
||||
/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell]
|
||||
/// and [`cell::RefCell`][refcell]. These types allow for mutation of
|
||||
/// their contents even through an immutable, shared reference. For
|
||||
/// example the `set` method on `Cell<T>` takes `&self`, so it requires
|
||||
/// only a shared reference `&Cell<T>`. The method performs no
|
||||
/// synchronization, thus `Cell` cannot be `Sync`.
|
||||
///
|
||||
/// Another example of a non-`Sync` type is the reference-counting
|
||||
/// pointer [`rc::Rc`][rc]. Given any reference `&Rc<T>`, you can clone
|
||||
/// a new `Rc<T>`, modifying the reference counts in a non-atomic way.
|
||||
///
|
||||
/// For cases when one does need thread-safe interior mutability,
|
||||
/// types like the atomics in `std::sync` and `Mutex` & `RWLock` in
|
||||
/// the `sync` crate do ensure that any mutation cannot cause data
|
||||
/// races. Hence these types are `Sync`.
|
||||
/// Rust provides [atomic data types], as well as explicit locking via
|
||||
/// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types
|
||||
/// ensure that any mutation cannot cause data races, hence the types
|
||||
/// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe
|
||||
/// analogue of `Rc`.
|
||||
///
|
||||
/// Any types with interior mutability must also use the `std::cell::UnsafeCell`
|
||||
/// wrapper around the value(s) which can be mutated when behind a `&`
|
||||
/// reference; not doing this is undefined behavior (for example,
|
||||
/// `transmute`-ing from `&T` to `&mut T` is invalid).
|
||||
/// Any types with interior mutability must also use the
|
||||
/// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which
|
||||
/// can be mutated through a shared reference. Failing to doing this is
|
||||
/// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing
|
||||
/// from `&T` to `&mut T` is invalid.
|
||||
///
|
||||
/// This trait is automatically derived when the compiler determines it's appropriate.
|
||||
/// See [the Nomicon](../../nomicon/send-and-sync.html) for more
|
||||
/// details about `Sync`.
|
||||
///
|
||||
/// [send]: trait.Send.html
|
||||
/// [u8]: ../../std/primitive.u8.html
|
||||
/// [f64]: ../../std/primitive.f64.html
|
||||
/// [box]: ../../std/boxed/struct.Box.html
|
||||
/// [vec]: ../../std/vec/struct.Vec.html
|
||||
/// [cell]: ../cell/struct.Cell.html
|
||||
/// [refcell]: ../cell/struct.RefCell.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [atomic data types]: ../sync/atomic/index.html
|
||||
/// [mutex]: ../../std/sync/struct.Mutex.html
|
||||
/// [rwlock]: ../../std/sync/struct.RwLock.html
|
||||
/// [unsafecell]: ../cell/struct.UnsafeCell.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [transmute]: ../../std/mem/fn.transmute.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sync"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
|
||||
|
|
@ -295,29 +397,30 @@ macro_rules! impls{
|
|||
)
|
||||
}
|
||||
|
||||
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
|
||||
/// even though it does not. This allows you to inform the compiler about certain safety properties
|
||||
/// of your code.
|
||||
/// Zero-sized type used to mark things that "act like" they own a `T`.
|
||||
///
|
||||
/// For a more in-depth explanation of how to use `PhantomData<T>`, please see [the Nomicon].
|
||||
/// Adding a `PhantomData<T>` field to your type tells the compiler that your
|
||||
/// type acts as though it stores a value of type `T`, even though it doesn't
|
||||
/// really. This information is used when computing certain safety properties.
|
||||
///
|
||||
/// [the Nomicon]: ../../nomicon/phantom-data.html
|
||||
/// For a more in-depth explanation of how to use `PhantomData<T>`, please see
|
||||
/// [the Nomicon](../../nomicon/phantom-data.html).
|
||||
///
|
||||
/// # A ghastly note 👻👻👻
|
||||
///
|
||||
/// Though they both have scary names, `PhantomData<T>` and 'phantom types' are related, but not
|
||||
/// identical. Phantom types are a more general concept that don't require `PhantomData<T>` to
|
||||
/// implement, but `PhantomData<T>` is the most common way to implement them in a correct manner.
|
||||
/// Though they both have scary names, `PhantomData` and 'phantom types' are
|
||||
/// related, but not identical. A phantom type parameter is simply a type
|
||||
/// parameter which is never used. In Rust, this often causes the compiler to
|
||||
/// complain, and the solution is to add a "dummy" use by way of `PhantomData`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ## Unused lifetime parameter
|
||||
/// ## Unused lifetime parameters
|
||||
///
|
||||
/// Perhaps the most common time that `PhantomData` is required is
|
||||
/// with a struct that has an unused lifetime parameter, typically as
|
||||
/// part of some unsafe code. For example, here is a struct `Slice`
|
||||
/// that has two pointers of type `*const T`, presumably pointing into
|
||||
/// an array somewhere:
|
||||
/// Perhaps the most common use case for `PhantomData` is a struct that has an
|
||||
/// unused lifetime parameter, typically as part of some unsafe code. For
|
||||
/// example, here is a struct `Slice` that has two pointers of type `*const T`,
|
||||
/// presumably pointing into an array somewhere:
|
||||
///
|
||||
/// ```ignore
|
||||
/// struct Slice<'a, T> {
|
||||
|
|
@ -331,7 +434,7 @@ macro_rules! impls{
|
|||
/// intent is not expressed in the code, since there are no uses of
|
||||
/// the lifetime `'a` and hence it is not clear what data it applies
|
||||
/// to. We can correct this by telling the compiler to act *as if* the
|
||||
/// `Slice` struct contained a borrowed reference `&'a T`:
|
||||
/// `Slice` struct contained a reference `&'a T`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::marker::PhantomData;
|
||||
|
|
@ -340,29 +443,53 @@ macro_rules! impls{
|
|||
/// struct Slice<'a, T: 'a> {
|
||||
/// start: *const T,
|
||||
/// end: *const T,
|
||||
/// phantom: PhantomData<&'a T>
|
||||
/// phantom: PhantomData<&'a T>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This also in turn requires that we annotate `T:'a`, indicating
|
||||
/// that `T` is a type that can be borrowed for the lifetime `'a`.
|
||||
/// This also in turn requires the annotation `T: 'a`, indicating
|
||||
/// that any references in `T` are valid over the lifetime `'a`.
|
||||
///
|
||||
/// ## Unused type parameters
|
||||
///
|
||||
/// It sometimes happens that there are unused type parameters that
|
||||
/// indicate what type of data a struct is "tied" to, even though that
|
||||
/// data is not actually found in the struct itself. Here is an
|
||||
/// example where this arises when handling external resources over a
|
||||
/// foreign function interface. `PhantomData<T>` can prevent
|
||||
/// mismatches by enforcing types in the method implementations:
|
||||
/// When initializing a `Slice` you simply provide the value
|
||||
/// `PhantomData` for the field `phantom`:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// # trait ResType { fn foo(&self); }
|
||||
/// # use std::marker::PhantomData;
|
||||
/// # struct Slice<'a, T: 'a> {
|
||||
/// # start: *const T,
|
||||
/// # end: *const T,
|
||||
/// # phantom: PhantomData<&'a T>,
|
||||
/// # }
|
||||
/// fn borrow_vec<'a, T>(vec: &'a Vec<T>) -> Slice<'a, T> {
|
||||
/// let ptr = vec.as_ptr();
|
||||
/// Slice {
|
||||
/// start: ptr,
|
||||
/// end: unsafe { ptr.offset(vec.len() as isize) },
|
||||
/// phantom: PhantomData,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Unused type parameters
|
||||
///
|
||||
/// It sometimes happens that you have unused type parameters which
|
||||
/// indicate what type of data a struct is "tied" to, even though that
|
||||
/// data is not actually found in the struct itself. Here is an
|
||||
/// example where this arises with [FFI]. The foreign interface uses
|
||||
/// handles of type `*mut ()` to refer to Rust values of different
|
||||
/// types. We track the Rust type using a phantom type parameter on
|
||||
/// the struct `ExternalResource` which wraps a handle.
|
||||
///
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// # trait ResType { }
|
||||
/// # struct ParamType;
|
||||
/// # mod foreign_lib {
|
||||
/// # pub fn new(_: usize) -> *mut () { 42 as *mut () }
|
||||
/// # pub fn do_stuff(_: *mut (), _: usize) {}
|
||||
/// # pub fn new(_: usize) -> *mut () { 42 as *mut () }
|
||||
/// # pub fn do_stuff(_: *mut (), _: usize) {}
|
||||
/// # }
|
||||
/// # fn convert_params(_: ParamType) -> usize { 42 }
|
||||
/// use std::marker::PhantomData;
|
||||
|
|
@ -389,21 +516,20 @@ macro_rules! impls{
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Indicating ownership
|
||||
/// ## Ownership and the drop check
|
||||
///
|
||||
/// Adding a field of type `PhantomData<T>` also indicates that your
|
||||
/// struct owns data of type `T`. This in turn implies that when your
|
||||
/// struct is dropped, it may in turn drop one or more instances of
|
||||
/// the type `T`, though that may not be apparent from the other
|
||||
/// structure of the type itself. This is commonly necessary if the
|
||||
/// structure is using a raw pointer like `*mut T` whose referent
|
||||
/// may be dropped when the type is dropped, as a `*mut T` is
|
||||
/// otherwise not treated as owned.
|
||||
/// Adding a field of type `PhantomData<T>` indicates that your
|
||||
/// type owns data of type `T`. This in turn implies that when your
|
||||
/// type is dropped, it may drop one or more instances of the type
|
||||
/// `T`. This has bearing on the Rust compiler's [drop check]
|
||||
/// analysis.
|
||||
///
|
||||
/// If your struct does not in fact *own* the data of type `T`, it is
|
||||
/// better to use a reference type, like `PhantomData<&'a T>`
|
||||
/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
|
||||
/// as not to indicate ownership.
|
||||
///
|
||||
/// [drop check]: ../../nomicon/dropck.html
|
||||
#[lang = "phantom_data"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct PhantomData<T:?Sized>;
|
||||
|
|
@ -419,10 +545,13 @@ mod impls {
|
|||
|
||||
/// Types that can be reflected over.
|
||||
///
|
||||
/// This trait is implemented for all types. Its purpose is to ensure
|
||||
/// that when you write a generic function that will employ
|
||||
/// reflection, that must be reflected (no pun intended) in the
|
||||
/// generic bounds of that function. Here is an example:
|
||||
/// By "reflection" we mean use of the [`Any`][any] trait, or related
|
||||
/// machinery such as [`TypeId`][typeid].
|
||||
///
|
||||
/// `Reflect` is implemented for all types. Its purpose is to ensure
|
||||
/// that when you write a generic function that will employ reflection,
|
||||
/// that must be reflected (no pun intended) in the generic bounds of
|
||||
/// that function.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(reflect_marker)]
|
||||
|
|
@ -436,21 +565,24 @@ mod impls {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Without the declaration `T: Reflect`, `foo` would not type check
|
||||
/// (note: as a matter of style, it would be preferable to write
|
||||
/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but
|
||||
/// we use `Reflect` here to show how it works). The `Reflect` bound
|
||||
/// thus serves to alert `foo`'s caller to the fact that `foo` may
|
||||
/// behave differently depending on whether `T = u32` or not. In
|
||||
/// particular, thanks to the `Reflect` bound, callers know that a
|
||||
/// function declared like `fn bar<T>(...)` will always act in
|
||||
/// precisely the same way no matter what type `T` is supplied,
|
||||
/// because there are no bounds declared on `T`. (The ability for a
|
||||
/// caller to reason about what a function may do based solely on what
|
||||
/// generic bounds are declared is often called the ["parametricity
|
||||
/// property"][1].)
|
||||
/// Without the bound `T: Reflect`, `foo` would not typecheck. (As
|
||||
/// a matter of style, it would be preferable to write `T: Any`,
|
||||
/// because `T: Any` implies `T: Reflect` and `T: 'static`, but we
|
||||
/// use `Reflect` here for illustrative purposes.)
|
||||
///
|
||||
/// [1]: http://en.wikipedia.org/wiki/Parametricity
|
||||
/// The `Reflect` bound serves to alert `foo`'s caller to the
|
||||
/// fact that `foo` may behave differently depending on whether
|
||||
/// `T` is `u32` or not. The ability for a caller to reason about what
|
||||
/// a function may do based solely on what generic bounds are declared
|
||||
/// is often called the "[parametricity property][param]". Despite the
|
||||
/// use of `Reflect`, Rust lacks true parametricity because a generic
|
||||
/// function can, at the very least, call [`mem::size_of`][size_of]
|
||||
/// without employing any trait bounds whatsoever.
|
||||
///
|
||||
/// [any]: ../any/trait.Any.html
|
||||
/// [typeid]: ../any/struct.TypeId.html
|
||||
/// [param]: http://en.wikipedia.org/wiki/Parametricity
|
||||
/// [size_of]: ../mem/fn.size_of.html
|
||||
#[rustc_reflect_like]
|
||||
#[unstable(feature = "reflect_marker",
|
||||
reason = "requires RFC and more experience",
|
||||
|
|
|
|||
|
|
@ -21,54 +21,39 @@ use ptr;
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use intrinsics::transmute;
|
||||
|
||||
/// Leaks a value into the void, consuming ownership and never running its
|
||||
/// destructor.
|
||||
/// Leaks a value: takes ownership and "forgets" about the value **without running
|
||||
/// its destructor**.
|
||||
///
|
||||
/// This function will take ownership of its argument, but is distinct from the
|
||||
/// `mem::drop` function in that it **does not run the destructor**, leaking the
|
||||
/// value and any resources that it owns.
|
||||
/// Any resources the value manages, such as heap memory or a file handle, will linger
|
||||
/// forever in an unreachable state.
|
||||
///
|
||||
/// There's only a few reasons to use this function. They mainly come
|
||||
/// up in unsafe code or FFI code.
|
||||
///
|
||||
/// * You have an uninitialized value, perhaps for performance reasons, and
|
||||
/// need to prevent the destructor from running on it.
|
||||
/// * You have two copies of a value (like when writing something like
|
||||
/// [`mem::swap`][swap]), but need the destructor to only run once to
|
||||
/// prevent a double `free`.
|
||||
/// * Transferring resources across [FFI][ffi] boundaries.
|
||||
///
|
||||
/// [swap]: fn.swap.html
|
||||
/// [ffi]: ../../book/ffi.html
|
||||
/// If you want to dispose of a value properly, running its destructor, see
|
||||
/// [`mem::drop`][drop].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is not marked as `unsafe` as Rust does not guarantee that the
|
||||
/// `Drop` implementation for a value will always run. Note, however, that
|
||||
/// leaking resources such as memory or I/O objects is likely not desired, so
|
||||
/// this function is only recommended for specialized use cases.
|
||||
/// `forget` is not marked as `unsafe`, because Rust's safety guarantees
|
||||
/// do not include a guarantee that destructors will always run. For example,
|
||||
/// a program can create a reference cycle using [`Rc`][rc], or call
|
||||
/// [`process:exit`][exit] to exit without running destructors. Thus, allowing
|
||||
/// `mem::forget` from safe code does not fundamentally change Rust's safety
|
||||
/// guarantees.
|
||||
///
|
||||
/// The safety of this function implies that when writing `unsafe` code
|
||||
/// yourself care must be taken when leveraging a destructor that is required to
|
||||
/// run to preserve memory safety. There are known situations where the
|
||||
/// destructor may not run (such as if ownership of the object with the
|
||||
/// destructor is returned) which must be taken into account.
|
||||
/// That said, leaking resources such as memory or I/O objects is usually undesirable,
|
||||
/// so `forget` is only recommended for specialized use cases like those shown below.
|
||||
///
|
||||
/// # Other forms of Leakage
|
||||
/// Because forgetting a value is allowed, any `unsafe` code you write must
|
||||
/// allow for this possibility. You cannot return a value and expect that the
|
||||
/// caller will necessarily run the value's destructor.
|
||||
///
|
||||
/// It's important to point out that this function is not the only method by
|
||||
/// which a value can be leaked in safe Rust code. Other known sources of
|
||||
/// leakage are:
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [exit]: ../../std/process/fn.exit.html
|
||||
///
|
||||
/// * `Rc` and `Arc` cycles
|
||||
/// * `mpsc::{Sender, Receiver}` cycles (they use `Arc` internally)
|
||||
/// * Panicking destructors are likely to leak local resources
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// Leak some heap memory by never deallocating it:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let heap_memory = Box::new(3);
|
||||
|
|
@ -77,7 +62,7 @@ pub use intrinsics::transmute;
|
|||
///
|
||||
/// Leak an I/O object, never closing the file:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// ```no_run
|
||||
/// use std::mem;
|
||||
/// use std::fs::File;
|
||||
///
|
||||
|
|
@ -85,9 +70,43 @@ pub use intrinsics::transmute;
|
|||
/// mem::forget(file);
|
||||
/// ```
|
||||
///
|
||||
/// The `mem::swap` function uses `mem::forget` to good effect:
|
||||
/// The practical use cases for `forget` are rather specialized and mainly come
|
||||
/// up in unsafe or FFI code.
|
||||
///
|
||||
/// ```rust
|
||||
/// ## Use case 1
|
||||
///
|
||||
/// You have created an uninitialized value using [`mem::uninitialized`][uninit].
|
||||
/// You must either initialize or `forget` it on every computation path before
|
||||
/// Rust drops it automatically, like at the end of a scope or after a panic.
|
||||
/// Running the destructor on an uninitialized value would be [undefined behavior][ub].
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// # let some_condition = false;
|
||||
/// unsafe {
|
||||
/// let mut uninit_vec: Vec<u32> = mem::uninitialized();
|
||||
///
|
||||
/// if some_condition {
|
||||
/// // Initialize the variable.
|
||||
/// ptr::write(&mut uninit_vec, Vec::new());
|
||||
/// } else {
|
||||
/// // Forget the uninitialized value so its destructor doesn't run.
|
||||
/// mem::forget(uninit_vec);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Use case 2
|
||||
///
|
||||
/// You have duplicated the bytes making up a value, without doing a proper
|
||||
/// [`Clone`][clone]. You need the value's destructor to run only once,
|
||||
/// because a double `free` is undefined behavior.
|
||||
///
|
||||
/// An example is the definition of [`mem::swap`][swap] in this module:
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
/// use std::ptr;
|
||||
///
|
||||
|
|
@ -109,6 +128,41 @@ pub use intrinsics::transmute;
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Use case 3
|
||||
///
|
||||
/// You are transferring ownership across a [FFI] boundary to code written in
|
||||
/// another language. You need to `forget` the value on the Rust side because Rust
|
||||
/// code is no longer responsible for it.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::mem;
|
||||
///
|
||||
/// extern "C" {
|
||||
/// fn my_c_function(x: *const u32);
|
||||
/// }
|
||||
///
|
||||
/// let x: Box<u32> = Box::new(3);
|
||||
///
|
||||
/// // Transfer ownership into C code.
|
||||
/// unsafe {
|
||||
/// my_c_function(&*x);
|
||||
/// }
|
||||
/// mem::forget(x);
|
||||
/// ```
|
||||
///
|
||||
/// In this case, C code must call back into Rust to free the object. Calling C's `free`
|
||||
/// function on a [`Box`][box] is *not* safe! Also, `Box` provides an [`into_raw`][into_raw]
|
||||
/// method which is the preferred way to do this in practice.
|
||||
///
|
||||
/// [drop]: fn.drop.html
|
||||
/// [uninit]: fn.uninitialized.html
|
||||
/// [clone]: ../clone/trait.Clone.html
|
||||
/// [swap]: fn.swap.html
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
/// [box]: ../../std/boxed/struct.Box.html
|
||||
/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn forget<T>(t: T) {
|
||||
|
|
@ -133,7 +187,14 @@ pub fn size_of<T>() -> usize {
|
|||
unsafe { intrinsics::size_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the size of the given value in bytes.
|
||||
/// Returns the size of the pointed-to value in bytes.
|
||||
///
|
||||
/// This is usually the same as `size_of::<T>()`. However, when `T` *has* no
|
||||
/// statically known size, e.g. a slice [`[T]`][slice] or a [trait object],
|
||||
/// then `size_of_val` can be used to get the dynamically-known size.
|
||||
///
|
||||
/// [slice]: ../../std/primitive.slice.html
|
||||
/// [trait object]: ../../book/trait-objects.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -141,6 +202,10 @@ pub fn size_of<T>() -> usize {
|
|||
/// use std::mem;
|
||||
///
|
||||
/// assert_eq!(4, mem::size_of_val(&5i32));
|
||||
///
|
||||
/// let x: [u8; 13] = [0; 13];
|
||||
/// let y: &[u8] = &x;
|
||||
/// assert_eq!(13, mem::size_of_val(y));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -148,10 +213,14 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
unsafe { intrinsics::size_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of a type
|
||||
/// Returns the [ABI]-required minimum alignment of a type.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -167,7 +236,11 @@ pub fn min_align_of<T>() -> usize {
|
|||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -184,10 +257,14 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the alignment in memory for a type.
|
||||
/// Returns the [ABI]-required minimum alignment of a type.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -201,7 +278,11 @@ pub fn align_of<T>() -> usize {
|
|||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -216,16 +297,23 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Creates a value initialized to zero.
|
||||
/// Creates a value whose bytes are all zero.
|
||||
///
|
||||
/// This function is similar to allocating space for a local variable and zeroing it out (an unsafe
|
||||
/// operation).
|
||||
/// This has the same effect as allocating space with
|
||||
/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for
|
||||
/// [FFI] sometimes, but should generally be avoided.
|
||||
///
|
||||
/// Care must be taken when using this function, if the type `T` has a destructor and the value
|
||||
/// falls out of scope (due to unwinding or returning) before being initialized, then the
|
||||
/// destructor will run on zeroed data, likely leading to crashes.
|
||||
/// There is no guarantee that an all-zero byte-pattern represents a valid value of
|
||||
/// some type `T`. If `T` has a destructor and the value is destroyed (due to
|
||||
/// a panic or the end of a scope) before being initialized, then the destructor
|
||||
/// will run on zeroed data, likely leading to [undefined behavior][ub].
|
||||
///
|
||||
/// This is useful for FFI functions sometimes, but should generally be avoided.
|
||||
/// See also the documentation for [`mem::uninitialized`][uninit], which has
|
||||
/// many of the same caveats.
|
||||
///
|
||||
/// [uninit]: fn.uninitialized.html
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -233,6 +321,7 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
/// use std::mem;
|
||||
///
|
||||
/// let x: i32 = unsafe { mem::zeroed() };
|
||||
/// assert_eq!(0, x);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -241,32 +330,38 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
}
|
||||
|
||||
/// Bypasses Rust's normal memory-initialization checks by pretending to
|
||||
/// produce a value of type T, while doing nothing at all.
|
||||
/// produce a value of type `T`, while doing nothing at all.
|
||||
///
|
||||
/// **This is incredibly dangerous, and should not be done lightly. Deeply
|
||||
/// consider initializing your memory with a default value instead.**
|
||||
///
|
||||
/// This is useful for FFI functions and initializing arrays sometimes,
|
||||
/// This is useful for [FFI] functions and initializing arrays sometimes,
|
||||
/// but should generally be avoided.
|
||||
///
|
||||
/// # Undefined Behavior
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
///
|
||||
/// It is Undefined Behavior to read uninitialized memory. Even just an
|
||||
/// # Undefined behavior
|
||||
///
|
||||
/// It is [undefined behavior][ub] to read uninitialized memory, even just an
|
||||
/// uninitialized boolean. For instance, if you branch on the value of such
|
||||
/// a boolean your program may take one, both, or neither of the branches.
|
||||
/// a boolean, your program may take one, both, or neither of the branches.
|
||||
///
|
||||
/// Note that this often also includes *writing* to the uninitialized value.
|
||||
/// Rust believes the value is initialized, and will therefore try to Drop
|
||||
/// the uninitialized value and its fields if you try to overwrite the memory
|
||||
/// in a normal manner. The only way to safely initialize an arbitrary
|
||||
/// uninitialized value is with one of the `ptr` functions: `write`, `copy`, or
|
||||
/// `copy_nonoverlapping`. This isn't necessary if `T` is a primitive
|
||||
/// or otherwise only contains types that don't implement Drop.
|
||||
/// Writing to the uninitialized value is similarly dangerous. Rust believes the
|
||||
/// value is initialized, and will therefore try to [`Drop`][drop] the uninitialized
|
||||
/// value and its fields if you try to overwrite it in a normal manner. The only way
|
||||
/// to safely initialize an uninitialized value is with [`ptr::write`][write],
|
||||
/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no].
|
||||
///
|
||||
/// If this value *does* need some kind of Drop, it must be initialized before
|
||||
/// If the value does implement `Drop`, it must be initialized before
|
||||
/// it goes out of scope (and therefore would be dropped). Note that this
|
||||
/// includes a `panic` occurring and unwinding the stack suddenly.
|
||||
///
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [write]: ../ptr/fn.write.html
|
||||
/// [copy]: ../intrinsics/fn.copy.html
|
||||
/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html
|
||||
/// [drop]: ../ops/trait.Drop.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Here's how to safely initialize an array of `Vec`s.
|
||||
|
|
@ -309,8 +404,8 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
/// println!("{:?}", &data[0]);
|
||||
/// ```
|
||||
///
|
||||
/// This example emphasizes exactly how delicate and dangerous doing this is.
|
||||
/// Note that the `vec!` macro *does* let you initialize every element with a
|
||||
/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized`
|
||||
/// can be. Note that the `vec!` macro *does* let you initialize every element with a
|
||||
/// value that is only `Clone`, so the following is semantically equivalent and
|
||||
/// vastly less dangerous, as long as you can live with an extra heap
|
||||
/// allocation:
|
||||
|
|
@ -325,21 +420,20 @@ pub unsafe fn uninitialized<T>() -> T {
|
|||
intrinsics::uninit()
|
||||
}
|
||||
|
||||
/// Swap the values at two mutable locations of the same type, without deinitializing or copying
|
||||
/// either one.
|
||||
/// Swaps the values at two mutable locations, without deinitializing either one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let x = &mut 5;
|
||||
/// let y = &mut 42;
|
||||
/// let mut x = 5;
|
||||
/// let mut y = 42;
|
||||
///
|
||||
/// mem::swap(x, y);
|
||||
/// mem::swap(&mut x, &mut y);
|
||||
///
|
||||
/// assert_eq!(42, *x);
|
||||
/// assert_eq!(5, *y);
|
||||
/// assert_eq!(42, x);
|
||||
/// assert_eq!(5, y);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -361,10 +455,7 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
}
|
||||
|
||||
/// Replaces the value at a mutable location with a new one, returning the old value, without
|
||||
/// deinitializing or copying either one.
|
||||
///
|
||||
/// This is primarily used for transferring and swapping ownership of a value in a mutable
|
||||
/// location.
|
||||
/// deinitializing either one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -373,15 +464,17 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let mut v: Vec<i32> = Vec::new();
|
||||
/// let mut v: Vec<i32> = vec![1, 2];
|
||||
///
|
||||
/// mem::replace(&mut v, Vec::new());
|
||||
/// let old_v = mem::replace(&mut v, vec![3, 4, 5]);
|
||||
/// assert_eq!(2, old_v.len());
|
||||
/// assert_eq!(3, v.len());
|
||||
/// ```
|
||||
///
|
||||
/// This function allows consumption of one field of a struct by replacing it with another value.
|
||||
/// The normal approach doesn't always work:
|
||||
/// `replace` allows consumption of a struct field by replacing it with another value.
|
||||
/// Without `replace` you can run into issues like these:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```ignore
|
||||
/// struct Buffer<T> { buf: Vec<T> }
|
||||
///
|
||||
/// impl<T> Buffer<T> {
|
||||
|
|
@ -401,6 +494,7 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// use std::mem;
|
||||
///
|
||||
/// # struct Buffer<T> { buf: Vec<T> }
|
||||
/// impl<T> Buffer<T> {
|
||||
/// fn get_and_reset(&mut self) -> Vec<T> {
|
||||
|
|
@ -417,14 +511,25 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
|
||||
/// Disposes of a value.
|
||||
///
|
||||
/// While this does call the argument's implementation of `Drop`, it will not
|
||||
/// release any borrows, as borrows are based on lexical scope.
|
||||
/// While this does call the argument's implementation of [`Drop`][drop],
|
||||
/// it will not release any borrows, as borrows are based on lexical scope.
|
||||
///
|
||||
/// This effectively does nothing for
|
||||
/// [types which implement `Copy`](../../book/ownership.html#copy-types),
|
||||
/// e.g. integers. Such values are copied and _then_ moved into the function,
|
||||
/// so the value persists after this function call.
|
||||
///
|
||||
/// This function is not magic; it is literally defined as
|
||||
///
|
||||
/// ```
|
||||
/// pub fn drop<T>(_x: T) { }
|
||||
/// ```
|
||||
///
|
||||
/// Because `_x` is moved into the function, it is automatically dropped before
|
||||
/// the function returns.
|
||||
///
|
||||
/// [drop]: ../ops/trait.Drop.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -461,8 +566,8 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
/// v.push(4); // no problems
|
||||
/// ```
|
||||
///
|
||||
/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can
|
||||
/// seemingly release a borrow of one:
|
||||
/// Since `RefCell` enforces the borrow rules at runtime, `drop` can
|
||||
/// release a `RefCell` borrow:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cell::RefCell;
|
||||
|
|
@ -478,7 +583,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
/// println!("{}", *borrow);
|
||||
/// ```
|
||||
///
|
||||
/// Integers and other types implementing `Copy` are unaffected by `drop()`
|
||||
/// Integers and other types implementing `Copy` are unaffected by `drop`.
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
|
|
@ -496,19 +601,22 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn drop<T>(_x: T) { }
|
||||
|
||||
/// Interprets `src` as `&U`, and then reads `src` without moving the contained
|
||||
/// value.
|
||||
/// Interprets `src` as having type `&U`, and then reads `src` without moving
|
||||
/// the contained value.
|
||||
///
|
||||
/// This function will unsafely assume the pointer `src` is valid for
|
||||
/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It
|
||||
/// will also unsafely create a copy of the contained value instead of moving
|
||||
/// out of `src`.
|
||||
/// [`size_of::<U>()`][size_of] bytes by transmuting `&T` to `&U` and then reading
|
||||
/// the `&U`. It will also unsafely create a copy of the contained value instead of
|
||||
/// moving out of `src`.
|
||||
///
|
||||
/// It is not a compile-time error if `T` and `U` have different sizes, but it
|
||||
/// is highly encouraged to only invoke this function where `T` and `U` have the
|
||||
/// same size. This function triggers undefined behavior if `U` is larger than
|
||||
/// same size. This function triggers [undefined behavior][ub] if `U` is larger than
|
||||
/// `T`.
|
||||
///
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [size_of]: fn.size_of.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -474,9 +474,9 @@ macro_rules! define_bignum {
|
|||
let sz = if self.size < 1 {1} else {self.size};
|
||||
let digitlen = mem::size_of::<$ty>() * 2;
|
||||
|
||||
try!(write!(f, "{:#x}", self.base[sz-1]));
|
||||
write!(f, "{:#x}", self.base[sz-1])?;
|
||||
for &v in self.base[..sz-1].iter().rev() {
|
||||
try!(write!(f, "_{:01$x}", v, digitlen));
|
||||
write!(f, "_{:01$x}", v, digitlen)?;
|
||||
}
|
||||
::result::Result::Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2211,25 +2211,21 @@ macro_rules! uint_impl {
|
|||
let mut base = self;
|
||||
let mut acc = 1;
|
||||
|
||||
let mut prev_base = self;
|
||||
let mut base_oflo = false;
|
||||
while exp > 0 {
|
||||
while exp > 1 {
|
||||
if (exp & 1) == 1 {
|
||||
if base_oflo {
|
||||
// ensure overflow occurs in the same manner it
|
||||
// would have otherwise (i.e. signal any exception
|
||||
// it would have otherwise).
|
||||
acc = acc * (prev_base * prev_base);
|
||||
} else {
|
||||
acc = acc * base;
|
||||
}
|
||||
acc = acc * base;
|
||||
}
|
||||
prev_base = base;
|
||||
let (new_base, new_base_oflo) = base.overflowing_mul(base);
|
||||
base = new_base;
|
||||
base_oflo = new_base_oflo;
|
||||
exp /= 2;
|
||||
base = base * base;
|
||||
}
|
||||
|
||||
// Deal with the final bit of the exponent separately, since
|
||||
// squaring the base afterwards is not necessary and may cause a
|
||||
// needless overflow.
|
||||
if exp == 1 {
|
||||
acc = acc * base;
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -282,6 +282,12 @@ macro_rules! forward_ref_binop {
|
|||
/// Point { x: 3, y: 3 });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that `RHS = Self` by default, but this is not mandatory. For example,
|
||||
/// [std::time::SystemTime] implements `Add<Duration>`, which permits
|
||||
/// operations of the form `SystemTime = SystemTime + Duration`.
|
||||
///
|
||||
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
|
||||
#[lang = "add"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Add<RHS=Self> {
|
||||
|
|
@ -349,6 +355,12 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
|||
/// Point { x: 1, y: 0 });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that `RHS = Self` by default, but this is not mandatory. For example,
|
||||
/// [std::time::SystemTime] implements `Sub<Duration>`, which permits
|
||||
/// operations of the form `SystemTime = SystemTime - Duration`.
|
||||
///
|
||||
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
|
||||
#[lang = "sub"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Sub<RHS=Self> {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
//! Optional values.
|
||||
//!
|
||||
//! Type `Option` represents an optional value: every `Option`
|
||||
//! is either `Some` and contains a value, or `None`, and
|
||||
//! does not. `Option` types are very common in Rust code, as
|
||||
//! Type [`Option`] represents an optional value: every [`Option`]
|
||||
//! is either [`Some`] and contains a value, or [`None`], and
|
||||
//! does not. [`Option`] types are very common in Rust code, as
|
||||
//! they have a number of uses:
|
||||
//!
|
||||
//! * Initial values
|
||||
|
|
@ -26,8 +26,8 @@
|
|||
//! * Nullable pointers
|
||||
//! * Swapping things out of difficult situations
|
||||
//!
|
||||
//! Options are commonly paired with pattern matching to query the presence
|
||||
//! of a value and take action, always accounting for the `None` case.
|
||||
//! [`Option`]s are commonly paired with pattern matching to query the presence
|
||||
//! of a value and take action, always accounting for the [`None`] case.
|
||||
//!
|
||||
//! ```
|
||||
//! fn divide(numerator: f64, denominator: f64) -> Option<f64> {
|
||||
|
|
@ -57,13 +57,13 @@
|
|||
//!
|
||||
//! Rust's pointer types must always point to a valid location; there are
|
||||
//! no "null" pointers. Instead, Rust has *optional* pointers, like
|
||||
//! the optional owned box, `Option<Box<T>>`.
|
||||
//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
|
||||
//!
|
||||
//! The following example uses `Option` to create an optional box of
|
||||
//! `i32`. Notice that in order to use the inner `i32` value first the
|
||||
//! The following example uses [`Option`] to create an optional box of
|
||||
//! [`i32`]. Notice that in order to use the inner [`i32`] value first the
|
||||
//! `check_optional` function needs to use pattern matching to
|
||||
//! determine whether the box has a value (i.e. it is `Some(...)`) or
|
||||
//! not (`None`).
|
||||
//! determine whether the box has a value (i.e. it is [`Some(...)`][`Some`]) or
|
||||
//! not ([`None`]).
|
||||
//!
|
||||
//! ```
|
||||
//! let optional: Option<Box<i32>> = None;
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This usage of `Option` to create safe nullable pointers is so
|
||||
//! This usage of [`Option`] to create safe nullable pointers is so
|
||||
//! common that Rust does special optimizations to make the
|
||||
//! representation of `Option<Box<T>>` a single pointer. Optional pointers
|
||||
//! representation of [`Option`]`<`[`Box<T>`]`>` a single pointer. Optional pointers
|
||||
//! in Rust are stored as efficiently as any other pointer type.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Basic pattern matching on `Option`:
|
||||
//! Basic pattern matching on [`Option`]:
|
||||
//!
|
||||
//! ```
|
||||
//! let msg = Some("howdy");
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
//! let unwrapped_msg = msg.unwrap_or("default message");
|
||||
//! ```
|
||||
//!
|
||||
//! Initialize a result to `None` before a loop:
|
||||
//! Initialize a result to [`None`] before a loop:
|
||||
//!
|
||||
//! ```
|
||||
//! enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) }
|
||||
|
|
@ -136,6 +136,12 @@
|
|||
//! None => println!("there are no animals :("),
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`Option`]: enum.Option.html
|
||||
//! [`Some`]: enum.Option.html#variant.Some
|
||||
//! [`None`]: enum.Option.html#variant.None
|
||||
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
//! [`i32`]: ../../std/primitive.i32.html
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -156,7 +162,7 @@ pub enum Option<T> {
|
|||
None,
|
||||
/// Some value `T`
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
Some(#[stable(feature = "rust1", since = "1.0.0")] T)
|
||||
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -168,7 +174,7 @@ impl<T> Option<T> {
|
|||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the option is a `Some` value
|
||||
/// Returns `true` if the option is a `Some` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -188,7 +194,7 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the option is a `None` value
|
||||
/// Returns `true` if the option is a `None` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -209,15 +215,17 @@ impl<T> Option<T> {
|
|||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Option<T>` to `Option<&T>`
|
||||
/// Converts from `Option<T>` to `Option<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Option<String>` into an `Option<usize>`, preserving the original.
|
||||
/// The `map` method takes the `self` argument by value, consuming the original,
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take an `Option` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Option.html#method.map
|
||||
///
|
||||
/// ```
|
||||
/// let num_as_str: Option<String> = Some("10".to_string());
|
||||
/// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
|
||||
|
|
@ -234,7 +242,7 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Option<T>` to `Option<&mut T>`
|
||||
/// Converts from `Option<T>` to `Option<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -357,7 +365,7 @@ impl<T> Option<T> {
|
|||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value
|
||||
/// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -423,8 +431,12 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to
|
||||
/// `Ok(v)` and `None` to `Err(err)`.
|
||||
/// Transforms the `Option<T>` into a [`Result<T, E>`], mapping `Some(v)` to
|
||||
/// [`Ok(v)`] and `None` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -444,8 +456,12 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to
|
||||
/// `Ok(v)` and `None` to `Err(err())`.
|
||||
/// Transforms the `Option<T>` into a [`Result<T, E>`], mapping `Some(v)` to
|
||||
/// [`Ok(v)`] and `None` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -698,6 +714,7 @@ fn expect_failed(msg: &str) -> ! {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for Option<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Option<T> { None }
|
||||
}
|
||||
|
|
@ -789,7 +806,9 @@ impl<A> DoubleEndedIterator for Item<A> {
|
|||
impl<A> ExactSizeIterator for Item<A> {}
|
||||
impl<A> FusedIterator for Item<A> {}
|
||||
|
||||
/// An iterator over a reference of the contained item in an Option.
|
||||
/// An iterator over a reference of the contained item in an [`Option`].
|
||||
///
|
||||
/// [`Option`]: enum.Option.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct Iter<'a, A: 'a> { inner: Item<&'a A> }
|
||||
|
|
@ -823,7 +842,9 @@ impl<'a, A> Clone for Iter<'a, A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over a mutable reference of the contained item in an Option.
|
||||
/// An iterator over a mutable reference of the contained item in an [`Option`].
|
||||
///
|
||||
/// [`Option`]: enum.Option.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> }
|
||||
|
|
@ -850,7 +871,9 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, A> FusedIterator for IterMut<'a, A> {}
|
||||
|
||||
/// An iterator over the item contained inside an Option.
|
||||
/// An iterator over the item contained inside an [`Option`].
|
||||
///
|
||||
/// [`Option`]: enum.Option.html
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IntoIter<A> { inner: Item<A> }
|
||||
|
|
|
|||
|
|
@ -479,6 +479,40 @@ impl<T: ?Sized> PartialEq for *mut T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Eq for *mut T {}
|
||||
|
||||
/// Compare raw pointers for equality.
|
||||
///
|
||||
/// This is the same as using the `==` operator, but less generic:
|
||||
/// the arguments have to be `*const T` raw pointers,
|
||||
/// not anything that implements `PartialEq`.
|
||||
///
|
||||
/// This can be used to compare `&T` references (which coerce to `*const T` implicitly)
|
||||
/// by their address rather than comparing the values they point to
|
||||
/// (which is what the `PartialEq for &T` implementation does).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_eq)]
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// let five = 5;
|
||||
/// let other_five = 5;
|
||||
/// let five_ref = &five;
|
||||
/// let same_five_ref = &five;
|
||||
/// let other_five_ref = &other_five;
|
||||
///
|
||||
/// assert!(five_ref == same_five_ref);
|
||||
/// assert!(five_ref == other_five_ref);
|
||||
///
|
||||
/// assert!(ptr::eq(five_ref, same_five_ref));
|
||||
/// assert!(!ptr::eq(five_ref, other_five_ref));
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")]
|
||||
#[inline]
|
||||
pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
|
||||
a == b
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for *const T {
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
//! Error handling with the `Result` type.
|
||||
//!
|
||||
//! `Result<T, E>` is the type used for returning and propagating
|
||||
//! errors. It is an enum with the variants, `Ok(T)`, representing
|
||||
//! success and containing a value, and `Err(E)`, representing error
|
||||
//! [`Result<T, E>`][`Result`] is the type used for returning and propagating
|
||||
//! errors. It is an enum with the variants, [`Ok(T)`], representing
|
||||
//! success and containing a value, and [`Err(E)`], representing error
|
||||
//! and containing an error value.
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -23,11 +23,11 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Functions return `Result` whenever errors are expected and
|
||||
//! recoverable. In the `std` crate `Result` is most prominently used
|
||||
//! Functions return [`Result`] whenever errors are expected and
|
||||
//! recoverable. In the `std` crate, [`Result`] is most prominently used
|
||||
//! for [I/O](../../std/io/index.html).
|
||||
//!
|
||||
//! A simple function returning `Result` might be
|
||||
//! A simple function returning [`Result`] might be
|
||||
//! defined and used like so:
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -50,8 +50,8 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Pattern matching on `Result`s is clear and straightforward for
|
||||
//! simple cases, but `Result` comes with some convenience methods
|
||||
//! Pattern matching on [`Result`]s is clear and straightforward for
|
||||
//! simple cases, but [`Result`] comes with some convenience methods
|
||||
//! that make working with it more succinct.
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
//!
|
||||
//! A common problem with using return values to indicate errors is
|
||||
//! that it is easy to ignore the return value, thus failing to handle
|
||||
//! the error. Result is annotated with the #[must_use] attribute,
|
||||
//! the error. [`Result`] is annotated with the `#[must_use]` attribute,
|
||||
//! which will cause the compiler to issue a warning when a Result
|
||||
//! value is ignored. This makes `Result` especially useful with
|
||||
//! value is ignored. This makes [`Result`] especially useful with
|
||||
//! functions that may encounter errors but don't otherwise return a
|
||||
//! useful value.
|
||||
//!
|
||||
//! Consider the `write_all` method defined for I/O types
|
||||
//! by the [`Write`](../../std/io/trait.Write.html) trait:
|
||||
//! Consider the [`write_all`] method defined for I/O types
|
||||
//! by the [`Write`] trait:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::io;
|
||||
|
|
@ -97,8 +97,8 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! *Note: The actual definition of `Write` uses `io::Result`, which
|
||||
//! is just a synonym for `Result<T, io::Error>`.*
|
||||
//! *Note: The actual definition of [`Write`] uses [`io::Result`], which
|
||||
//! is just a synonym for [`Result`]`<T, `[`io::Error`]`>`.*
|
||||
//!
|
||||
//! This method doesn't produce a value, but the write may
|
||||
//! fail. It's crucial to handle the error case, and *not* write
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
//! warning (by default, controlled by the `unused_must_use` lint).
|
||||
//!
|
||||
//! You might instead, if you don't want to handle the error, simply
|
||||
//! assert success with `expect`. This will panic if the
|
||||
//! assert success with [`expect`]. This will panic if the
|
||||
//! write fails, providing a marginally useful message indicating why:
|
||||
//!
|
||||
//! ```{.no_run}
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
//! assert!(file.write_all(b"important message").is_ok());
|
||||
//! ```
|
||||
//!
|
||||
//! Or propagate the error up the call stack with `try!`:
|
||||
//! Or propagate the error up the call stack with [`try!`]:
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::fs::File;
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
//! # The `try!` macro
|
||||
//!
|
||||
//! When writing code that calls many functions that return the
|
||||
//! `Result` type, the error handling can be tedious. The `try!`
|
||||
//! [`Result`] type, the error handling can be tedious. The [`try!`]
|
||||
//! macro hides some of the boilerplate of propagating errors up the
|
||||
//! call stack.
|
||||
//!
|
||||
|
|
@ -219,9 +219,9 @@
|
|||
//!
|
||||
//! *It's much nicer!*
|
||||
//!
|
||||
//! Wrapping an expression in `try!` will result in the unwrapped
|
||||
//! success (`Ok`) value, unless the result is `Err`, in which case
|
||||
//! `Err` is returned early from the enclosing function. Its simple definition
|
||||
//! Wrapping an expression in [`try!`] will result in the unwrapped
|
||||
//! success ([`Ok`]) value, unless the result is [`Err`], in which case
|
||||
//! [`Err`] is returned early from the enclosing function. Its simple definition
|
||||
//! makes it clear:
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -230,9 +230,21 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! `try!` is imported by the prelude and is available everywhere, but it can only
|
||||
//! be used in functions that return `Result` because of the early return of
|
||||
//! `Err` that it provides.
|
||||
//! [`try!`] is imported by the prelude and is available everywhere, but it can only
|
||||
//! be used in functions that return [`Result`] because of the early return of
|
||||
//! [`Err`] that it provides.
|
||||
//!
|
||||
//! [`expect`]: enum.Result.html#method.expect
|
||||
//! [`Write`]: ../../std/io/trait.Write.html
|
||||
//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all
|
||||
//! [`io::Result`]: ../../std/io/type.Result.html
|
||||
//! [`try!`]: ../../std/macro.try.html
|
||||
//! [`Result`]: enum.Result.html
|
||||
//! [`Ok(T)`]: enum.Result.html#variant.Ok
|
||||
//! [`Err(E)`]: enum.Result.html#variant.Err
|
||||
//! [`io::Error`]: ../../std/io/struct.Error.html
|
||||
//! [`Ok`]: enum.Result.html#variant.Ok
|
||||
//! [`Err`]: enum.Result.html#variant.Err
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -264,7 +276,7 @@ impl<T, E> Result<T, E> {
|
|||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns true if the result is `Ok`
|
||||
/// Returns true if the result is `Ok`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -286,7 +298,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the result is `Err`
|
||||
/// Returns true if the result is `Err`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -309,11 +321,13 @@ impl<T, E> Result<T, E> {
|
|||
// Adapter for each variant
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Result<T, E>` to `Option<T>`
|
||||
/// Converts from `Result<T, E>` to [`Option<T>`].
|
||||
///
|
||||
/// Converts `self` into an `Option<T>`, consuming `self`,
|
||||
/// Converts `self` into an [`Option<T>`], consuming `self`,
|
||||
/// and discarding the error, if any.
|
||||
///
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -334,11 +348,13 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Result<T, E>` to `Option<E>`
|
||||
/// Converts from `Result<T, E>` to [`Option<E>`].
|
||||
///
|
||||
/// Converts `self` into an `Option<E>`, consuming `self`,
|
||||
/// Converts `self` into an [`Option<E>`], consuming `self`,
|
||||
/// and discarding the success value, if any.
|
||||
///
|
||||
/// [`Option<E>`]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -363,7 +379,7 @@ impl<T, E> Result<T, E> {
|
|||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Result<T, E>` to `Result<&T, &E>`
|
||||
/// Converts from `Result<T, E>` to `Result<&T, &E>`.
|
||||
///
|
||||
/// Produces a new `Result`, containing a reference
|
||||
/// into the original, leaving the original in place.
|
||||
|
|
@ -388,7 +404,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Result<T, E>` to `Result<&mut T, &mut E>`
|
||||
/// Converts from `Result<T, E>` to `Result<&mut T, &mut E>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -563,7 +579,7 @@ impl<T, E> Result<T, E> {
|
|||
|
||||
/// Calls `op` if the result is `Ok`, otherwise returns the `Err` value of `self`.
|
||||
///
|
||||
/// This function can be used for control flow based on result values.
|
||||
/// This function can be used for control flow based on `Result` values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -646,7 +662,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
|
||||
/// Unwraps a result, yielding the content of an `Ok`.
|
||||
/// Else it returns `optb`.
|
||||
/// Else, it returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -837,7 +853,10 @@ impl<'a, T, E> IntoIterator for &'a mut Result<T, E> {
|
|||
// The Result Iterators
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// An iterator over a reference to the `Ok` variant of a `Result`.
|
||||
/// An iterator over a reference to the [`Ok`] variant of a [`Result`].
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Result`]: enum.Result.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Iter<'a, T: 'a> { inner: Option<&'a T> }
|
||||
|
|
@ -872,7 +891,10 @@ impl<'a, T> Clone for Iter<'a, T> {
|
|||
fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } }
|
||||
}
|
||||
|
||||
/// An iterator over a mutable reference to the `Ok` variant of a `Result`.
|
||||
/// An iterator over a mutable reference to the [`Ok`] variant of a [`Result`].
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Result`]: enum.Result.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IterMut<'a, T: 'a> { inner: Option<&'a mut T> }
|
||||
|
|
@ -902,7 +924,14 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T> FusedIterator for IterMut<'a, T> {}
|
||||
|
||||
/// An iterator over the value in a `Ok` variant of a `Result`.
|
||||
/// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is
|
||||
/// created by the [`into_iter`] method on [`Result`][`Result`] (provided by
|
||||
/// the [`IntoIterator`] trait).
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Result`]: enum.Result.html
|
||||
/// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter
|
||||
/// [`IntoIterator`]: ../iter/trait.IntoIterator.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IntoIter<T> { inner: Option<T> }
|
||||
|
|
|
|||
|
|
@ -520,8 +520,8 @@ impl<T> ops::Index<usize> for [T] {
|
|||
type Output = T;
|
||||
|
||||
fn index(&self, index: usize) -> &T {
|
||||
assert!(index < self.len());
|
||||
unsafe { self.get_unchecked(index) }
|
||||
// NB built-in indexing
|
||||
&(*self)[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -530,8 +530,8 @@ impl<T> ops::Index<usize> for [T] {
|
|||
impl<T> ops::IndexMut<usize> for [T] {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut T {
|
||||
assert!(index < self.len());
|
||||
unsafe { self.get_unchecked_mut(index) }
|
||||
// NB built-in indexing
|
||||
&mut (*self)[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -755,11 +755,13 @@ impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Default for &'a [T] {
|
||||
/// Creates an empty slice.
|
||||
fn default() -> &'a [T] { &[] }
|
||||
}
|
||||
|
||||
#[stable(feature = "mut_slice_default", since = "1.5.0")]
|
||||
impl<'a, T> Default for &'a mut [T] {
|
||||
/// Creates a mutable empty slice.
|
||||
fn default() -> &'a mut [T] { &mut [] }
|
||||
}
|
||||
|
||||
|
|
@ -1821,7 +1823,8 @@ impl<T: PartialOrd> PartialOrd for [T] {
|
|||
// intermediate trait for specialization of slice's PartialEq
|
||||
trait SlicePartialEq<B> {
|
||||
fn equal(&self, other: &[B]) -> bool;
|
||||
fn not_equal(&self, other: &[B]) -> bool;
|
||||
|
||||
fn not_equal(&self, other: &[B]) -> bool { !self.equal(other) }
|
||||
}
|
||||
|
||||
// Generic slice equality
|
||||
|
|
@ -1841,20 +1844,6 @@ impl<A, B> SlicePartialEq<B> for [A]
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
default fn not_equal(&self, other: &[B]) -> bool {
|
||||
if self.len() != other.len() {
|
||||
return true;
|
||||
}
|
||||
|
||||
for i in 0..self.len() {
|
||||
if self[i].ne(&other[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Use memcmp for bytewise equality when the types allow
|
||||
|
|
@ -1874,10 +1863,6 @@ impl<A> SlicePartialEq<A> for [A]
|
|||
other.as_ptr() as *const u8, size) == 0
|
||||
}
|
||||
}
|
||||
|
||||
fn not_equal(&self, other: &[A]) -> bool {
|
||||
!self.equal(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -1987,5 +1987,6 @@ impl AsRef<[u8]> for str {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Default for &'a str {
|
||||
/// Creates an empty str
|
||||
fn default() -> &'a str { "" }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ pub struct AtomicBool {
|
|||
#[cfg(target_has_atomic = "8")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Default for AtomicBool {
|
||||
/// Creates an `AtomicBool` initialised as false.
|
||||
fn default() -> Self {
|
||||
Self::new(false)
|
||||
}
|
||||
|
|
@ -117,6 +118,7 @@ pub struct AtomicPtr<T> {
|
|||
#[cfg(target_has_atomic = "ptr")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for AtomicPtr<T> {
|
||||
/// Creates a null `AtomicPtr<T>`.
|
||||
fn default() -> AtomicPtr<T> {
|
||||
AtomicPtr::new(::ptr::null_mut())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -664,12 +664,24 @@ fn test_max_by_key() {
|
|||
assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_by() {
|
||||
let xs: &[isize] = &[-3, 0, 1, 5, -10];
|
||||
assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_by_key() {
|
||||
let xs: &[isize] = &[-3, 0, 1, 5, -10];
|
||||
assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_by() {
|
||||
let xs: &[isize] = &[-3, 0, 1, 5, -10];
|
||||
assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_by_ref() {
|
||||
let mut xs = 0..10;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#![feature(try_from)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![feature(iter_max_by)]
|
||||
#![feature(iter_min_by)]
|
||||
|
||||
extern crate core;
|
||||
extern crate test;
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ impl OptGroup {
|
|||
}],
|
||||
}
|
||||
}
|
||||
(_, _) => panic!("something is wrong with the long-form opt"),
|
||||
_ => panic!("something is wrong with the long-form opt"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b
|
||||
Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c
|
||||
|
|
@ -124,12 +124,15 @@ 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"))]
|
||||
#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))]
|
||||
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
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -232,13 +232,13 @@ extern "C" {
|
|||
// Again, I'm not entirely sure what this is describing, it just seems to work.
|
||||
#[cfg_attr(not(test), lang = "msvc_try_filter")]
|
||||
static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor {
|
||||
pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _,
|
||||
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
|
||||
spare: 0 as *mut _,
|
||||
name: imp::NAME1,
|
||||
};
|
||||
|
||||
static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor {
|
||||
pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _,
|
||||
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
|
||||
spare: 0 as *mut _,
|
||||
name: imp::NAME2,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
|
|||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Default for ReseedWithDefault {
|
||||
/// Creates an instance of `ReseedWithDefault`.
|
||||
fn default() -> ReseedWithDefault {
|
||||
ReseedWithDefault
|
||||
}
|
||||
|
|
@ -137,6 +138,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
impl Default for Counter {
|
||||
/// Constructs a `Counter` with initial value zero.
|
||||
fn default() -> Counter {
|
||||
Counter { i: 0 }
|
||||
}
|
||||
|
|
|
|||
1609
src/librbml/lib.rs
1609
src/librbml/lib.rs
File diff suppressed because it is too large
Load diff
|
|
@ -14,7 +14,6 @@ flate = { path = "../libflate" }
|
|||
fmt_macros = { path = "../libfmt_macros" }
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = { path = "../liblog" }
|
||||
rbml = { path = "../librbml" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
|
||||
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
|
||||
match pat.node {
|
||||
PatKind::Binding(_, _, None) |
|
||||
PatKind::Binding(.., None) |
|
||||
PatKind::Path(..) |
|
||||
PatKind::Lit(..) |
|
||||
PatKind::Range(..) |
|
||||
|
|
@ -109,7 +109,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
|
||||
PatKind::Box(ref subpat) |
|
||||
PatKind::Ref(ref subpat, _) |
|
||||
PatKind::Binding(_, _, Some(ref subpat)) => {
|
||||
PatKind::Binding(.., Some(ref subpat)) => {
|
||||
let subpat_exit = self.pat(&subpat, pred);
|
||||
self.add_ast_node(pat.id, &[subpat_exit])
|
||||
}
|
||||
|
|
@ -306,7 +306,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
self.call(expr, pred, &func, args.iter().map(|e| &**e))
|
||||
}
|
||||
|
||||
hir::ExprMethodCall(_, _, ref args) => {
|
||||
hir::ExprMethodCall(.., ref args) => {
|
||||
self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -341,6 +341,8 @@ path is found (as demonstrated above).
|
|||
|
||||
### Debugging the dependency graph
|
||||
|
||||
#### Dumping the graph
|
||||
|
||||
The compiler is also capable of dumping the dependency graph for your
|
||||
debugging pleasure. To do so, pass the `-Z dump-dep-graph` flag. The
|
||||
graph will be dumped to `dep_graph.{txt,dot}` in the current
|
||||
|
|
@ -392,6 +394,35 @@ This will dump out all the nodes that lead from `Hir(foo)` to
|
|||
`TypeckItemBody(bar)`, from which you can (hopefully) see the source
|
||||
of the erroneous edge.
|
||||
|
||||
#### Tracking down incorrect edges
|
||||
|
||||
Sometimes, after you dump the dependency graph, you will find some
|
||||
path that should not exist, but you will not be quite sure how it came
|
||||
to be. **When the compiler is built with debug assertions,** it can
|
||||
help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE`
|
||||
environment variable to a filter. Every edge created in the dep-graph
|
||||
will be tested against that filter -- if it matches, a `bug!` is
|
||||
reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`).
|
||||
|
||||
The syntax for these filters is the same as described in the previous
|
||||
section. However, note that this filter is applied to every **edge**
|
||||
and doesn't handle longer paths in the graph, unlike the previous
|
||||
section.
|
||||
|
||||
Example:
|
||||
|
||||
You find that there is a path from the `Hir` of `foo` to the type
|
||||
check of `bar` and you don't think there should be. You dump the
|
||||
dep-graph as described in the previous section and open `dep-graph.txt`
|
||||
to see something like:
|
||||
|
||||
Hir(foo) -> Collect(bar)
|
||||
Collect(bar) -> TypeckItemBody(bar)
|
||||
|
||||
That first edge looks suspicious to you. So you set
|
||||
`RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and
|
||||
then observe the backtrace. Voila, bug fixed!
|
||||
|
||||
### Inlining of HIR nodes
|
||||
|
||||
For the time being, at least, we still sometimes "inline" HIR nodes
|
||||
|
|
|
|||
|
|
@ -66,4 +66,11 @@ impl EdgeFilter {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test<D: Clone + Debug>(&self,
|
||||
source: &DepNode<D>,
|
||||
target: &DepNode<D>)
|
||||
-> bool {
|
||||
self.source.test(source) && self.target.test(target)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,18 +103,13 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
// table in the tcx (or elsewhere) maps to one of these
|
||||
// nodes. Often we map multiple tables to the same node if there
|
||||
// is no point in distinguishing them (e.g., both the type and
|
||||
// predicates for an item wind up in `ItemSignature`). Other
|
||||
// times, such as `ImplItems` vs `TraitItemDefIds`, tables which
|
||||
// might be mergable are kept distinct because the sets of def-ids
|
||||
// to which they apply are disjoint, and hence we might as well
|
||||
// have distinct labels for easier debugging.
|
||||
// predicates for an item wind up in `ItemSignature`).
|
||||
ImplOrTraitItems(D),
|
||||
ItemSignature(D),
|
||||
FieldTy(D),
|
||||
SizedConstraint(D),
|
||||
TraitItemDefIds(D),
|
||||
ImplOrTraitItemDefIds(D),
|
||||
InherentImpls(D),
|
||||
ImplItems(D),
|
||||
|
||||
// The set of impls for a given trait. Ultimately, it would be
|
||||
// nice to get more fine-grained here (e.g., to include a
|
||||
|
|
@ -132,7 +127,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
// which would yield an overly conservative dep-graph.
|
||||
TraitItems(D),
|
||||
ReprHints(D),
|
||||
TraitSelect(D, Vec<D>),
|
||||
TraitSelect(Vec<D>),
|
||||
}
|
||||
|
||||
impl<D: Clone + Debug> DepNode<D> {
|
||||
|
|
@ -162,9 +157,8 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
ImplOrTraitItems,
|
||||
ItemSignature,
|
||||
FieldTy,
|
||||
TraitItemDefIds,
|
||||
ImplOrTraitItemDefIds,
|
||||
InherentImpls,
|
||||
ImplItems,
|
||||
TraitImpls,
|
||||
ReprHints,
|
||||
}
|
||||
|
|
@ -231,16 +225,14 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
ItemSignature(ref d) => op(d).map(ItemSignature),
|
||||
FieldTy(ref d) => op(d).map(FieldTy),
|
||||
SizedConstraint(ref d) => op(d).map(SizedConstraint),
|
||||
TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
|
||||
ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds),
|
||||
InherentImpls(ref d) => op(d).map(InherentImpls),
|
||||
ImplItems(ref d) => op(d).map(ImplItems),
|
||||
TraitImpls(ref d) => op(d).map(TraitImpls),
|
||||
TraitItems(ref d) => op(d).map(TraitItems),
|
||||
ReprHints(ref d) => op(d).map(ReprHints),
|
||||
TraitSelect(ref d, ref type_ds) => {
|
||||
let d = try_opt!(op(d));
|
||||
TraitSelect(ref type_ds) => {
|
||||
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
|
||||
Some(TraitSelect(d, type_ds))
|
||||
Some(TraitSelect(type_ds))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,17 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
|
|||
pub fn keys(&self) -> Vec<M::Key> {
|
||||
self.map.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/// Append `elem` to the vector stored for `k`, creating a new vector if needed.
|
||||
/// This is considered a write to `k`.
|
||||
pub fn push<E: Clone>(&mut self, k: M::Key, elem: E)
|
||||
where M: DepTrackingMapConfig<Value=Vec<E>>
|
||||
{
|
||||
self.write(&k);
|
||||
self.map.entry(k)
|
||||
.or_insert(Vec::new())
|
||||
.push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ impl DepGraph {
|
|||
data: Rc::new(DepGraphData {
|
||||
thread: DepGraphThreadData::new(enabled),
|
||||
previous_work_products: RefCell::new(FnvHashMap()),
|
||||
work_products: RefCell::new(FnvHashMap())
|
||||
work_products: RefCell::new(FnvHashMap()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ mod edges;
|
|||
mod graph;
|
||||
mod query;
|
||||
mod raii;
|
||||
mod shadow;
|
||||
mod thread;
|
||||
mod visit;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,3 +47,4 @@ impl<'graph> Drop for IgnoreTask<'graph> {
|
|||
self.data.enqueue(DepMessage::PopIgnore);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
145
src/librustc/dep_graph/shadow.rs
Normal file
145
src/librustc/dep_graph/shadow.rs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The "Shadow Graph" is maintained on the main thread and which
|
||||
//! tracks each message relating to the dep-graph and applies some
|
||||
//! sanity checks as they go by. If an error results, it means you get
|
||||
//! a nice stack-trace telling you precisely what caused the error.
|
||||
//!
|
||||
//! NOTE: This is a debugging facility which can potentially have non-trivial
|
||||
//! runtime impact. Therefore, it is largely compiled out if
|
||||
//! debug-assertions are not enabled.
|
||||
//!
|
||||
//! The basic sanity check, enabled if you have debug assertions
|
||||
//! enabled, is that there is always a task (or ignore) on the stack
|
||||
//! when you do read/write, and that the tasks are pushed/popped
|
||||
//! according to a proper stack discipline.
|
||||
//!
|
||||
//! Optionally, if you specify RUST_FORBID_DEP_GRAPH_EDGE, you can
|
||||
//! specify an edge filter to be applied to each edge as it is
|
||||
//! created. See `./README.md` for details.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use std::cell::{BorrowState, RefCell};
|
||||
use std::env;
|
||||
|
||||
use super::DepNode;
|
||||
use super::thread::DepMessage;
|
||||
use super::debug::EdgeFilter;
|
||||
|
||||
pub struct ShadowGraph {
|
||||
// if you push None onto the stack, that corresponds to an Ignore
|
||||
stack: RefCell<Vec<Option<DepNode<DefId>>>>,
|
||||
forbidden_edge: Option<EdgeFilter>,
|
||||
}
|
||||
|
||||
const ENABLED: bool = cfg!(debug_assertions);
|
||||
|
||||
impl ShadowGraph {
|
||||
pub fn new() -> Self {
|
||||
let forbidden_edge = if !ENABLED {
|
||||
None
|
||||
} else {
|
||||
match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
|
||||
Ok(s) => {
|
||||
match EdgeFilter::new(&s) {
|
||||
Ok(f) => Some(f),
|
||||
Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
|
||||
}
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
};
|
||||
|
||||
ShadowGraph {
|
||||
stack: RefCell::new(vec![]),
|
||||
forbidden_edge: forbidden_edge,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enqueue(&self, message: &DepMessage) {
|
||||
if ENABLED {
|
||||
match self.stack.borrow_state() {
|
||||
BorrowState::Unused => {}
|
||||
_ => {
|
||||
// When we apply edge filters, that invokes the
|
||||
// Debug trait on DefIds, which in turn reads from
|
||||
// various bits of state and creates reads! Ignore
|
||||
// those recursive reads.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
match *message {
|
||||
DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)),
|
||||
DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))),
|
||||
DepMessage::PushTask(ref n) => stack.push(Some(n.clone())),
|
||||
DepMessage::PushIgnore => stack.push(None),
|
||||
DepMessage::PopTask(ref n) => {
|
||||
match stack.pop() {
|
||||
Some(Some(m)) => {
|
||||
if *n != m {
|
||||
bug!("stack mismatch: found {:?} expected {:?}", m, n)
|
||||
}
|
||||
}
|
||||
Some(None) => bug!("stack mismatch: found Ignore expected {:?}", n),
|
||||
None => bug!("stack mismatch: found empty stack, expected {:?}", n),
|
||||
}
|
||||
}
|
||||
DepMessage::PopIgnore => {
|
||||
match stack.pop() {
|
||||
Some(Some(m)) => bug!("stack mismatch: found {:?} expected ignore", m),
|
||||
Some(None) => (),
|
||||
None => bug!("stack mismatch: found empty stack, expected ignore"),
|
||||
}
|
||||
}
|
||||
DepMessage::Query => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_edge(&self,
|
||||
source: Option<Option<&DepNode<DefId>>>,
|
||||
target: Option<Option<&DepNode<DefId>>>) {
|
||||
assert!(ENABLED);
|
||||
match (source, target) {
|
||||
// cannot happen, one side is always Some(Some(_))
|
||||
(None, None) => unreachable!(),
|
||||
|
||||
// nothing on top of the stack
|
||||
(None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n),
|
||||
|
||||
// this corresponds to an Ignore being top of the stack
|
||||
(Some(None), _) | (_, Some(None)) => (),
|
||||
|
||||
// a task is on top of the stack
|
||||
(Some(Some(source)), Some(Some(target))) => {
|
||||
if let Some(ref forbidden_edge) = self.forbidden_edge {
|
||||
if forbidden_edge.test(source, target) {
|
||||
bug!("forbidden edge {:?} -> {:?} created", source, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do a little juggling: we get back a reference to an option at the
|
||||
// top of the stack, convert it to an optional reference.
|
||||
fn top<'s>(stack: &'s Vec<Option<DepNode<DefId>>>) -> Option<Option<&'s DepNode<DefId>>> {
|
||||
stack.last()
|
||||
.map(|n: &'s Option<DepNode<DefId>>| -> Option<&'s DepNode<DefId>> {
|
||||
// (*)
|
||||
// (*) type annotation just there to clarify what would
|
||||
// otherwise be some *really* obscure code
|
||||
n.as_ref()
|
||||
})
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@
|
|||
|
||||
use hir::def_id::DefId;
|
||||
use rustc_data_structures::veccell::VecCell;
|
||||
use std::cell::Cell;
|
||||
use std::sync::mpsc::{self, Sender, Receiver};
|
||||
use std::thread;
|
||||
|
||||
use super::DepGraphQuery;
|
||||
use super::DepNode;
|
||||
use super::edges::DepGraphEdges;
|
||||
use super::shadow::ShadowGraph;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DepMessage {
|
||||
|
|
@ -42,12 +42,16 @@ pub enum DepMessage {
|
|||
pub struct DepGraphThreadData {
|
||||
enabled: bool,
|
||||
|
||||
// Local counter that just tracks how many tasks are pushed onto the
|
||||
// stack, so that we still get an error in the case where one is
|
||||
// missing. If dep-graph construction is enabled, we'd get the same
|
||||
// error when processing tasks later on, but that's annoying because
|
||||
// it lacks precision about the source of the error.
|
||||
tasks_pushed: Cell<usize>,
|
||||
// The "shadow graph" is a debugging aid. We give it each message
|
||||
// in real time as it arrives and it checks for various errors
|
||||
// (for example, a read/write when there is no current task; it
|
||||
// can also apply user-defined filters; see `shadow` module for
|
||||
// details). This only occurs if debug-assertions are enabled.
|
||||
//
|
||||
// Note that in some cases the same errors will occur when the
|
||||
// data is processed off the main thread, but that's annoying
|
||||
// because it lacks precision about the source of the error.
|
||||
shadow_graph: ShadowGraph,
|
||||
|
||||
// current buffer, where we accumulate messages
|
||||
messages: VecCell<DepMessage>,
|
||||
|
|
@ -76,7 +80,7 @@ impl DepGraphThreadData {
|
|||
|
||||
DepGraphThreadData {
|
||||
enabled: enabled,
|
||||
tasks_pushed: Cell::new(0),
|
||||
shadow_graph: ShadowGraph::new(),
|
||||
messages: VecCell::with_capacity(INITIAL_CAPACITY),
|
||||
swap_in: rx2,
|
||||
swap_out: tx1,
|
||||
|
|
@ -118,21 +122,7 @@ impl DepGraphThreadData {
|
|||
/// the buffer is full, this may swap.)
|
||||
#[inline]
|
||||
pub fn enqueue(&self, message: DepMessage) {
|
||||
// Regardless of whether dep graph construction is enabled, we
|
||||
// still want to check that we always have a valid task on the
|
||||
// stack when a read/write/etc event occurs.
|
||||
match message {
|
||||
DepMessage::Read(_) | DepMessage::Write(_) =>
|
||||
if self.tasks_pushed.get() == 0 {
|
||||
self.invalid_message("read/write but no current task")
|
||||
},
|
||||
DepMessage::PushTask(_) | DepMessage::PushIgnore =>
|
||||
self.tasks_pushed.set(self.tasks_pushed.get() + 1),
|
||||
DepMessage::PopTask(_) | DepMessage::PopIgnore =>
|
||||
self.tasks_pushed.set(self.tasks_pushed.get() - 1),
|
||||
DepMessage::Query =>
|
||||
(),
|
||||
}
|
||||
self.shadow_graph.enqueue(&message);
|
||||
|
||||
if self.enabled {
|
||||
self.enqueue_enabled(message);
|
||||
|
|
@ -147,11 +137,6 @@ impl DepGraphThreadData {
|
|||
self.swap();
|
||||
}
|
||||
}
|
||||
|
||||
// Outline this too.
|
||||
fn invalid_message(&self, string: &str) {
|
||||
bug!("{}; see src/librustc/dep_graph/README.md for more information", string)
|
||||
}
|
||||
}
|
||||
|
||||
/// Definition of the depgraph thread.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use syntax::visit::Visitor;
|
|||
enum Target {
|
||||
Fn,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
Other,
|
||||
}
|
||||
|
|
@ -27,6 +28,7 @@ impl Target {
|
|||
match item.node {
|
||||
ast::ItemKind::Fn(..) => Target::Fn,
|
||||
ast::ItemKind::Struct(..) => Target::Struct,
|
||||
ast::ItemKind::Union(..) => Target::Union,
|
||||
ast::ItemKind::Enum(..) => Target::Enum,
|
||||
_ => Target::Other,
|
||||
}
|
||||
|
|
@ -40,7 +42,9 @@ struct CheckAttrVisitor<'a> {
|
|||
impl<'a> CheckAttrVisitor<'a> {
|
||||
fn check_inline(&self, attr: &ast::Attribute, target: Target) {
|
||||
if target != Target::Fn {
|
||||
span_err!(self.sess, attr.span, E0518, "attribute should be applied to function");
|
||||
struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
|
||||
.span_label(attr.span, &format!("requires a function"))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,16 +58,20 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
|
||||
let mut conflicting_reprs = 0;
|
||||
for word in words {
|
||||
|
||||
let name = match word.name() {
|
||||
Some(word) => word,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let message = match &*name {
|
||||
let (message, label) = match &*name {
|
||||
"C" => {
|
||||
conflicting_reprs += 1;
|
||||
if target != Target::Struct && target != Target::Enum {
|
||||
"attribute should be applied to struct or enum"
|
||||
if target != Target::Struct &&
|
||||
target != Target::Union &&
|
||||
target != Target::Enum {
|
||||
("attribute should be applied to struct, enum or union",
|
||||
"a struct, enum or union")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
|
@ -71,8 +79,10 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
"packed" => {
|
||||
// Do not increment conflicting_reprs here, because "packed"
|
||||
// can be used to modify another repr hint
|
||||
if target != Target::Struct {
|
||||
"attribute should be applied to struct"
|
||||
if target != Target::Struct &&
|
||||
target != Target::Union {
|
||||
("attribute should be applied to struct or union",
|
||||
"a struct or union")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
|
@ -80,7 +90,8 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
"simd" => {
|
||||
conflicting_reprs += 1;
|
||||
if target != Target::Struct {
|
||||
"attribute should be applied to struct"
|
||||
("attribute should be applied to struct",
|
||||
"a struct")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
|
@ -90,15 +101,17 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
"isize" | "usize" => {
|
||||
conflicting_reprs += 1;
|
||||
if target != Target::Enum {
|
||||
"attribute should be applied to enum"
|
||||
("attribute should be applied to enum",
|
||||
"an enum")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
span_err!(self.sess, attr.span, E0517, "{}", message);
|
||||
struct_span_err!(self.sess, attr.span, E0517, "{}", message)
|
||||
.span_label(attr.span, &format!("requires {}", label))
|
||||
.emit();
|
||||
}
|
||||
if conflicting_reprs > 1 {
|
||||
span_warn!(self.sess, attr.span, E0566,
|
||||
|
|
|
|||
|
|
@ -16,23 +16,20 @@ use hir;
|
|||
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum Def {
|
||||
Fn(DefId),
|
||||
SelfTy(Option<DefId> /* trait */, Option<ast::NodeId> /* impl */),
|
||||
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
|
||||
Mod(DefId),
|
||||
ForeignMod(DefId),
|
||||
Static(DefId, bool /* is_mutbl */),
|
||||
Const(DefId),
|
||||
AssociatedConst(DefId),
|
||||
Local(DefId, // def id of variable
|
||||
ast::NodeId), // node id of variable
|
||||
Variant(DefId /* enum */, DefId /* variant */),
|
||||
Local(DefId),
|
||||
Variant(DefId),
|
||||
Enum(DefId),
|
||||
TyAlias(DefId),
|
||||
AssociatedTy(DefId /* trait */, DefId),
|
||||
AssociatedTy(DefId),
|
||||
Trait(DefId),
|
||||
PrimTy(hir::PrimTy),
|
||||
TyParam(DefId),
|
||||
Upvar(DefId, // def id of closed over local
|
||||
ast::NodeId, // node id of closed over local
|
||||
usize, // index in the freevars list of the closure
|
||||
ast::NodeId), // expr node that creates the closure
|
||||
|
||||
|
|
@ -41,6 +38,7 @@ pub enum Def {
|
|||
// If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions)
|
||||
// it denotes a constructor and its DefId refers to NodeId of the struct's constructor.
|
||||
Struct(DefId),
|
||||
Union(DefId),
|
||||
Label(ast::NodeId),
|
||||
Method(DefId),
|
||||
Err,
|
||||
|
|
@ -93,37 +91,20 @@ pub type DefMap = NodeMap<PathResolution>;
|
|||
// within.
|
||||
pub type ExportMap = NodeMap<Vec<Export>>;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct Export {
|
||||
pub name: ast::Name, // The name of the target.
|
||||
pub def_id: DefId, // The definition of the target.
|
||||
}
|
||||
|
||||
impl Def {
|
||||
pub fn var_id(&self) -> ast::NodeId {
|
||||
match *self {
|
||||
Def::Local(_, id) |
|
||||
Def::Upvar(_, id, _, _) => {
|
||||
id
|
||||
}
|
||||
|
||||
Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
|
||||
Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
|
||||
Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
|
||||
Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
|
||||
Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
|
||||
bug!("attempted .var_id() on invalid {:?}", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
match *self {
|
||||
Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
|
||||
Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
|
||||
Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) |
|
||||
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
|
||||
Def::Variant(id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) |
|
||||
Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
|
||||
Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
|
||||
Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
|
||||
Def::Local(id) | Def::Upvar(id, ..) => {
|
||||
id
|
||||
}
|
||||
|
||||
|
|
@ -140,13 +121,13 @@ impl Def {
|
|||
match *self {
|
||||
Def::Fn(..) => "function",
|
||||
Def::Mod(..) => "module",
|
||||
Def::ForeignMod(..) => "foreign module",
|
||||
Def::Static(..) => "static",
|
||||
Def::Variant(..) => "variant",
|
||||
Def::Enum(..) => "enum",
|
||||
Def::TyAlias(..) => "type",
|
||||
Def::AssociatedTy(..) => "associated type",
|
||||
Def::Struct(..) => "struct",
|
||||
Def::Union(..) => "union",
|
||||
Def::Trait(..) => "trait",
|
||||
Def::Method(..) => "method",
|
||||
Def::Const(..) => "constant",
|
||||
|
|
|
|||
|
|
@ -8,12 +8,69 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::cstore::LOCAL_CRATE;
|
||||
use ty;
|
||||
use syntax::ast::CrateNum;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use serialize::{self, Encoder, Decoder};
|
||||
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
|
||||
#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)]
|
||||
pub struct CrateNum(u32);
|
||||
|
||||
impl Idx for CrateNum {
|
||||
fn new(value: usize) -> Self {
|
||||
assert!(value < (u32::MAX) as usize);
|
||||
CrateNum(value as u32)
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Item definitions in the currently-compiled crate would have the CrateNum
|
||||
/// LOCAL_CRATE in their DefId.
|
||||
pub const LOCAL_CRATE: CrateNum = CrateNum(0);
|
||||
|
||||
impl CrateNum {
|
||||
pub fn new(x: usize) -> CrateNum {
|
||||
assert!(x < (u32::MAX as usize));
|
||||
CrateNum(x as u32)
|
||||
}
|
||||
|
||||
pub fn from_u32(x: u32) -> CrateNum {
|
||||
CrateNum(x)
|
||||
}
|
||||
|
||||
pub fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
pub fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CrateNum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl serialize::UseSpecializedEncodable for CrateNum {
|
||||
fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl serialize::UseSpecializedDecodable for CrateNum {
|
||||
fn default_decode<D: Decoder>(d: &mut D) -> Result<CrateNum, D::Error> {
|
||||
d.read_u32().map(CrateNum)
|
||||
}
|
||||
}
|
||||
|
||||
/// A DefIndex is an index into the hir-map for a crate, identifying a
|
||||
/// particular definition. It should really be considered an interned
|
||||
/// shorthand for a particular DefPath.
|
||||
|
|
@ -46,8 +103,7 @@ pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
|
|||
|
||||
/// A DefId identifies a particular *definition*, by combining a crate
|
||||
/// index and a def index.
|
||||
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
|
||||
RustcDecodable, Hash, Copy)]
|
||||
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)]
|
||||
pub struct DefId {
|
||||
pub krate: CrateNum,
|
||||
pub index: DefIndex,
|
||||
|
|
@ -58,19 +114,14 @@ impl fmt::Debug for DefId {
|
|||
write!(f, "DefId {{ krate: {:?}, node: {:?}",
|
||||
self.krate, self.index)?;
|
||||
|
||||
// Unfortunately, there seems to be no way to attempt to print
|
||||
// a path for a def-id, so I'll just make a best effort for now
|
||||
// and otherwise fallback to just printing the crate/node pair
|
||||
if self.is_local() { // (1)
|
||||
// (1) side-step fact that not all external things have paths at
|
||||
// the moment, such as type parameters
|
||||
ty::tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
write!(f, " => {}", tcx.item_path_str(*self))?;
|
||||
ty::tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
if let Some(def_path) = tcx.opt_def_path(*self) {
|
||||
write!(f, " => {}", def_path.to_string(tcx))?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
write!(f, " }}")
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -49,8 +49,8 @@ pub enum FnKind<'a> {
|
|||
impl<'a> FnKind<'a> {
|
||||
pub fn attrs(&self) -> &'a [Attribute] {
|
||||
match *self {
|
||||
FnKind::ItemFn(_, _, _, _, _, _, attrs) => attrs,
|
||||
FnKind::Method(_, _, _, attrs) => attrs,
|
||||
FnKind::ItemFn(.., attrs) => attrs,
|
||||
FnKind::Method(.., attrs) => attrs,
|
||||
FnKind::Closure(attrs) => attrs,
|
||||
}
|
||||
}
|
||||
|
|
@ -341,14 +341,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
visitor.visit_id(item.id);
|
||||
visitor.visit_trait_ref(trait_ref)
|
||||
}
|
||||
ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
|
||||
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);
|
||||
walk_list!(visitor, visit_impl_item, impl_items);
|
||||
}
|
||||
ItemStruct(ref struct_definition, ref generics) => {
|
||||
ItemStruct(ref struct_definition, ref generics) |
|
||||
ItemUnion(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);
|
||||
|
|
@ -621,10 +622,10 @@ pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declarat
|
|||
|
||||
pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
|
||||
match function_kind {
|
||||
FnKind::ItemFn(_, generics, _, _, _, _, _) => {
|
||||
FnKind::ItemFn(_, generics, ..) => {
|
||||
visitor.visit_generics(generics);
|
||||
}
|
||||
FnKind::Method(_, sig, _, _) => {
|
||||
FnKind::Method(_, sig, ..) => {
|
||||
visitor.visit_generics(&sig.generics);
|
||||
}
|
||||
FnKind::Closure(_) => {}
|
||||
|
|
@ -880,8 +881,8 @@ pub struct IdRange {
|
|||
impl IdRange {
|
||||
pub fn max() -> IdRange {
|
||||
IdRange {
|
||||
min: u32::MAX,
|
||||
max: u32::MIN,
|
||||
min: NodeId::from_u32(u32::MAX),
|
||||
max: NodeId::from_u32(u32::MIN),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -895,7 +896,7 @@ impl IdRange {
|
|||
|
||||
pub fn add(&mut self, id: NodeId) {
|
||||
self.min = cmp::min(self.min, id);
|
||||
self.max = cmp::max(self.max, id + 1);
|
||||
self.max = cmp::max(self.max, NodeId::from_u32(id.as_u32() + 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ use syntax_pos::Span;
|
|||
pub struct LoweringContext<'a> {
|
||||
crate_root: Option<&'static str>,
|
||||
// Use to assign ids to hir nodes that do not directly correspond to an ast node
|
||||
sess: Option<&'a Session>,
|
||||
sess: &'a Session,
|
||||
// As we walk the AST we must keep track of the current 'parent' def id (in
|
||||
// the form of a DefIndex) so that if we create a new node which introduces
|
||||
// a definition, then we can properly create the def id.
|
||||
|
|
@ -81,21 +81,7 @@ pub trait Resolver {
|
|||
|
||||
// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
|
||||
// This should only return `None` during testing.
|
||||
fn definitions(&mut self) -> Option<&mut Definitions>;
|
||||
}
|
||||
|
||||
pub struct DummyResolver;
|
||||
impl Resolver for DummyResolver {
|
||||
fn resolve_generated_global_path(&mut self, _path: &hir::Path, _is_value: bool) -> Def {
|
||||
Def::Err
|
||||
}
|
||||
fn get_resolution(&mut self, _id: NodeId) -> Option<PathResolution> {
|
||||
None
|
||||
}
|
||||
fn record_resolution(&mut self, _id: NodeId, _def: Def) {}
|
||||
fn definitions(&mut self) -> Option<&mut Definitions> {
|
||||
None
|
||||
}
|
||||
fn definitions(&mut self) -> &mut Definitions;
|
||||
}
|
||||
|
||||
pub fn lower_crate(sess: &Session,
|
||||
|
|
@ -115,22 +101,13 @@ pub fn lower_crate(sess: &Session,
|
|||
} else {
|
||||
Some("std")
|
||||
},
|
||||
sess: Some(sess),
|
||||
sess: sess,
|
||||
parent_def: None,
|
||||
resolver: resolver,
|
||||
}.lower_crate(krate)
|
||||
}
|
||||
|
||||
impl<'a> LoweringContext<'a> {
|
||||
pub fn testing_context(resolver: &'a mut Resolver) -> Self {
|
||||
LoweringContext {
|
||||
crate_root: None,
|
||||
sess: None,
|
||||
parent_def: None,
|
||||
resolver: resolver,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_crate(&mut self, c: &Crate) -> hir::Crate {
|
||||
struct ItemLowerer<'lcx, 'interner: 'lcx> {
|
||||
items: BTreeMap<NodeId, hir::Item>,
|
||||
|
|
@ -161,12 +138,11 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn next_id(&self) -> NodeId {
|
||||
self.sess.map(Session::next_node_id).unwrap_or(0)
|
||||
self.sess.next_node_id()
|
||||
}
|
||||
|
||||
fn diagnostic(&self) -> &errors::Handler {
|
||||
self.sess.map(Session::diagnostic)
|
||||
.unwrap_or_else(|| panic!("this lowerer cannot emit diagnostics"))
|
||||
self.sess.diagnostic()
|
||||
}
|
||||
|
||||
fn str_to_ident(&self, s: &'static str) -> Name {
|
||||
|
|
@ -177,9 +153,9 @@ impl<'a> LoweringContext<'a> {
|
|||
where F: FnOnce(&mut LoweringContext) -> T
|
||||
{
|
||||
let old_def = self.parent_def;
|
||||
self.parent_def = match self.resolver.definitions() {
|
||||
Some(defs) => Some(defs.opt_def_index(parent_id).unwrap()),
|
||||
None => old_def,
|
||||
self.parent_def = {
|
||||
let defs = self.resolver.definitions();
|
||||
Some(defs.opt_def_index(parent_id).unwrap())
|
||||
};
|
||||
|
||||
let result = f(self);
|
||||
|
|
@ -638,7 +614,10 @@ impl<'a> LoweringContext<'a> {
|
|||
let struct_def = self.lower_variant_data(struct_def);
|
||||
hir::ItemStruct(struct_def, self.lower_generics(generics))
|
||||
}
|
||||
ItemKind::Union(..) => panic!("`union` is not yet implemented"),
|
||||
ItemKind::Union(ref vdata, ref generics) => {
|
||||
let vdata = self.lower_variant_data(vdata);
|
||||
hir::ItemUnion(vdata, self.lower_generics(generics))
|
||||
}
|
||||
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
|
||||
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
|
||||
self.lower_trait_ref(trait_ref))
|
||||
|
|
@ -1716,9 +1695,10 @@ impl<'a> LoweringContext<'a> {
|
|||
let expr_path = hir::ExprPath(None, self.path_ident(span, id));
|
||||
let expr = self.expr(span, expr_path, ThinVec::new());
|
||||
|
||||
let def = self.resolver.definitions().map(|defs| {
|
||||
Def::Local(defs.local_def_id(binding), binding)
|
||||
}).unwrap_or(Def::Err);
|
||||
let def = {
|
||||
let defs = self.resolver.definitions();
|
||||
Def::Local(defs.local_def_id(binding))
|
||||
};
|
||||
self.resolver.record_resolution(expr.id, def);
|
||||
|
||||
expr
|
||||
|
|
@ -1866,11 +1846,12 @@ impl<'a> LoweringContext<'a> {
|
|||
let pat = self.pat(span, pat_ident);
|
||||
|
||||
let parent_def = self.parent_def;
|
||||
let def = self.resolver.definitions().map(|defs| {
|
||||
let def = {
|
||||
let defs = self.resolver.definitions();
|
||||
let def_path_data = DefPathData::Binding(name.as_str());
|
||||
let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data);
|
||||
Def::Local(DefId::local(def_index), pat.id)
|
||||
}).unwrap_or(Def::Err);
|
||||
Def::Local(DefId::local(def_index))
|
||||
};
|
||||
self.resolver.record_resolution(pat.id, def);
|
||||
|
||||
pat
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ pub struct NodeCollector<'ast> {
|
|||
pub map: Vec<MapEntry<'ast>>,
|
||||
/// The parent of this node
|
||||
pub parent_node: NodeId,
|
||||
/// If true, completely ignore nested items. We set this when loading
|
||||
/// HIR from metadata, since in that case we only want the HIR for
|
||||
/// one specific item (and not the ones nested inside of it).
|
||||
pub ignore_nested_items: bool
|
||||
}
|
||||
|
||||
impl<'ast> NodeCollector<'ast> {
|
||||
|
|
@ -35,6 +39,7 @@ impl<'ast> NodeCollector<'ast> {
|
|||
krate: krate,
|
||||
map: vec![],
|
||||
parent_node: CRATE_NODE_ID,
|
||||
ignore_nested_items: false
|
||||
};
|
||||
collector.insert_entry(CRATE_NODE_ID, RootCrate);
|
||||
|
||||
|
|
@ -52,6 +57,7 @@ impl<'ast> NodeCollector<'ast> {
|
|||
krate: krate,
|
||||
map: map,
|
||||
parent_node: parent_node,
|
||||
ignore_nested_items: true
|
||||
};
|
||||
|
||||
assert_eq!(parent_def_path.krate, parent_def_id.krate);
|
||||
|
|
@ -63,10 +69,10 @@ impl<'ast> NodeCollector<'ast> {
|
|||
fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
|
||||
debug!("ast_map: {:?} => {:?}", id, entry);
|
||||
let len = self.map.len();
|
||||
if id as usize >= len {
|
||||
self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
|
||||
if id.as_usize() >= len {
|
||||
self.map.extend(repeat(NotPresent).take(id.as_usize() - len + 1));
|
||||
}
|
||||
self.map[id as usize] = entry;
|
||||
self.map[id.as_usize()] = entry;
|
||||
}
|
||||
|
||||
fn insert(&mut self, id: NodeId, node: Node<'ast>) {
|
||||
|
|
@ -88,7 +94,9 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
|||
/// their outer items.
|
||||
fn visit_nested_item(&mut self, item: ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item);
|
||||
self.visit_item(self.krate.item(item.id))
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_item(self.krate.item(item.id))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'ast Item) {
|
||||
|
|
@ -109,7 +117,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
|||
this.insert(struct_def.id(), NodeStructCtor(struct_def));
|
||||
}
|
||||
}
|
||||
ItemTrait(_, _, ref bounds, _) => {
|
||||
ItemTrait(.., ref bounds, _) => {
|
||||
for b in bounds.iter() {
|
||||
if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
|
||||
this.insert(t.trait_ref.ref_id, NodeItem(i));
|
||||
|
|
|
|||
|
|
@ -285,15 +285,6 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
|
|||
|
||||
// We walk the HIR rather than the AST when reading items from metadata.
|
||||
impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
|
||||
/// Because we want to track parent items and so forth, enable
|
||||
/// deep walking so that we walk nested items in the context of
|
||||
/// their outer items.
|
||||
fn visit_nested_item(&mut self, item_id: hir::ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item_id);
|
||||
let item = self.hir_crate.unwrap().item(item_id.id);
|
||||
self.visit_item(item)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'ast hir::Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
|
||||
|
|
@ -302,9 +293,9 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
|
|||
let def_data = match i.node {
|
||||
hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
|
||||
DefPathData::Impl,
|
||||
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
|
||||
hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) |
|
||||
hir::ItemTy(..) =>
|
||||
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) |
|
||||
hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) |
|
||||
hir::ItemForeignMod(..) | hir::ItemTy(..) =>
|
||||
DefPathData::TypeNs(i.name.as_str()),
|
||||
hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
|
||||
DefPathData::ValueNs(i.name.as_str()),
|
||||
|
|
@ -331,7 +322,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
|
|||
});
|
||||
}
|
||||
}
|
||||
hir::ItemStruct(ref struct_def, _) => {
|
||||
hir::ItemStruct(ref struct_def, _) |
|
||||
hir::ItemUnion(ref struct_def, _) => {
|
||||
// If this is a tuple-like struct, register the constructor.
|
||||
if !struct_def.is_struct() {
|
||||
this.create_def(struct_def.id(),
|
||||
|
|
|
|||
|
|
@ -8,14 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::cstore::LOCAL_CRATE;
|
||||
use hir::def_id::{DefId, DefIndex};
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
|
||||
use hir::map::def_collector::DefCollector;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use std::fmt::Write;
|
||||
use std::hash::{Hash, Hasher, SipHasher};
|
||||
use syntax::{ast, visit};
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token::{self, InternedString};
|
||||
use ty::TyCtxt;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
|
|
@ -70,7 +69,7 @@ pub struct DefPath {
|
|||
pub data: Vec<DisambiguatedDefPathData>,
|
||||
|
||||
/// what krate root is this path relative to?
|
||||
pub krate: ast::CrateNum,
|
||||
pub krate: CrateNum,
|
||||
}
|
||||
|
||||
impl DefPath {
|
||||
|
|
@ -78,7 +77,7 @@ impl DefPath {
|
|||
self.krate == LOCAL_CRATE
|
||||
}
|
||||
|
||||
pub fn make<FN>(start_krate: ast::CrateNum,
|
||||
pub fn make<FN>(start_krate: CrateNum,
|
||||
start_index: DefIndex,
|
||||
mut get_key: FN) -> DefPath
|
||||
where FN: FnMut(DefIndex) -> DefKey
|
||||
|
|
@ -116,11 +115,7 @@ impl DefPath {
|
|||
pub fn to_string(&self, tcx: TyCtxt) -> String {
|
||||
let mut s = String::with_capacity(self.data.len() * 16);
|
||||
|
||||
if self.krate == LOCAL_CRATE {
|
||||
s.push_str(&tcx.crate_name(self.krate));
|
||||
} else {
|
||||
s.push_str(&tcx.sess.cstore.original_crate_name(self.krate));
|
||||
}
|
||||
s.push_str(&tcx.original_crate_name(self.krate));
|
||||
s.push_str("/");
|
||||
s.push_str(&tcx.crate_disambiguator(self.krate));
|
||||
|
||||
|
|
@ -142,7 +137,7 @@ impl DefPath {
|
|||
}
|
||||
|
||||
pub fn deterministic_hash_to<H: Hasher>(&self, tcx: TyCtxt, state: &mut H) {
|
||||
tcx.crate_name(self.krate).hash(state);
|
||||
tcx.original_crate_name(self.krate).hash(state);
|
||||
tcx.crate_disambiguator(self.krate).hash(state);
|
||||
self.data.hash(state);
|
||||
}
|
||||
|
|
@ -327,6 +322,30 @@ impl Definitions {
|
|||
}
|
||||
|
||||
impl DefPathData {
|
||||
pub fn get_opt_name(&self) -> Option<ast::Name> {
|
||||
use self::DefPathData::*;
|
||||
match *self {
|
||||
TypeNs(ref name) |
|
||||
ValueNs(ref name) |
|
||||
Module(ref name) |
|
||||
MacroDef(ref name) |
|
||||
TypeParam(ref name) |
|
||||
LifetimeDef(ref name) |
|
||||
EnumVariant(ref name) |
|
||||
Binding(ref name) |
|
||||
Field(ref name) => Some(token::intern(name)),
|
||||
|
||||
Impl |
|
||||
CrateRoot |
|
||||
InlinedRoot(_) |
|
||||
Misc |
|
||||
ClosureExpr |
|
||||
StructCtor |
|
||||
Initializer |
|
||||
ImplTrait => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_interned_str(&self) -> InternedString {
|
||||
use self::DefPathData::*;
|
||||
match *self {
|
||||
|
|
|
|||
|
|
@ -22,17 +22,15 @@ use middle::cstore::InlinedItem as II;
|
|||
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
|
||||
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
|
||||
use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID};
|
||||
use syntax::codemap::Spanned;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use hir::*;
|
||||
use hir::fold::Folder;
|
||||
use hir::print as pprust;
|
||||
|
||||
use arena::TypedArena;
|
||||
use std::cell::RefCell;
|
||||
use std::cmp;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
|
||||
|
|
@ -240,7 +238,7 @@ impl<'ast> Map<'ast> {
|
|||
let mut id = id0;
|
||||
if !self.is_inlined_node_id(id) {
|
||||
loop {
|
||||
match map[id as usize] {
|
||||
match map[id.as_usize()] {
|
||||
EntryItem(_, item) => {
|
||||
let def_id = self.local_def_id(item.id);
|
||||
// NB ^~~~~~~
|
||||
|
|
@ -295,7 +293,7 @@ impl<'ast> Map<'ast> {
|
|||
// reading from an inlined def-id is really a read out of
|
||||
// the metadata from which we loaded the item.
|
||||
loop {
|
||||
match map[id as usize] {
|
||||
match map[id.as_usize()] {
|
||||
EntryItem(p, _) |
|
||||
EntryForeignItem(p, _) |
|
||||
EntryTraitItem(p, _) |
|
||||
|
|
@ -373,7 +371,7 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
|
||||
fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
|
||||
self.map.borrow().get(id as usize).cloned()
|
||||
self.map.borrow().get(id.as_usize()).cloned()
|
||||
}
|
||||
|
||||
pub fn krate(&self) -> &'ast Crate {
|
||||
|
|
@ -456,8 +454,8 @@ impl<'ast> Map<'ast> {
|
|||
let mut id = start_id;
|
||||
loop {
|
||||
let parent_node = self.get_parent_node(id);
|
||||
if parent_node == 0 {
|
||||
return Ok(0);
|
||||
if parent_node == CRATE_NODE_ID {
|
||||
return Ok(CRATE_NODE_ID);
|
||||
}
|
||||
if parent_node == id {
|
||||
return Err(id);
|
||||
|
|
@ -582,22 +580,24 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData {
|
||||
pub fn expect_variant_data(&self, id: NodeId) -> &'ast VariantData {
|
||||
match self.find(id) {
|
||||
Some(NodeItem(i)) => {
|
||||
match i.node {
|
||||
ItemStruct(ref struct_def, _) => struct_def,
|
||||
_ => bug!("struct ID bound to non-struct")
|
||||
ItemStruct(ref struct_def, _) |
|
||||
ItemUnion(ref struct_def, _) => struct_def,
|
||||
_ => {
|
||||
bug!("struct ID bound to non-struct {}",
|
||||
self.node_to_string(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(NodeVariant(variant)) => {
|
||||
if variant.node.data.is_struct() {
|
||||
&variant.node.data
|
||||
} else {
|
||||
bug!("struct ID bound to enum variant that isn't struct-like")
|
||||
}
|
||||
Some(NodeStructCtor(data)) => data,
|
||||
Some(NodeVariant(variant)) => &variant.node.data,
|
||||
_ => {
|
||||
bug!("expected struct or variant, found {}",
|
||||
self.node_to_string(id));
|
||||
}
|
||||
_ => bug!("expected struct, found {}", self.node_to_string(id)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -680,7 +680,7 @@ impl<'ast> Map<'ast> {
|
|||
map: self,
|
||||
item_name: parts.last().unwrap(),
|
||||
in_which: &parts[..parts.len() - 1],
|
||||
idx: 0,
|
||||
idx: CRATE_NODE_ID,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -801,10 +801,10 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> {
|
|||
fn next(&mut self) -> Option<NodeId> {
|
||||
loop {
|
||||
let idx = self.idx;
|
||||
if idx as usize >= self.map.entry_count() {
|
||||
if idx.as_usize() >= self.map.entry_count() {
|
||||
return None;
|
||||
}
|
||||
self.idx += 1;
|
||||
self.idx = NodeId::from_u32(self.idx.as_u32() + 1);
|
||||
let name = match self.map.find_entry(idx) {
|
||||
Some(EntryItem(_, n)) => n.name(),
|
||||
Some(EntryForeignItem(_, n))=> n.name(),
|
||||
|
|
@ -832,57 +832,6 @@ impl Named for Variant_ { fn name(&self) -> Name { self.name } }
|
|||
impl Named for TraitItem { fn name(&self) -> Name { self.name } }
|
||||
impl Named for ImplItem { fn name(&self) -> Name { self.name } }
|
||||
|
||||
pub trait FoldOps {
|
||||
fn new_id(&self, id: NodeId) -> NodeId {
|
||||
id
|
||||
}
|
||||
fn new_def_id(&self, def_id: DefId) -> DefId {
|
||||
def_id
|
||||
}
|
||||
fn new_span(&self, span: Span) -> Span {
|
||||
span
|
||||
}
|
||||
}
|
||||
|
||||
/// A Folder that updates IDs and Span's according to fold_ops.
|
||||
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 {
|
||||
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 {
|
||||
self.fold_ops.new_span(span)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_crate<'ast>(forest: &'ast mut Forest,
|
||||
definitions: Definitions)
|
||||
-> Map<'ast> {
|
||||
|
|
@ -906,7 +855,7 @@ 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;
|
||||
let local_node_id_watermark = NodeId::new(map.len());
|
||||
let local_def_id_watermark = definitions.len();
|
||||
|
||||
Map {
|
||||
|
|
@ -921,34 +870,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
|
|||
|
||||
/// Used for items loaded from external crate that are being inlined into this
|
||||
/// crate.
|
||||
pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
|
||||
parent_def_path: DefPath,
|
||||
parent_def_id: DefId,
|
||||
ii: InlinedItem,
|
||||
fold_ops: F)
|
||||
-> &'ast InlinedItem {
|
||||
let mut fld = IdAndSpanUpdater::new(fold_ops);
|
||||
let ii = match ii {
|
||||
II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d),
|
||||
i.map(|i| fld.fold_item(i))),
|
||||
II::TraitItem(d, ti) => {
|
||||
II::TraitItem(fld.fold_ops.new_def_id(d),
|
||||
ti.map(|ti| fld.fold_trait_item(ti)))
|
||||
}
|
||||
II::ImplItem(d, ii) => {
|
||||
II::ImplItem(fld.fold_ops.new_def_id(d),
|
||||
ii.map(|ii| fld.fold_impl_item(ii)))
|
||||
}
|
||||
};
|
||||
pub fn map_decoded_item<'ast>(map: &Map<'ast>,
|
||||
parent_def_path: DefPath,
|
||||
parent_def_id: DefId,
|
||||
ii: InlinedItem,
|
||||
ii_parent_id: NodeId)
|
||||
-> &'ast InlinedItem {
|
||||
let _ignore = map.forest.dep_graph.in_ignore();
|
||||
|
||||
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,
|
||||
|
|
@ -1030,6 +960,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
|||
ItemTy(..) => "ty",
|
||||
ItemEnum(..) => "enum",
|
||||
ItemStruct(..) => "struct",
|
||||
ItemUnion(..) => "union",
|
||||
ItemTrait(..) => "trait",
|
||||
ItemImpl(..) => "impl",
|
||||
ItemDefaultImpl(..) => "default impl",
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ macro_rules! hir_vec {
|
|||
pub mod check_attr;
|
||||
pub mod def;
|
||||
pub mod def_id;
|
||||
pub mod fold;
|
||||
pub mod intravisit;
|
||||
pub mod lowering;
|
||||
pub mod map;
|
||||
|
|
@ -469,7 +468,7 @@ impl Pat {
|
|||
}
|
||||
|
||||
match self.node {
|
||||
PatKind::Binding(_, _, Some(ref p)) => p.walk_(it),
|
||||
PatKind::Binding(.., Some(ref p)) => p.walk_(it),
|
||||
PatKind::Struct(_, ref fields, _) => {
|
||||
fields.iter().all(|field| field.node.pat.walk_(it))
|
||||
}
|
||||
|
|
@ -486,7 +485,7 @@ impl Pat {
|
|||
}
|
||||
PatKind::Wild |
|
||||
PatKind::Lit(_) |
|
||||
PatKind::Range(_, _) |
|
||||
PatKind::Range(..) |
|
||||
PatKind::Binding(..) |
|
||||
PatKind::Path(..) => {
|
||||
true
|
||||
|
|
@ -1483,6 +1482,8 @@ pub enum Item_ {
|
|||
ItemEnum(EnumDef, Generics),
|
||||
/// A struct definition, e.g. `struct Foo<A> {x: A}`
|
||||
ItemStruct(VariantData, Generics),
|
||||
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
|
||||
ItemUnion(VariantData, Generics),
|
||||
/// Represents a Trait Declaration
|
||||
ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
|
||||
|
||||
|
|
@ -1512,6 +1513,7 @@ impl Item_ {
|
|||
ItemTy(..) => "type alias",
|
||||
ItemEnum(..) => "enum",
|
||||
ItemStruct(..) => "struct",
|
||||
ItemUnion(..) => "union",
|
||||
ItemTrait(..) => "trait",
|
||||
ItemImpl(..) |
|
||||
ItemDefaultImpl(..) => "item",
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
|
|||
|
||||
pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
|
||||
match pat.node {
|
||||
PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true,
|
||||
PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(Some(..), _) => true,
|
||||
PatKind::TupleStruct(..) |
|
||||
PatKind::Path(..) |
|
||||
PatKind::Struct(..) => {
|
||||
|
|
@ -62,7 +62,7 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
|
|||
_ => false
|
||||
}
|
||||
}
|
||||
PatKind::Vec(_, _, _) => true,
|
||||
PatKind::Vec(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +174,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
|
|||
PatKind::Path(..) |
|
||||
PatKind::Struct(..) => {
|
||||
match dm.get(&p.id) {
|
||||
Some(&PathResolution { base_def: Def::Variant(_, id), .. }) => {
|
||||
Some(&PathResolution { base_def: Def::Variant(id), .. }) => {
|
||||
variants.push(id);
|
||||
}
|
||||
_ => ()
|
||||
|
|
|
|||
|
|
@ -752,7 +752,10 @@ impl<'a> State<'a> {
|
|||
self.head(&visibility_qualified(&item.vis, "struct"))?;
|
||||
self.print_struct(struct_def, generics, item.name, item.span, true)?;
|
||||
}
|
||||
|
||||
hir::ItemUnion(ref struct_def, ref generics) => {
|
||||
self.head(&visibility_qualified(&item.vis, "union"))?;
|
||||
self.print_struct(struct_def, generics, item.name, item.span, true)?;
|
||||
}
|
||||
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
|
||||
self.head("")?;
|
||||
self.print_visibility(&item.vis)?;
|
||||
|
|
@ -1753,9 +1756,9 @@ impl<'a> State<'a> {
|
|||
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
|
||||
}
|
||||
} else {
|
||||
try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
|
||||
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
|
||||
}
|
||||
try!(self.pclose());
|
||||
self.pclose()?;
|
||||
}
|
||||
PatKind::Path(None, ref path) => {
|
||||
self.print_path(path, true, 0)?;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
match item.node {
|
||||
hir::ItemImpl(..) => "impl",
|
||||
hir::ItemStruct(..) => "struct",
|
||||
hir::ItemUnion(..) => "union",
|
||||
hir::ItemEnum(..) => "enum",
|
||||
hir::ItemTrait(..) => "trait",
|
||||
hir::ItemFn(..) => "function body",
|
||||
|
|
@ -139,9 +140,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
Some(ast_map::NodeExpr(expr)) => match expr.node {
|
||||
hir::ExprCall(..) => "call",
|
||||
hir::ExprMethodCall(..) => "method call",
|
||||
hir::ExprMatch(_, _, hir::MatchSource::IfLetDesugar { .. }) => "if let",
|
||||
hir::ExprMatch(_, _, hir::MatchSource::WhileLetDesugar) => "while let",
|
||||
hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) => "for",
|
||||
hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
|
||||
hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let",
|
||||
hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for",
|
||||
hir::ExprMatch(..) => "match",
|
||||
_ => "expression",
|
||||
},
|
||||
|
|
@ -487,10 +488,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// if they are both "path types", there's a chance of ambiguity
|
||||
// due to different versions of the same crate
|
||||
match (&exp_found.expected.sty, &exp_found.found.sty) {
|
||||
(&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) |
|
||||
(&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
|
||||
(&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
|
||||
(&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => {
|
||||
(&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => {
|
||||
report_path_match(err, exp_adt.did, found_adt.did);
|
||||
},
|
||||
_ => ()
|
||||
|
|
@ -549,7 +547,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
if !is_simple_error {
|
||||
diag.note_expected_found(&"type", &expected, &found);
|
||||
if expected == found {
|
||||
if let &TypeError::Sorts(ref values) = terr {
|
||||
diag.note_expected_found_extra(
|
||||
&"type", &expected, &found,
|
||||
&format!(" ({})", values.expected.sort_string(self.tcx)),
|
||||
&format!(" ({})", values.found.sort_string(self.tcx)));
|
||||
} else {
|
||||
diag.note_expected_found(&"type", &expected, &found);
|
||||
}
|
||||
} else {
|
||||
diag.note_expected_found(&"type", &expected, &found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1370,7 +1379,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
hir::TyPath(ref maybe_qself, ref path) => {
|
||||
match self.tcx.expect_def(cur_ty.id) {
|
||||
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
|
||||
Def::Enum(did) | Def::TyAlias(did) |
|
||||
Def::Struct(did) | Def::Union(did) => {
|
||||
let generics = self.tcx.lookup_generics(did);
|
||||
|
||||
let expected =
|
||||
|
|
@ -1785,7 +1795,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|||
let method_id_opt = match tcx.map.find(parent) {
|
||||
Some(node) => match node {
|
||||
ast_map::NodeItem(item) => match item.node {
|
||||
hir::ItemFn(_, _, _, _, ref gen, _) => {
|
||||
hir::ItemFn(.., ref gen, _) => {
|
||||
taken.extend_from_slice(&gen.lifetimes);
|
||||
None
|
||||
},
|
||||
|
|
@ -1809,7 +1819,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|||
if let Some(node) = tcx.map.find(parent) {
|
||||
match node {
|
||||
ast_map::NodeItem(item) => match item.node {
|
||||
hir::ItemImpl(_, _, ref gen, _, _, _) => {
|
||||
hir::ItemImpl(_, _, ref gen, ..) => {
|
||||
taken.extend_from_slice(&gen.lifetimes);
|
||||
}
|
||||
_ => ()
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
|
|||
ty::TyInt(..) |
|
||||
ty::TyUint(..) |
|
||||
ty::TyFloat(..) |
|
||||
ty::TyEnum(..) |
|
||||
ty::TyAdt(..) |
|
||||
ty::TyBox(..) |
|
||||
ty::TyStr |
|
||||
ty::TyError |
|
||||
|
|
@ -167,7 +167,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
|
|||
ty::TyFnDef(..) |
|
||||
ty::TyFnPtr(_) |
|
||||
ty::TyTrait(..) |
|
||||
ty::TyStruct(..) |
|
||||
ty::TyClosure(..) |
|
||||
ty::TyNever |
|
||||
ty::TyTuple(..) |
|
||||
|
|
|
|||
|
|
@ -130,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(a_is_expected).relate(&a_match, &b_match));
|
||||
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
|
||||
|
|
@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
warnings.extend(
|
||||
match self.region_vars.var_origin(vid) {
|
||||
LateBoundRegion(_,
|
||||
ty::BrNamed(_, _, wc),
|
||||
ty::BrNamed(.., wc),
|
||||
_) => Some(wc),
|
||||
_ => None,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
// avoid reporting the same error twice.
|
||||
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
|
||||
|
||||
// This is a temporary field used for toggling on normalization in the inference context,
|
||||
// as we move towards the approach described here:
|
||||
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
|
||||
// At a point sometime in the future normalization will be done by the typing context
|
||||
// directly.
|
||||
normalize: bool,
|
||||
|
||||
// Sadly, the behavior of projection varies a bit depending on the
|
||||
// stage of compilation. The specifics are given in the
|
||||
// documentation for `Reveal`.
|
||||
|
|
@ -232,7 +225,7 @@ impl TypeOrigin {
|
|||
&TypeOrigin::RelateOutputImplTypes(_) |
|
||||
&TypeOrigin::ExprAssignable(_) => "mismatched types",
|
||||
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
|
||||
&TypeOrigin::MatchExpressionArm(_, _, source) => match source {
|
||||
&TypeOrigin::MatchExpressionArm(.., source) => match source {
|
||||
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
|
||||
_ => "match arms have incompatible types",
|
||||
},
|
||||
|
|
@ -255,7 +248,7 @@ impl TypeOrigin {
|
|||
&TypeOrigin::RelateOutputImplTypes(_) => {
|
||||
"trait type parameters matches those specified on the impl"
|
||||
}
|
||||
&TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
|
||||
&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",
|
||||
|
|
@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
tables: Option<RefCell<ty::Tables<'tcx>>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'gcx>>,
|
||||
projection_mode: Reveal,
|
||||
normalize: bool
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
|
|
@ -473,19 +465,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
|||
tables: tables.map(RefCell::new),
|
||||
param_env: param_env,
|
||||
projection_mode: projection_mode,
|
||||
normalize: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
|
||||
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
InferCtxtBuilder {
|
||||
global_tcx: self,
|
||||
arenas: ty::CtxtArenas::new(),
|
||||
tables: None,
|
||||
param_env: None,
|
||||
projection_mode: projection_mode,
|
||||
normalize: false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -506,7 +485,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
|||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
||||
reported_trait_errors: RefCell::new(FnvHashSet()),
|
||||
normalize: false,
|
||||
projection_mode: Reveal::NotSpecializable,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: self.sess.err_count(),
|
||||
|
|
@ -525,7 +503,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
|||
ref tables,
|
||||
ref mut param_env,
|
||||
projection_mode,
|
||||
normalize
|
||||
} = *self;
|
||||
let tables = if let Some(ref tables) = *tables {
|
||||
InferTables::Local(tables)
|
||||
|
|
@ -547,7 +524,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
|||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
reported_trait_errors: RefCell::new(FnvHashSet()),
|
||||
normalize: normalize,
|
||||
projection_mode: projection_mode,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: tcx.sess.err_count(),
|
||||
|
|
@ -683,6 +659,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
|
||||
}
|
||||
|
||||
/// Finishes processes any obligations that remain in the
|
||||
/// fulfillment context, and then returns the result with all type
|
||||
/// variables removed and regions erased. Because this is intended
|
||||
/// for use after type-check has completed, if any errors occur,
|
||||
/// it will panic. It is used during normalization and other cases
|
||||
/// where processing the obligations in `fulfill_cx` may cause
|
||||
/// type inference variables that appear in `result` to be
|
||||
/// unified, and hence we need to process those obligations to get
|
||||
/// the complete picture of the type.
|
||||
pub fn drain_fulfillment_cx_or_panic<T>(&self,
|
||||
span: Span,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
|
|
@ -692,45 +677,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
{
|
||||
debug!("drain_fulfillment_cx_or_panic()");
|
||||
|
||||
let when = "resolving bounds after type-checking";
|
||||
let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
|
||||
Ok(v) => v,
|
||||
Err(errors) => {
|
||||
span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
|
||||
}
|
||||
};
|
||||
|
||||
match self.tcx.lift_to_global(&v) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finishes processes any obligations that remain in the fulfillment
|
||||
/// context, and then "freshens" and returns `result`. This is
|
||||
/// primarily used during normalization and other cases where
|
||||
/// processing the obligations in `fulfill_cx` may cause type
|
||||
/// inference variables that appear in `result` to be unified, and
|
||||
/// hence we need to process those obligations to get the complete
|
||||
/// picture of the type.
|
||||
pub fn drain_fulfillment_cx<T>(&self,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> Result<T,Vec<traits::FulfillmentError<'tcx>>>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("drain_fulfillment_cx(result={:?})",
|
||||
result);
|
||||
|
||||
// In principle, we only need to do this so long as `result`
|
||||
// contains unbound type parameters. It could be a slight
|
||||
// optimization to stop iterating early.
|
||||
fulfill_cx.select_all_or_error(self)?;
|
||||
match fulfill_cx.select_all_or_error(self) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
|
||||
errors);
|
||||
}
|
||||
}
|
||||
|
||||
let result = self.resolve_type_vars_if_possible(result);
|
||||
Ok(self.tcx.erase_regions(&result))
|
||||
let result = self.tcx.erase_regions(&result);
|
||||
|
||||
match self.tcx.lift_to_global(&result) {
|
||||
Some(result) => result,
|
||||
None => {
|
||||
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn projection_mode(&self) -> Reveal {
|
||||
|
|
@ -864,6 +830,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
// Clear the "obligations in snapshot" flag, invoke the closure,
|
||||
// then restore the flag to its original value. This flag is a
|
||||
// debugging measure designed to detect cases where we start a
|
||||
// snapshot, create type variables, register obligations involving
|
||||
// those type variables in the fulfillment cx, and then have to
|
||||
// unroll the snapshot, leaving "dangling type variables" behind.
|
||||
// In such cases, the flag will be set by the fulfillment cx, and
|
||||
// an assertion will fail when rolling the snapshot back. Very
|
||||
// useful, much better than grovelling through megabytes of
|
||||
// RUST_LOG output.
|
||||
//
|
||||
// HOWEVER, in some cases the flag is wrong. In particular, we
|
||||
// sometimes create a "mini-fulfilment-cx" in which we enroll
|
||||
// obligations. As long as this fulfillment cx is fully drained
|
||||
// before we return, this is not a problem, as there won't be any
|
||||
// escaping obligations in the main cx. In those cases, you can
|
||||
// use this function.
|
||||
pub fn save_and_restore_obligations_in_snapshot_flag<F, R>(&self, func: F) -> R
|
||||
where F: FnOnce(&Self) -> R
|
||||
{
|
||||
let flag = self.obligations_in_snapshot.get();
|
||||
self.obligations_in_snapshot.set(false);
|
||||
let result = func(self);
|
||||
self.obligations_in_snapshot.set(flag);
|
||||
result
|
||||
}
|
||||
|
||||
fn start_snapshot(&self) -> CombinedSnapshot {
|
||||
debug!("start_snapshot()");
|
||||
|
||||
|
|
@ -1702,17 +1695,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
let closure_ty = self.tcx.closure_type(def_id, substs);
|
||||
if self.normalize {
|
||||
let closure_ty = self.tcx.erase_regions(&closure_ty);
|
||||
|
||||
if !closure_ty.has_projection_types() {
|
||||
return closure_ty;
|
||||
}
|
||||
|
||||
self.normalize_projections_in(&closure_ty)
|
||||
} else {
|
||||
closure_ty
|
||||
}
|
||||
closure_ty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1756,7 +1739,7 @@ impl TypeOrigin {
|
|||
TypeOrigin::ExprAssignable(span) => span,
|
||||
TypeOrigin::Misc(span) => span,
|
||||
TypeOrigin::RelateOutputImplTypes(span) => span,
|
||||
TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
|
||||
TypeOrigin::MatchExpressionArm(match_span, ..) => match_span,
|
||||
TypeOrigin::IfExpression(span) => span,
|
||||
TypeOrigin::IfExpressionWithNoElse(span) => span,
|
||||
TypeOrigin::RangeExpression(span) => span,
|
||||
|
|
@ -1809,7 +1792,7 @@ impl RegionVariableOrigin {
|
|||
Autoref(a) => a,
|
||||
Coercion(a) => a,
|
||||
EarlyBoundRegion(a, _) => a,
|
||||
LateBoundRegion(a, _, _) => a,
|
||||
LateBoundRegion(a, ..) => a,
|
||||
BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
|
||||
UpvarRegion(_, a) => a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,8 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
let requested_node: Option<ast::NodeId> = env::var("RUST_REGION_GRAPH_NODE")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok());
|
||||
let requested_node = env::var("RUST_REGION_GRAPH_NODE")
|
||||
.ok().and_then(|s| s.parse().map(ast::NodeId::new).ok());
|
||||
|
||||
if requested_node.is_some() && requested_node != Some(subject_node) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
|
|||
undo_entry: &UndoLogEntry<'tcx>)
|
||||
-> bool {
|
||||
match undo_entry {
|
||||
&AddConstraint(ConstrainVarSubVar(_, _)) =>
|
||||
&AddConstraint(ConstrainVarSubVar(..)) =>
|
||||
false,
|
||||
&AddConstraint(ConstrainRegSubVar(a, _)) =>
|
||||
skols.contains(&a),
|
||||
|
|
@ -613,7 +613,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
|
|||
skols.contains(&b),
|
||||
&AddConstraint(ConstrainRegSubReg(a, b)) =>
|
||||
skols.contains(&a) || skols.contains(&b),
|
||||
&AddGiven(_, _) =>
|
||||
&AddGiven(..) =>
|
||||
false,
|
||||
&AddVerify(_) =>
|
||||
false,
|
||||
|
|
@ -1372,7 +1372,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
|
|||
(&ReFree(..), &ReFree(..)) => Equal,
|
||||
(&ReFree(..), _) => Less,
|
||||
(_, &ReFree(..)) => Greater,
|
||||
(_, _) => Equal,
|
||||
(..) => Equal,
|
||||
}
|
||||
}
|
||||
lower_bounds.sort_by(|a, b| free_regions_first(a, b));
|
||||
|
|
|
|||
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