Merge pull request #5 from rust-lang/master
update from origin 2020-06-19
This commit is contained in:
commit
791ccccddc
301 changed files with 3922 additions and 1889 deletions
13
Cargo.toml
13
Cargo.toml
|
|
@ -42,6 +42,19 @@ debug-assertions = false
|
|||
debug = false
|
||||
debug-assertions = false
|
||||
|
||||
[profile.release.package.compiler_builtins]
|
||||
# For compiler-builtins we always use a high number of codegen units.
|
||||
# The goal here is to place every single intrinsic into its own object
|
||||
# file to avoid symbol clashes with the system libgcc if possible. Note
|
||||
# that this number doesn't actually produce this many object files, we
|
||||
# just don't create more than this number of object files.
|
||||
#
|
||||
# It's a bit of a bummer that we have to pass this here, unfortunately.
|
||||
# Ideally this would be specified through an env var to Cargo so Cargo
|
||||
# knows how many CGUs are for this specific crate, but for now
|
||||
# per-crate configuration isn't specifiable in the environment.
|
||||
codegen-units = 10000
|
||||
|
||||
# We want the RLS to use the version of Cargo that we've got vendored in this
|
||||
# repository to ensure that the same exact version of Cargo is used by both the
|
||||
# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository
|
||||
|
|
|
|||
|
|
@ -209,7 +209,8 @@
|
|||
# Build the sanitizer runtimes
|
||||
#sanitizers = false
|
||||
|
||||
# Build the profiler runtime
|
||||
# Build the profiler runtime (required when compiling with options that depend
|
||||
# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
|
||||
#profiler = false
|
||||
|
||||
# Indicates whether the native libraries linked into Cargo will be statically
|
||||
|
|
|
|||
|
|
@ -894,7 +894,7 @@ def bootstrap(help_triggered):
|
|||
build.clean = args.clean
|
||||
|
||||
try:
|
||||
toml_path = args.config or 'config.toml'
|
||||
toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config or 'config.toml'
|
||||
if not os.path.exists(toml_path):
|
||||
toml_path = os.path.join(build.rust_root, toml_path)
|
||||
|
||||
|
|
@ -947,6 +947,7 @@ def bootstrap(help_triggered):
|
|||
env["SRC"] = build.rust_root
|
||||
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
|
||||
env["BOOTSTRAP_PYTHON"] = sys.executable
|
||||
env["BOOTSTRAP_CONFIG"] = toml_path
|
||||
env["BUILD_DIR"] = build.build_dir
|
||||
env["RUSTC_BOOTSTRAP"] = '1'
|
||||
env["CARGO"] = build.cargo()
|
||||
|
|
|
|||
|
|
@ -99,9 +99,21 @@ struct StepDescription {
|
|||
name: &'static str,
|
||||
}
|
||||
|
||||
/// Collection of paths used to match a task rule.
|
||||
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub enum PathSet {
|
||||
/// A collection of individual paths.
|
||||
///
|
||||
/// These are generally matched as a path suffix. For example, a
|
||||
/// command-line value of `libstd` will match if `src/libstd` is in the
|
||||
/// set.
|
||||
Set(BTreeSet<PathBuf>),
|
||||
/// A "suite" of paths.
|
||||
///
|
||||
/// These can match as a path suffix (like `Set`), or as a prefix. For
|
||||
/// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs`
|
||||
/// will match `src/test/ui`. A command-line value of `ui` would also
|
||||
/// match `src/test/ui`.
|
||||
Suite(PathBuf),
|
||||
}
|
||||
|
||||
|
|
@ -251,21 +263,33 @@ impl<'a> ShouldRun<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
// Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
|
||||
// ever be used, but as we transition to having all rules properly handle passing krate(...) by
|
||||
// actually doing something different for every crate passed.
|
||||
/// Indicates it should run if the command-line selects the given crate or
|
||||
/// any of its (local) dependencies.
|
||||
///
|
||||
/// Compared to `krate`, this treats the dependencies as aliases for the
|
||||
/// same job. Generally it is preferred to use `krate`, and treat each
|
||||
/// individual path separately. For example `./x.py test src/liballoc`
|
||||
/// (which uses `krate`) will test just `liballoc`. However, `./x.py check
|
||||
/// src/liballoc` (which uses `all_krates`) will check all of `libtest`.
|
||||
/// `all_krates` should probably be removed at some point.
|
||||
pub fn all_krates(mut self, name: &str) -> Self {
|
||||
let mut set = BTreeSet::new();
|
||||
for krate in self.builder.in_tree_crates(name) {
|
||||
set.insert(PathBuf::from(&krate.path));
|
||||
let path = krate.local_path(self.builder);
|
||||
set.insert(path);
|
||||
}
|
||||
self.paths.insert(PathSet::Set(set));
|
||||
self
|
||||
}
|
||||
|
||||
/// Indicates it should run if the command-line selects the given crate or
|
||||
/// any of its (local) dependencies.
|
||||
///
|
||||
/// `make_run` will be called separately for each matching command-line path.
|
||||
pub fn krate(mut self, name: &str) -> Self {
|
||||
for krate in self.builder.in_tree_crates(name) {
|
||||
self.paths.insert(PathSet::one(&krate.path));
|
||||
let path = krate.local_path(self.builder);
|
||||
self.paths.insert(PathSet::one(path));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
|
@ -488,13 +512,19 @@ impl<'a> Builder<'a> {
|
|||
should_run = (desc.should_run)(should_run);
|
||||
}
|
||||
let mut help = String::from("Available paths:\n");
|
||||
let mut add_path = |path: &Path| {
|
||||
help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display()));
|
||||
};
|
||||
for pathset in should_run.paths {
|
||||
if let PathSet::Set(set) = pathset {
|
||||
set.iter().for_each(|path| {
|
||||
help.push_str(
|
||||
format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(),
|
||||
)
|
||||
})
|
||||
match pathset {
|
||||
PathSet::Set(set) => {
|
||||
for path in set {
|
||||
add_path(&path);
|
||||
}
|
||||
}
|
||||
PathSet::Suite(path) => {
|
||||
add_path(&path.join("..."));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(help)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::builder::Cargo;
|
|||
use crate::dist;
|
||||
use crate::native;
|
||||
use crate::util::{exe, is_dylib, symlink_dir};
|
||||
use crate::{Compiler, GitRepo, Mode};
|
||||
use crate::{Compiler, DependencyType, GitRepo, Mode};
|
||||
|
||||
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
|
||||
use crate::cache::{Interned, INTERNER};
|
||||
|
|
@ -74,6 +74,7 @@ impl Step for Std {
|
|||
// Even if we're not building std this stage, the new sysroot must
|
||||
// still contain the third party objects needed by various targets.
|
||||
copy_third_party_objects(builder, &compiler, target);
|
||||
copy_self_contained_objects(builder, &compiler, target);
|
||||
|
||||
builder.ensure(StdLink {
|
||||
compiler: compiler_to_use,
|
||||
|
|
@ -83,7 +84,8 @@ impl Step for Std {
|
|||
return;
|
||||
}
|
||||
|
||||
target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
|
||||
target_deps.extend(copy_third_party_objects(builder, &compiler, target));
|
||||
target_deps.extend(copy_self_contained_objects(builder, &compiler, target));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
|
||||
std_cargo(builder, target, compiler.stage, &mut cargo);
|
||||
|
|
@ -109,21 +111,76 @@ impl Step for Std {
|
|||
}
|
||||
}
|
||||
|
||||
fn copy_and_stamp(
|
||||
builder: &Builder<'_>,
|
||||
libdir: &Path,
|
||||
sourcedir: &Path,
|
||||
name: &str,
|
||||
target_deps: &mut Vec<(PathBuf, DependencyType)>,
|
||||
dependency_type: DependencyType,
|
||||
) {
|
||||
let target = libdir.join(name);
|
||||
builder.copy(&sourcedir.join(name), &target);
|
||||
|
||||
target_deps.push((target, dependency_type));
|
||||
}
|
||||
|
||||
/// Copies third party objects needed by various targets.
|
||||
fn copy_third_party_objects(
|
||||
builder: &Builder<'_>,
|
||||
compiler: &Compiler,
|
||||
target: Interned<String>,
|
||||
) -> Vec<PathBuf> {
|
||||
) -> Vec<(PathBuf, DependencyType)> {
|
||||
let libdir = builder.sysroot_libdir(*compiler, target);
|
||||
|
||||
let mut target_deps = vec![];
|
||||
|
||||
let mut copy_and_stamp = |sourcedir: &Path, name: &str| {
|
||||
let target = libdir.join(name);
|
||||
builder.copy(&sourcedir.join(name), &target);
|
||||
target_deps.push(target);
|
||||
// Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx.
|
||||
//
|
||||
// This target needs to be linked to Fortanix's port of llvm's libunwind.
|
||||
// libunwind requires support for rwlock and printing to stderr,
|
||||
// which is provided by std for this target.
|
||||
if target == "x86_64-fortanix-unknown-sgx" {
|
||||
let src_path_env = "X86_FORTANIX_SGX_LIBS";
|
||||
let src =
|
||||
env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env));
|
||||
copy_and_stamp(
|
||||
builder,
|
||||
&*libdir,
|
||||
Path::new(&src),
|
||||
"libunwind.a",
|
||||
&mut target_deps,
|
||||
DependencyType::Target,
|
||||
);
|
||||
}
|
||||
|
||||
if builder.config.sanitizers && compiler.stage != 0 {
|
||||
// The sanitizers are only copied in stage1 or above,
|
||||
// to avoid creating dependency on LLVM.
|
||||
target_deps.extend(
|
||||
copy_sanitizers(builder, &compiler, target)
|
||||
.into_iter()
|
||||
.map(|d| (d, DependencyType::Target)),
|
||||
);
|
||||
}
|
||||
|
||||
target_deps
|
||||
}
|
||||
|
||||
/// Copies third party objects needed by various targets for self-contained linkage.
|
||||
fn copy_self_contained_objects(
|
||||
builder: &Builder<'_>,
|
||||
compiler: &Compiler,
|
||||
target: Interned<String>,
|
||||
) -> Vec<(PathBuf, DependencyType)> {
|
||||
// cfg(bootstrap)
|
||||
// Remove when upgrading bootstrap compiler.
|
||||
let libdir_self_contained = if compiler.stage == 0 {
|
||||
builder.sysroot_libdir(*compiler, target).to_path_buf()
|
||||
} else {
|
||||
builder.sysroot_libdir(*compiler, target).join("self-contained")
|
||||
};
|
||||
t!(fs::create_dir_all(&libdir_self_contained));
|
||||
let mut target_deps = vec![];
|
||||
|
||||
// Copies the CRT objects.
|
||||
//
|
||||
|
|
@ -135,29 +192,32 @@ fn copy_third_party_objects(
|
|||
if target.contains("musl") {
|
||||
let srcdir = builder.musl_root(target).unwrap().join("lib");
|
||||
for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
|
||||
copy_and_stamp(&srcdir, obj);
|
||||
copy_and_stamp(
|
||||
builder,
|
||||
&libdir_self_contained,
|
||||
&srcdir,
|
||||
obj,
|
||||
&mut target_deps,
|
||||
DependencyType::TargetSelfContained,
|
||||
);
|
||||
}
|
||||
} else if target.ends_with("-wasi") {
|
||||
let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi");
|
||||
copy_and_stamp(&srcdir, "crt1.o");
|
||||
}
|
||||
|
||||
// Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx.
|
||||
//
|
||||
// This target needs to be linked to Fortanix's port of llvm's libunwind.
|
||||
// libunwind requires support for rwlock and printing to stderr,
|
||||
// which is provided by std for this target.
|
||||
if target == "x86_64-fortanix-unknown-sgx" {
|
||||
let src_path_env = "X86_FORTANIX_SGX_LIBS";
|
||||
let src =
|
||||
env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env));
|
||||
copy_and_stamp(Path::new(&src), "libunwind.a");
|
||||
}
|
||||
|
||||
if builder.config.sanitizers && compiler.stage != 0 {
|
||||
// The sanitizers are only copied in stage1 or above,
|
||||
// to avoid creating dependency on LLVM.
|
||||
target_deps.extend(copy_sanitizers(builder, &compiler, target));
|
||||
copy_and_stamp(
|
||||
builder,
|
||||
&libdir_self_contained,
|
||||
&srcdir,
|
||||
"crt1.o",
|
||||
&mut target_deps,
|
||||
DependencyType::TargetSelfContained,
|
||||
);
|
||||
} else if target.contains("windows-gnu") {
|
||||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
let src = compiler_file(builder, builder.cc(target), target, obj);
|
||||
let target = libdir_self_contained.join(obj);
|
||||
builder.copy(&src, &target);
|
||||
target_deps.push((target, DependencyType::TargetSelfContained));
|
||||
}
|
||||
}
|
||||
|
||||
target_deps
|
||||
|
|
@ -335,7 +395,7 @@ pub struct StartupObjects {
|
|||
}
|
||||
|
||||
impl Step for StartupObjects {
|
||||
type Output = Vec<PathBuf>;
|
||||
type Output = Vec<(PathBuf, DependencyType)>;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/rtstartup")
|
||||
|
|
@ -354,7 +414,7 @@ impl Step for StartupObjects {
|
|||
/// They don't require any library support as they're just plain old object
|
||||
/// files, so we just use the nightly snapshot compiler to always build them (as
|
||||
/// no other compilers are guaranteed to be available).
|
||||
fn run(self, builder: &Builder<'_>) -> Vec<PathBuf> {
|
||||
fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
|
||||
let for_compiler = self.compiler;
|
||||
let target = self.target;
|
||||
if !target.contains("windows-gnu") {
|
||||
|
|
@ -388,14 +448,7 @@ impl Step for StartupObjects {
|
|||
|
||||
let target = sysroot_dir.join((*file).to_string() + ".o");
|
||||
builder.copy(dst_file, &target);
|
||||
target_deps.push(target);
|
||||
}
|
||||
|
||||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
let src = compiler_file(builder, builder.cc(target), target, obj);
|
||||
let target = sysroot_dir.join(obj);
|
||||
builder.copy(&src, &target);
|
||||
target_deps.push(target);
|
||||
target_deps.push((target, DependencyType::Target));
|
||||
}
|
||||
|
||||
target_deps
|
||||
|
|
@ -808,14 +861,17 @@ pub fn add_to_sysroot(
|
|||
sysroot_host_dst: &Path,
|
||||
stamp: &Path,
|
||||
) {
|
||||
let self_contained_dst = &sysroot_dst.join("self-contained");
|
||||
t!(fs::create_dir_all(&sysroot_dst));
|
||||
t!(fs::create_dir_all(&sysroot_host_dst));
|
||||
for (path, host) in builder.read_stamp_file(stamp) {
|
||||
if host {
|
||||
builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap()));
|
||||
} else {
|
||||
builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
|
||||
}
|
||||
t!(fs::create_dir_all(&self_contained_dst));
|
||||
for (path, dependency_type) in builder.read_stamp_file(stamp) {
|
||||
let dst = match dependency_type {
|
||||
DependencyType::Host => sysroot_host_dst,
|
||||
DependencyType::Target => sysroot_dst,
|
||||
DependencyType::TargetSelfContained => self_contained_dst,
|
||||
};
|
||||
builder.copy(&path, &dst.join(path.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -824,7 +880,7 @@ pub fn run_cargo(
|
|||
cargo: Cargo,
|
||||
tail_args: Vec<String>,
|
||||
stamp: &Path,
|
||||
additional_target_deps: Vec<PathBuf>,
|
||||
additional_target_deps: Vec<(PathBuf, DependencyType)>,
|
||||
is_check: bool,
|
||||
) -> Vec<PathBuf> {
|
||||
if builder.config.dry_run {
|
||||
|
|
@ -875,7 +931,7 @@ pub fn run_cargo(
|
|||
if filename.starts_with(&host_root_dir) {
|
||||
// Unless it's a proc macro used in the compiler
|
||||
if crate_types.iter().any(|t| t == "proc-macro") {
|
||||
deps.push((filename.to_path_buf(), true));
|
||||
deps.push((filename.to_path_buf(), DependencyType::Host));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -883,7 +939,7 @@ pub fn run_cargo(
|
|||
// If this was output in the `deps` dir then this is a precise file
|
||||
// name (hash included) so we start tracking it.
|
||||
if filename.starts_with(&target_deps_dir) {
|
||||
deps.push((filename.to_path_buf(), false));
|
||||
deps.push((filename.to_path_buf(), DependencyType::Target));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -935,17 +991,21 @@ pub fn run_cargo(
|
|||
let candidate = format!("{}.lib", path_to_add);
|
||||
let candidate = PathBuf::from(candidate);
|
||||
if candidate.exists() {
|
||||
deps.push((candidate, false));
|
||||
deps.push((candidate, DependencyType::Target));
|
||||
}
|
||||
}
|
||||
deps.push((path_to_add.into(), false));
|
||||
deps.push((path_to_add.into(), DependencyType::Target));
|
||||
}
|
||||
|
||||
deps.extend(additional_target_deps.into_iter().map(|d| (d, false)));
|
||||
deps.extend(additional_target_deps);
|
||||
deps.sort();
|
||||
let mut new_contents = Vec::new();
|
||||
for (dep, proc_macro) in deps.iter() {
|
||||
new_contents.extend(if *proc_macro { b"h" } else { b"t" });
|
||||
for (dep, dependency_type) in deps.iter() {
|
||||
new_contents.extend(match *dependency_type {
|
||||
DependencyType::Host => b"h",
|
||||
DependencyType::Target => b"t",
|
||||
DependencyType::TargetSelfContained => b"s",
|
||||
});
|
||||
new_contents.extend(dep.to_str().unwrap().as_bytes());
|
||||
new_contents.extend(b"\0");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use crate::channel;
|
|||
use crate::compile;
|
||||
use crate::tool::{self, Tool};
|
||||
use crate::util::{exe, is_dylib, timeit};
|
||||
use crate::{Compiler, Mode, LLVM_TOOLS};
|
||||
use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
|
||||
use time::{self, Timespec};
|
||||
|
||||
pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
|
||||
|
|
@ -306,7 +306,12 @@ fn make_win_dist(
|
|||
}
|
||||
|
||||
//Copy platform tools to platform-specific bin directory
|
||||
let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
|
||||
let target_bin_dir = plat_root
|
||||
.join("lib")
|
||||
.join("rustlib")
|
||||
.join(target_triple)
|
||||
.join("bin")
|
||||
.join("self-contained");
|
||||
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
|
||||
for src in target_tools {
|
||||
builder.copy_to_folder(&src, &target_bin_dir);
|
||||
|
|
@ -321,7 +326,12 @@ fn make_win_dist(
|
|||
);
|
||||
|
||||
//Copy platform libs to platform-specific lib directory
|
||||
let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
|
||||
let target_lib_dir = plat_root
|
||||
.join("lib")
|
||||
.join("rustlib")
|
||||
.join(target_triple)
|
||||
.join("lib")
|
||||
.join("self-contained");
|
||||
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
|
||||
for src in target_libs {
|
||||
builder.copy_to_folder(&src, &target_lib_dir);
|
||||
|
|
@ -652,9 +662,13 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
|
|||
/// Copy stamped files into an image's `target/lib` directory.
|
||||
fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
|
||||
let dst = image.join("lib/rustlib").join(target).join("lib");
|
||||
let self_contained_dst = dst.join("self-contained");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
for (path, host) in builder.read_stamp_file(stamp) {
|
||||
if !host || builder.config.build == target {
|
||||
t!(fs::create_dir_all(&self_contained_dst));
|
||||
for (path, dependency_type) in builder.read_stamp_file(stamp) {
|
||||
if dependency_type == DependencyType::TargetSelfContained {
|
||||
builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap()));
|
||||
} else if dependency_type == DependencyType::Target || builder.config.build == target {
|
||||
builder.copy(&path, &dst.join(path.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -548,8 +548,8 @@ impl Step for Rustc {
|
|||
// Find dependencies for top level crates.
|
||||
let mut compiler_crates = HashSet::new();
|
||||
for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
|
||||
let interned_root_crate = INTERNER.intern_str(root_crate);
|
||||
find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
|
||||
compiler_crates
|
||||
.extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name));
|
||||
}
|
||||
|
||||
for krate in &compiler_crates {
|
||||
|
|
@ -564,22 +564,6 @@ impl Step for Rustc {
|
|||
}
|
||||
}
|
||||
|
||||
fn find_compiler_crates(
|
||||
builder: &Builder<'_>,
|
||||
name: &Interned<String>,
|
||||
crates: &mut HashSet<Interned<String>>,
|
||||
) {
|
||||
// Add current crate.
|
||||
crates.insert(*name);
|
||||
|
||||
// Look for dependencies.
|
||||
for dep in builder.crates.get(name).unwrap().deps.iter() {
|
||||
if builder.crates.get(dep).unwrap().is_local(builder) {
|
||||
find_compiler_crates(builder, dep, crates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Rustdoc {
|
||||
stage: u32,
|
||||
|
|
|
|||
|
|
@ -3,18 +3,16 @@
|
|||
//! This module implements the command-line parsing of the build system which
|
||||
//! has various flags to configure how it's run.
|
||||
|
||||
use std::fs;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
use getopts::Options;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::config::Config;
|
||||
use crate::metadata;
|
||||
use crate::{Build, DocTests};
|
||||
|
||||
use crate::cache::{Interned, INTERNER};
|
||||
use crate::config::Config;
|
||||
use crate::{Build, DocTests};
|
||||
|
||||
/// Deserialized version of all flags for this compile.
|
||||
pub struct Flags {
|
||||
|
|
@ -438,19 +436,12 @@ Arguments:
|
|||
// Get any optional paths which occur after the subcommand
|
||||
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
|
||||
|
||||
let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
|
||||
if fs::metadata("config.toml").is_ok() {
|
||||
Some(PathBuf::from("config.toml"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
|
||||
|
||||
// All subcommands except `clean` can have an optional "Available paths" section
|
||||
if matches.opt_present("verbose") {
|
||||
let config = Config::parse(&["build".to_string()]);
|
||||
let mut build = Build::new(config);
|
||||
metadata::build(&mut build);
|
||||
let build = Build::new(config);
|
||||
|
||||
let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
|
||||
extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
|
||||
|
|
|
|||
|
|
@ -70,7 +70,10 @@ fn install_sh(
|
|||
let libdir_default = PathBuf::from("lib");
|
||||
let mandir_default = datadir_default.join("man");
|
||||
let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
|
||||
fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
|
||||
fs::create_dir_all(p)
|
||||
.unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
|
||||
fs::canonicalize(p)
|
||||
.unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
|
||||
});
|
||||
let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
|
||||
let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
|
||||
|
|
|
|||
|
|
@ -270,16 +270,22 @@ struct Crate {
|
|||
}
|
||||
|
||||
impl Crate {
|
||||
fn is_local(&self, build: &Build) -> bool {
|
||||
self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim")
|
||||
}
|
||||
|
||||
fn local_path(&self, build: &Build) -> PathBuf {
|
||||
assert!(self.is_local(build));
|
||||
self.path.strip_prefix(&build.config.src).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// When building Rust various objects are handled differently.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum DependencyType {
|
||||
/// Libraries originating from proc-macros.
|
||||
Host,
|
||||
/// Typical Rust libraries.
|
||||
Target,
|
||||
/// Non Rust libraries and objects shipped to ease usage of certain targets.
|
||||
TargetSelfContained,
|
||||
}
|
||||
|
||||
/// The various "modes" of invoking Cargo.
|
||||
///
|
||||
/// These entries currently correspond to the various output directories of the
|
||||
|
|
@ -1079,17 +1085,29 @@ impl Build {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a Vec of all the dependencies of the given root crate,
|
||||
/// including transitive dependencies and the root itself. Only includes
|
||||
/// "local" crates (those in the local source tree, not from a registry).
|
||||
fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
|
||||
let mut ret = Vec::new();
|
||||
let mut list = vec![INTERNER.intern_str(root)];
|
||||
let mut visited = HashSet::new();
|
||||
while let Some(krate) = list.pop() {
|
||||
let krate = &self.crates[&krate];
|
||||
if krate.is_local(self) {
|
||||
ret.push(krate);
|
||||
}
|
||||
ret.push(krate);
|
||||
for dep in &krate.deps {
|
||||
if visited.insert(dep) && dep != "build_helper" {
|
||||
// Don't include optional deps if their features are not
|
||||
// enabled. Ideally this would be computed from `cargo
|
||||
// metadata --features …`, but that is somewhat slow. Just
|
||||
// skip `build_helper` since there aren't any operations we
|
||||
// want to perform on it. In the future, we may want to
|
||||
// consider just filtering all build and dev dependencies in
|
||||
// metadata::build.
|
||||
if visited.insert(dep)
|
||||
&& dep != "build_helper"
|
||||
&& (dep != "profiler_builtins" || self.config.profiler)
|
||||
&& (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
|
||||
{
|
||||
list.push(*dep);
|
||||
}
|
||||
}
|
||||
|
|
@ -1097,7 +1115,7 @@ impl Build {
|
|||
ret
|
||||
}
|
||||
|
||||
fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> {
|
||||
fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
|
||||
if self.config.dry_run {
|
||||
return Vec::new();
|
||||
}
|
||||
|
|
@ -1110,9 +1128,14 @@ impl Build {
|
|||
if part.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let host = part[0] as char == 'h';
|
||||
let dependency_type = match part[0] as char {
|
||||
'h' => DependencyType::Host,
|
||||
's' => DependencyType::TargetSelfContained,
|
||||
't' => DependencyType::Target,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let path = PathBuf::from(t!(str::from_utf8(&part[1..])));
|
||||
paths.push((path, host));
|
||||
paths.push((path, dependency_type));
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
|
|
@ -12,7 +10,6 @@ use crate::{Build, Crate};
|
|||
#[derive(Deserialize)]
|
||||
struct Output {
|
||||
packages: Vec<Package>,
|
||||
resolve: Resolve,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
@ -21,63 +18,25 @@ struct Package {
|
|||
name: String,
|
||||
source: Option<String>,
|
||||
manifest_path: String,
|
||||
dependencies: Vec<Dependency>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Resolve {
|
||||
nodes: Vec<ResolveNode>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ResolveNode {
|
||||
id: String,
|
||||
dependencies: Vec<String>,
|
||||
struct Dependency {
|
||||
name: String,
|
||||
source: Option<String>,
|
||||
}
|
||||
|
||||
pub fn build(build: &mut Build) {
|
||||
let mut resolves = Vec::new();
|
||||
build_krate(&build.std_features(), build, &mut resolves, "src/libstd");
|
||||
build_krate("", build, &mut resolves, "src/libtest");
|
||||
build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc");
|
||||
|
||||
let mut id2name = HashMap::with_capacity(build.crates.len());
|
||||
for (name, krate) in build.crates.iter() {
|
||||
id2name.insert(krate.id.clone(), name.clone());
|
||||
}
|
||||
|
||||
for node in resolves {
|
||||
let name = match id2name.get(&node.id) {
|
||||
Some(name) => name,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let krate = build.crates.get_mut(name).unwrap();
|
||||
for dep in node.dependencies.iter() {
|
||||
let dep = match id2name.get(dep) {
|
||||
Some(dep) => dep,
|
||||
None => continue,
|
||||
};
|
||||
krate.deps.insert(*dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode>, krate: &str) {
|
||||
// Run `cargo metadata` to figure out what crates we're testing.
|
||||
//
|
||||
// Down below we're going to call `cargo test`, but to test the right set
|
||||
// of packages we're going to have to know what `-p` arguments to pass it
|
||||
// to know what crates to test. Here we run `cargo metadata` to learn about
|
||||
// the dependency graph and what `-p` arguments there are.
|
||||
let mut cargo = Command::new(&build.initial_cargo);
|
||||
cargo
|
||||
.arg("metadata")
|
||||
.arg("--format-version")
|
||||
.arg("1")
|
||||
.arg("--features")
|
||||
.arg(features)
|
||||
.arg("--no-deps")
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join(krate).join("Cargo.toml"));
|
||||
.arg(build.src.join("Cargo.toml"));
|
||||
let output = output(&mut cargo);
|
||||
let output: Output = serde_json::from_str(&output).unwrap();
|
||||
for package in output.packages {
|
||||
|
|
@ -85,8 +44,13 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode
|
|||
let name = INTERNER.intern_string(package.name);
|
||||
let mut path = PathBuf::from(package.manifest_path);
|
||||
path.pop();
|
||||
build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path });
|
||||
let deps = package
|
||||
.dependencies
|
||||
.into_iter()
|
||||
.filter(|dep| dep.source.is_none())
|
||||
.map(|dep| INTERNER.intern_string(dep.name))
|
||||
.collect();
|
||||
build.crates.insert(name, Crate { name, id: package.id, deps, path });
|
||||
}
|
||||
}
|
||||
resolves.extend(output.resolve.nodes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1648,14 +1648,8 @@ impl Step for Crate {
|
|||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let builder = run.builder;
|
||||
for krate in run.builder.in_tree_crates("test") {
|
||||
if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
|
||||
run = run.path(krate.local_path(&builder).to_str().unwrap());
|
||||
}
|
||||
}
|
||||
run
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.krate("test")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ path = "../liballoc/tests/lib.rs"
|
|||
[[bench]]
|
||||
name = "collectionsbenches"
|
||||
path = "../liballoc/benches/lib.rs"
|
||||
test = true
|
||||
|
||||
[[bench]]
|
||||
name = "vec_deque_append_bench"
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ impl<T> Box<T> {
|
|||
#[unstable(feature = "box_into_boxed_slice", issue = "71582")]
|
||||
pub fn into_boxed_slice(boxed: Box<T>) -> Box<[T]> {
|
||||
// *mut T and *mut [T; 1] have the same size and alignment
|
||||
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1] as *mut [T]) }
|
||||
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1]) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1639,7 +1639,7 @@ impl<T: Default> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// This code generalises `extend_with_{element,default}`.
|
||||
// This code generalizes `extend_with_{element,default}`.
|
||||
trait ExtendWith<T> {
|
||||
fn next(&mut self) -> T;
|
||||
fn last(self) -> T;
|
||||
|
|
@ -1837,7 +1837,7 @@ unsafe trait IsZero {
|
|||
}
|
||||
|
||||
macro_rules! impl_is_zero {
|
||||
($t: ty, $is_zero: expr) => {
|
||||
($t:ty, $is_zero:expr) => {
|
||||
unsafe impl IsZero for $t {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
|
|
@ -2362,9 +2362,9 @@ macro_rules! __impl_slice_eq1 {
|
|||
__impl_slice_eq1! { [] Vec<A>, Vec<B>, }
|
||||
__impl_slice_eq1! { [] Vec<A>, &[B], }
|
||||
__impl_slice_eq1! { [] Vec<A>, &mut [B], }
|
||||
__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone }
|
||||
__impl_slice_eq1! { [] Cow<'_, [A]>, &[B], A: Clone }
|
||||
__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B], A: Clone }
|
||||
__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone }
|
||||
__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], [B; N]: LengthAtMost32 }
|
||||
__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], [B; N]: LengthAtMost32 }
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ path = "../libcore/tests/lib.rs"
|
|||
[[bench]]
|
||||
name = "corebenches"
|
||||
path = "../libcore/benches/lib.rs"
|
||||
test = true
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// wasm32 does not support benches (no time).
|
||||
#![cfg(not(target_arch = "wasm32"))]
|
||||
#![feature(flt2dec)]
|
||||
#![feature(test)]
|
||||
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ pub trait Into<T>: Sized {
|
|||
/// [`Into`]: trait.Into.html
|
||||
/// [`from`]: trait.From.html#tymethod.from
|
||||
/// [book]: ../../book/ch09-00-error-handling.html
|
||||
#[rustc_diagnostic_item = "from_trait"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented(on(
|
||||
all(_Self = "&str", T = "std::string::String"),
|
||||
|
|
|
|||
|
|
@ -1941,6 +1941,13 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// Perma-unstable: do not use.
|
||||
pub fn miri_start_panic(payload: *mut u8) -> !;
|
||||
|
||||
/// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
|
||||
/// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
|
||||
/// generation.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[lang = "count_code_region"]
|
||||
pub fn count_code_region(index: u32);
|
||||
}
|
||||
|
||||
// Some functions are defined here because they accidentally got made
|
||||
|
|
@ -2057,9 +2064,14 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
|
|||
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
|
||||
}
|
||||
|
||||
debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
|
||||
debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
|
||||
debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory");
|
||||
if cfg!(debug_assertions)
|
||||
&& !(is_aligned_and_not_null(src)
|
||||
&& is_aligned_and_not_null(dst)
|
||||
&& is_nonoverlapping(src, dst, count))
|
||||
{
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
copy_nonoverlapping(src, dst, count)
|
||||
}
|
||||
|
||||
|
|
@ -2122,8 +2134,10 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
|||
fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
}
|
||||
|
||||
debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
|
||||
debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
|
||||
if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
copy(src, dst, count)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -581,11 +581,12 @@ pub const fn needs_drop<T>() -> bool {
|
|||
/// This means that, for example, the padding byte in `(u8, u16)` is not
|
||||
/// necessarily zeroed.
|
||||
///
|
||||
/// There is no guarantee that an all-zero byte-pattern represents a valid value of
|
||||
/// some type `T`. For example, the all-zero byte-pattern is not a valid value
|
||||
/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types
|
||||
/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv]
|
||||
/// that there always is a valid value in a variable it considers initialized.
|
||||
/// There is no guarantee that an all-zero byte-pattern represents a valid value
|
||||
/// of some type `T`. For example, the all-zero byte-pattern is not a valid value
|
||||
/// for reference types (`&T`, `&mut T`) and functions pointers. Using `zeroed`
|
||||
/// on such types causes immediate [undefined behavior][ub] because [the Rust
|
||||
/// compiler assumes][inv] that there always is a valid value in a variable it
|
||||
/// considers initialized.
|
||||
///
|
||||
/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
|
||||
/// It is useful for FFI sometimes, but should generally be avoided.
|
||||
|
|
@ -612,6 +613,7 @@ pub const fn needs_drop<T>() -> bool {
|
|||
/// use std::mem;
|
||||
///
|
||||
/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
|
||||
/// let _y: fn() = unsafe { mem::zeroed() }; // And again!
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
use crate::cmp::Ordering;
|
||||
use crate::fmt;
|
||||
use crate::hash;
|
||||
use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping};
|
||||
use crate::intrinsics::{self, abort, is_aligned_and_not_null, is_nonoverlapping};
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -420,9 +420,14 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
|||
#[inline]
|
||||
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
|
||||
pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer");
|
||||
debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer");
|
||||
debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory");
|
||||
if cfg!(debug_assertions)
|
||||
&& !(is_aligned_and_not_null(x)
|
||||
&& is_aligned_and_not_null(y)
|
||||
&& is_nonoverlapping(x, y, count))
|
||||
{
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
|
||||
let x = x as *mut u8;
|
||||
let y = y as *mut u8;
|
||||
|
|
@ -838,7 +843,10 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn write<T>(dst: *mut T, src: T) {
|
||||
debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
|
||||
if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
intrinsics::move_val_init(&mut *dst, src)
|
||||
}
|
||||
|
||||
|
|
@ -1003,7 +1011,10 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
|
|||
#[inline]
|
||||
#[stable(feature = "volatile", since = "1.9.0")]
|
||||
pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer");
|
||||
if cfg!(debug_assertions) && !is_aligned_and_not_null(src) {
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
intrinsics::volatile_load(src)
|
||||
}
|
||||
|
||||
|
|
@ -1072,7 +1083,10 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
|||
#[inline]
|
||||
#[stable(feature = "volatile", since = "1.9.0")]
|
||||
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
|
||||
debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
|
||||
if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
intrinsics::volatile_store(dst, src);
|
||||
}
|
||||
|
||||
|
|
@ -1399,3 +1413,70 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I }
|
|||
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
|
||||
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
|
||||
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
|
||||
|
||||
/// Create a `const` raw pointer to a place, without creating an intermediate reference.
|
||||
///
|
||||
/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
|
||||
/// and points to initialized data. For cases where those requirements do not hold,
|
||||
/// raw pointers should be used instead. However, `&expr as *const _` creates a reference
|
||||
/// before casting it to a raw pointer, and that reference is subject to the same rules
|
||||
/// as all other references. This macro can create a raw pointer *without* creating
|
||||
/// a reference first.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(raw_ref_macros)]
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// #[repr(packed)]
|
||||
/// struct Packed {
|
||||
/// f1: u8,
|
||||
/// f2: u16,
|
||||
/// }
|
||||
///
|
||||
/// let packed = Packed { f1: 1, f2: 2 };
|
||||
/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
|
||||
/// let raw_f2 = ptr::raw_const!(packed.f2);
|
||||
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
|
||||
/// ```
|
||||
#[unstable(feature = "raw_ref_macros", issue = "73394")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(raw_ref_op)]
|
||||
pub macro raw_const($e:expr) {
|
||||
&raw const $e
|
||||
}
|
||||
|
||||
/// Create a `mut` raw pointer to a place, without creating an intermediate reference.
|
||||
///
|
||||
/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
|
||||
/// and points to initialized data. For cases where those requirements do not hold,
|
||||
/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference
|
||||
/// before casting it to a raw pointer, and that reference is subject to the same rules
|
||||
/// as all other references. This macro can create a raw pointer *without* creating
|
||||
/// a reference first.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(raw_ref_macros)]
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// #[repr(packed)]
|
||||
/// struct Packed {
|
||||
/// f1: u8,
|
||||
/// f2: u16,
|
||||
/// }
|
||||
///
|
||||
/// let mut packed = Packed { f1: 1, f2: 2 };
|
||||
/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
|
||||
/// let raw_f2 = ptr::raw_mut!(packed.f2);
|
||||
/// unsafe { raw_f2.write_unaligned(42); }
|
||||
/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
|
||||
/// ```
|
||||
#[unstable(feature = "raw_ref_macros", issue = "73394")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(raw_ref_op)]
|
||||
pub macro raw_mut($e:expr) {
|
||||
&raw mut $e
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1145,45 +1145,69 @@ impl<T, E: Into<!>> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
#[unstable(feature = "inner_deref", issue = "50264")]
|
||||
impl<T: Deref, E> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E>`.
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a reference to the
|
||||
/// `Ok` type's `Deref::Target` type.
|
||||
/// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
|
||||
/// and returns the new [`Result`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let x: Result<String, u32> = Ok("hello".to_string());
|
||||
/// let y: Result<&str, &u32> = Ok("hello");
|
||||
/// assert_eq!(x.as_deref(), y);
|
||||
///
|
||||
/// let x: Result<String, u32> = Err(42);
|
||||
/// let y: Result<&str, &u32> = Err(&42);
|
||||
/// assert_eq!(x.as_deref(), y);
|
||||
/// ```
|
||||
pub fn as_deref(&self) -> Result<&T::Target, &E> {
|
||||
self.as_ref().map(|t| t.deref())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
#[unstable(feature = "inner_deref", issue = "50264")]
|
||||
impl<T, E: Deref> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &E::Target>`.
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &<E as Deref>::Target>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a reference to the
|
||||
/// `Err` type's `Deref::Target` type.
|
||||
/// Coerces the [`Err`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
|
||||
/// and returns the new [`Result`].
|
||||
pub fn as_deref_err(&self) -> Result<&T, &E::Target> {
|
||||
self.as_ref().map_err(|e| e.deref())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
#[unstable(feature = "inner_deref", issue = "50264")]
|
||||
impl<T: DerefMut, E> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T::Target, &mut E>`.
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
|
||||
/// the `Ok` type's `Deref::Target` type.
|
||||
/// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
|
||||
/// and returns the new [`Result`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut x: Result<String, u32> = Ok("hello".to_string());
|
||||
/// let y: Result<&mut str, &mut u32> = Ok("HELLO");
|
||||
/// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
|
||||
///
|
||||
/// let mut x: Result<String, u32> = Err(42);
|
||||
/// let y: Result<&mut str, &mut u32> = Err(&42);
|
||||
/// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
|
||||
/// ```
|
||||
pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
|
||||
self.as_mut().map(|t| t.deref_mut())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
#[unstable(feature = "inner_deref", issue = "50264")]
|
||||
impl<T, E: DerefMut> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut E::Target>`.
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut <E as DerefMut>::Target>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
|
||||
/// the `Err` type's `Deref::Target` type.
|
||||
/// Coerces the [`Err`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
|
||||
/// and returns the new [`Result`].
|
||||
pub fn as_deref_mut_err(&mut self) -> Result<&mut T, &mut E::Target> {
|
||||
self.as_mut().map_err(|e| e.deref_mut())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,3 +241,52 @@ fn iterator_drops() {
|
|||
}
|
||||
assert_eq!(i.get(), 5);
|
||||
}
|
||||
|
||||
// This test does not work on targets without panic=unwind support.
|
||||
// To work around this problem, test is marked is should_panic, so it will
|
||||
// be automagically skipped on unsuitable targets, such as
|
||||
// wasm32-unknown-unkown.
|
||||
//
|
||||
// It means that we use panic for indicating success.
|
||||
#[test]
|
||||
#[should_panic(expected = "test succeeded")]
|
||||
fn array_default_impl_avoids_leaks_on_panic() {
|
||||
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
#[derive(Debug)]
|
||||
struct Bomb(usize);
|
||||
|
||||
impl Default for Bomb {
|
||||
fn default() -> Bomb {
|
||||
if COUNTER.load(Relaxed) == 3 {
|
||||
panic!("bomb limit exceeded");
|
||||
}
|
||||
|
||||
COUNTER.fetch_add(1, Relaxed);
|
||||
Bomb(COUNTER.load(Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
COUNTER.fetch_sub(1, Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default());
|
||||
let panic_msg = match res {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(p) => p.downcast::<&'static str>().unwrap(),
|
||||
};
|
||||
assert_eq!(*panic_msg, "bomb limit exceeded");
|
||||
// check that all bombs are successfully dropped
|
||||
assert_eq!(COUNTER.load(Relaxed), 0);
|
||||
panic!("test succeeded")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_array_is_always_default() {
|
||||
struct DoesNotImplDefault;
|
||||
|
||||
let _arr = <[DoesNotImplDefault; 0]>::default();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! additional metadata), and [`ItemKind`] (which represents a concrete type and contains
|
||||
//! information specific to the type of the item).
|
||||
//!
|
||||
//! Other module items that worth mentioning:
|
||||
//! Other module items worth mentioning:
|
||||
//! - [`Ty`] and [`TyKind`]: A parsed Rust type.
|
||||
//! - [`Expr`] and [`ExprKind`]: A parsed Rust expression.
|
||||
//! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions.
|
||||
|
|
|
|||
|
|
@ -997,6 +997,33 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
|
||||
}
|
||||
|
||||
fn instrprof_increment(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
num_counters: &'ll Value,
|
||||
index: &'ll Value,
|
||||
) -> &'ll Value {
|
||||
debug!(
|
||||
"instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})",
|
||||
fn_name, hash, num_counters, index
|
||||
);
|
||||
|
||||
let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) };
|
||||
let args = &[fn_name, hash, num_counters, index];
|
||||
let args = self.check_call("call", llfn, args);
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMRustBuildCall(
|
||||
self.llbuilder,
|
||||
llfn,
|
||||
args.as_ptr() as *const &llvm::Value,
|
||||
args.len() as c_uint,
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
llfn: &'ll Value,
|
||||
|
|
|
|||
|
|
@ -749,6 +749,8 @@ impl CodegenCx<'b, 'tcx> {
|
|||
ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
|
||||
ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
|
||||
|
||||
ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
|
||||
|
||||
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
|
||||
ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
|
||||
ifn!("llvm.localescape", fn(...) -> void);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use self::EnumDiscriminantInfo::*;
|
||||
use self::EnumTagInfo::*;
|
||||
use self::MemberDescriptionFactory::*;
|
||||
use self::RecursiveTypeDescription::*;
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ use rustc_middle::{bug, span_bug};
|
|||
use rustc_session::config::{self, DebugInfo};
|
||||
use rustc_span::symbol::{Interner, Symbol};
|
||||
use rustc_span::{self, SourceFile, SourceFileHash, Span};
|
||||
use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
|
||||
use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
|
||||
use rustc_target::abi::{Int, Pointer, F32, F64};
|
||||
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
|
||||
|
||||
|
|
@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names(
|
|||
struct EnumMemberDescriptionFactory<'ll, 'tcx> {
|
||||
enum_type: Ty<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
discriminant_type_metadata: Option<&'ll DIType>,
|
||||
tag_type_metadata: Option<&'ll DIType>,
|
||||
containing_scope: &'ll DIScope,
|
||||
span: Span,
|
||||
}
|
||||
|
|
@ -1385,7 +1385,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
self.layout,
|
||||
variant_info,
|
||||
NoDiscriminant,
|
||||
NoTag,
|
||||
self_metadata,
|
||||
self.span,
|
||||
);
|
||||
|
|
@ -1409,19 +1409,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
}]
|
||||
}
|
||||
Variants::Multiple {
|
||||
discr_kind: DiscriminantKind::Tag,
|
||||
discr_index,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
tag_field,
|
||||
ref variants,
|
||||
..
|
||||
} => {
|
||||
let discriminant_info = if fallback {
|
||||
RegularDiscriminant {
|
||||
discr_field: Field::from(discr_index),
|
||||
discr_type_metadata: self.discriminant_type_metadata.unwrap(),
|
||||
let tag_info = if fallback {
|
||||
RegularTag {
|
||||
tag_field: Field::from(tag_field),
|
||||
tag_type_metadata: self.tag_type_metadata.unwrap(),
|
||||
}
|
||||
} else {
|
||||
// This doesn't matter in this case.
|
||||
NoDiscriminant
|
||||
NoTag
|
||||
};
|
||||
variants
|
||||
.iter_enumerated()
|
||||
|
|
@ -1432,7 +1432,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
variant,
|
||||
variant_info,
|
||||
discriminant_info,
|
||||
tag_info,
|
||||
self_metadata,
|
||||
self.span,
|
||||
);
|
||||
|
|
@ -1467,11 +1467,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
.collect()
|
||||
}
|
||||
Variants::Multiple {
|
||||
discr_kind:
|
||||
DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant },
|
||||
ref discr,
|
||||
tag_encoding:
|
||||
TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
|
||||
ref tag,
|
||||
ref variants,
|
||||
discr_index,
|
||||
tag_field,
|
||||
} => {
|
||||
if fallback {
|
||||
let variant = self.layout.for_variant(cx, dataful_variant);
|
||||
|
|
@ -1480,7 +1480,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
variant,
|
||||
variant_info_for(dataful_variant),
|
||||
OptimizedDiscriminant,
|
||||
OptimizedTag,
|
||||
self.containing_scope,
|
||||
self.span,
|
||||
);
|
||||
|
|
@ -1524,8 +1524,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
&mut name,
|
||||
self.layout,
|
||||
self.layout.fields.offset(discr_index),
|
||||
self.layout.field(cx, discr_index).size,
|
||||
self.layout.fields.offset(tag_field),
|
||||
self.layout.field(cx, tag_field).size,
|
||||
);
|
||||
variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
|
||||
name.push_str(variant_name);
|
||||
|
|
@ -1552,7 +1552,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
variant,
|
||||
variant_info,
|
||||
OptimizedDiscriminant,
|
||||
OptimizedTag,
|
||||
self_metadata,
|
||||
self.span,
|
||||
);
|
||||
|
|
@ -1573,7 +1573,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
let value = (i.as_u32() as u128)
|
||||
.wrapping_sub(niche_variants.start().as_u32() as u128)
|
||||
.wrapping_add(niche_start);
|
||||
let value = truncate(value, discr.value.size(cx));
|
||||
let value = truncate(value, tag.value.size(cx));
|
||||
// NOTE(eddyb) do *NOT* remove this assert, until
|
||||
// we pass the full 128-bit value to LLVM, otherwise
|
||||
// truncation will be silent and remain undetected.
|
||||
|
|
@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> {
|
|||
/// Cloned from the `layout::Struct` describing the variant.
|
||||
offsets: Vec<Size>,
|
||||
args: Vec<(String, Ty<'tcx>)>,
|
||||
discriminant_type_metadata: Option<&'ll DIType>,
|
||||
tag_type_metadata: Option<&'ll DIType>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -1617,7 +1617,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
|
|||
MemberDescription {
|
||||
name: name.to_string(),
|
||||
type_metadata: if use_enum_fallback(cx) {
|
||||
match self.discriminant_type_metadata {
|
||||
match self.tag_type_metadata {
|
||||
// Discriminant is always the first field of our variant
|
||||
// when using the enum fallback.
|
||||
Some(metadata) if i == 0 => metadata,
|
||||
|
|
@ -1637,11 +1637,14 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: terminology here should be aligned with `abi::TagEncoding`.
|
||||
// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
|
||||
// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
|
||||
#[derive(Copy, Clone)]
|
||||
enum EnumDiscriminantInfo<'ll> {
|
||||
RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType },
|
||||
OptimizedDiscriminant,
|
||||
NoDiscriminant,
|
||||
enum EnumTagInfo<'ll> {
|
||||
RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
|
||||
OptimizedTag,
|
||||
NoTag,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -1706,7 +1709,7 @@ fn describe_enum_variant(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
layout: layout::TyAndLayout<'tcx>,
|
||||
variant: VariantInfo<'_, 'tcx>,
|
||||
discriminant_info: EnumDiscriminantInfo<'ll>,
|
||||
discriminant_info: EnumTagInfo<'ll>,
|
||||
containing_scope: &'ll DIScope,
|
||||
span: Span,
|
||||
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
|
||||
|
|
@ -1722,12 +1725,12 @@ fn describe_enum_variant(
|
|||
let (offsets, args) = if use_enum_fallback(cx) {
|
||||
// If this is not a univariant enum, there is also the discriminant field.
|
||||
let (discr_offset, discr_arg) = match discriminant_info {
|
||||
RegularDiscriminant { discr_field, .. } => {
|
||||
RegularTag { tag_field, .. } => {
|
||||
// We have the layout of an enum variant, we need the layout of the outer enum
|
||||
let enum_layout = cx.layout_of(layout.ty);
|
||||
let offset = enum_layout.fields.offset(discr_field.as_usize());
|
||||
let offset = enum_layout.fields.offset(tag_field.as_usize());
|
||||
let args =
|
||||
("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty);
|
||||
("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
|
||||
(Some(offset), Some(args))
|
||||
}
|
||||
_ => (None, None),
|
||||
|
|
@ -1757,8 +1760,8 @@ fn describe_enum_variant(
|
|||
let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
|
||||
offsets,
|
||||
args,
|
||||
discriminant_type_metadata: match discriminant_info {
|
||||
RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata),
|
||||
tag_type_metadata: match discriminant_info {
|
||||
RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
|
||||
_ => None,
|
||||
},
|
||||
span,
|
||||
|
|
@ -1880,18 +1883,18 @@ fn prepare_enum_metadata(
|
|||
|
||||
if let (
|
||||
&Abi::Scalar(_),
|
||||
&Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. },
|
||||
&Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
|
||||
) = (&layout.abi, &layout.variants)
|
||||
{
|
||||
return FinalMetadata(discriminant_type_metadata(discr.value));
|
||||
return FinalMetadata(discriminant_type_metadata(tag.value));
|
||||
}
|
||||
|
||||
if use_enum_fallback(cx) {
|
||||
let discriminant_type_metadata = match layout.variants {
|
||||
Variants::Single { .. }
|
||||
| Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None,
|
||||
Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => {
|
||||
Some(discriminant_type_metadata(discr.value))
|
||||
| Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
|
||||
Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
|
||||
Some(discriminant_type_metadata(tag.value))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1927,7 +1930,7 @@ fn prepare_enum_metadata(
|
|||
EnumMDF(EnumMemberDescriptionFactory {
|
||||
enum_type,
|
||||
layout,
|
||||
discriminant_type_metadata,
|
||||
tag_type_metadata: discriminant_type_metadata,
|
||||
containing_scope,
|
||||
span,
|
||||
}),
|
||||
|
|
@ -1943,16 +1946,13 @@ fn prepare_enum_metadata(
|
|||
Variants::Single { .. } => None,
|
||||
|
||||
Variants::Multiple {
|
||||
discr_kind: DiscriminantKind::Niche { .. },
|
||||
ref discr,
|
||||
discr_index,
|
||||
..
|
||||
tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
|
||||
} => {
|
||||
// Find the integer type of the correct size.
|
||||
let size = discr.value.size(cx);
|
||||
let align = discr.value.align(cx);
|
||||
let size = tag.value.size(cx);
|
||||
let align = tag.value.align(cx);
|
||||
|
||||
let discr_type = match discr.value {
|
||||
let tag_type = match tag.value {
|
||||
Int(t, _) => t,
|
||||
F32 => Integer::I32,
|
||||
F64 => Integer::I64,
|
||||
|
|
@ -1960,7 +1960,7 @@ fn prepare_enum_metadata(
|
|||
}
|
||||
.to_ty(cx.tcx, false);
|
||||
|
||||
let discr_metadata = basic_type_metadata(cx, discr_type);
|
||||
let tag_metadata = basic_type_metadata(cx, tag_type);
|
||||
unsafe {
|
||||
Some(llvm::LLVMRustDIBuilderCreateMemberType(
|
||||
DIB(cx),
|
||||
|
|
@ -1971,17 +1971,15 @@ fn prepare_enum_metadata(
|
|||
UNKNOWN_LINE_NUMBER,
|
||||
size.bits(),
|
||||
align.abi.bits() as u32,
|
||||
layout.fields.offset(discr_index).bits(),
|
||||
layout.fields.offset(tag_field).bits(),
|
||||
DIFlags::FlagArtificial,
|
||||
discr_metadata,
|
||||
tag_metadata,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Variants::Multiple {
|
||||
discr_kind: DiscriminantKind::Tag, ref discr, discr_index, ..
|
||||
} => {
|
||||
let discr_type = discr.value.to_ty(cx.tcx);
|
||||
Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
|
||||
let discr_type = tag.value.to_ty(cx.tcx);
|
||||
let (size, align) = cx.size_and_align_of(discr_type);
|
||||
|
||||
let discr_metadata = basic_type_metadata(cx, discr_type);
|
||||
|
|
@ -1995,7 +1993,7 @@ fn prepare_enum_metadata(
|
|||
UNKNOWN_LINE_NUMBER,
|
||||
size.bits(),
|
||||
align.bits() as u32,
|
||||
layout.fields.offset(discr_index).bits(),
|
||||
layout.fields.offset(tag_field).bits(),
|
||||
DIFlags::FlagArtificial,
|
||||
discr_metadata,
|
||||
))
|
||||
|
|
@ -2081,7 +2079,7 @@ fn prepare_enum_metadata(
|
|||
EnumMDF(EnumMemberDescriptionFactory {
|
||||
enum_type,
|
||||
layout,
|
||||
discriminant_type_metadata: None,
|
||||
tag_type_metadata: None,
|
||||
containing_scope,
|
||||
span,
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ use crate::type_of::LayoutLlvmExt;
|
|||
use crate::va_arg::emit_va_arg;
|
||||
use crate::value::Value;
|
||||
|
||||
use log::debug;
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
|
||||
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
|
||||
|
|
@ -21,6 +23,7 @@ use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
|
|||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
|
|
@ -86,6 +89,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
args: &[OperandRef<'tcx, &'ll Value>],
|
||||
llresult: &'ll Value,
|
||||
span: Span,
|
||||
caller_instance: ty::Instance<'tcx>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let callee_ty = instance.monomorphic_ty(tcx);
|
||||
|
|
@ -136,6 +140,28 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
|
||||
self.call(llfn, &[], None)
|
||||
}
|
||||
"count_code_region" => {
|
||||
if let ty::InstanceDef::Item(fn_def_id) = caller_instance.def {
|
||||
let caller_fn_path = tcx.def_path_str(fn_def_id);
|
||||
debug!(
|
||||
"count_code_region to llvm.instrprof.increment(fn_name={})",
|
||||
caller_fn_path
|
||||
);
|
||||
|
||||
// FIXME(richkadel): (1) Replace raw function name with mangled function name;
|
||||
// (2) Replace hardcoded `1234` in `hash` with a computed hash (as discussed in)
|
||||
// the MCP (compiler-team/issues/278); and replace the hardcoded `1` for
|
||||
// `num_counters` with the actual number of counters per function (when the
|
||||
// changes are made to inject more than one counter per function).
|
||||
let (fn_name, _len_val) = self.const_str(Symbol::intern(&caller_fn_path));
|
||||
let index = args[0].immediate();
|
||||
let hash = self.const_u64(1234);
|
||||
let num_counters = self.const_u32(1);
|
||||
self.instrprof_increment(fn_name, hash, num_counters, index)
|
||||
} else {
|
||||
bug!("intrinsic count_code_region: no src.instance");
|
||||
}
|
||||
}
|
||||
"va_start" => self.va_start(args[0].immediate()),
|
||||
"va_end" => self.va_end(args[0].immediate()),
|
||||
"va_copy" => {
|
||||
|
|
|
|||
|
|
@ -1360,6 +1360,7 @@ extern "C" {
|
|||
|
||||
// Miscellaneous instructions
|
||||
pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
|
||||
pub fn LLVMRustGetInstrprofIncrementIntrinsic(M: &Module) -> &'a Value;
|
||||
pub fn LLVMRustBuildCall(
|
||||
B: &Builder<'a>,
|
||||
Fn: &'a Value,
|
||||
|
|
|
|||
|
|
@ -1075,6 +1075,10 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
|
|||
if file_path.exists() {
|
||||
return file_path;
|
||||
}
|
||||
let file_path = fs.get_selfcontained_lib_path().join(name);
|
||||
if file_path.exists() {
|
||||
return file_path;
|
||||
}
|
||||
for search_path in fs.search_paths() {
|
||||
let file_path = search_path.dir.join(name);
|
||||
if file_path.exists() {
|
||||
|
|
@ -1470,6 +1474,9 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
|
|||
// The location of crates will be determined as needed.
|
||||
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
|
||||
|
||||
let lib_path = sess.target_filesearch(PathKind::All).get_selfcontained_lib_path();
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
|
||||
}
|
||||
|
||||
/// Add options making relocation sections in the produced ELF files read-only
|
||||
|
|
|
|||
|
|
@ -721,12 +721,14 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
}
|
||||
|
||||
fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
|
||||
// not supported?
|
||||
self.link_staticlib(lib);
|
||||
self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
|
||||
}
|
||||
fn link_whole_rlib(&mut self, path: &Path) {
|
||||
// not supported?
|
||||
self.link_rlib(path);
|
||||
let mut arg = OsString::from("/WHOLEARCHIVE:");
|
||||
arg.push(path);
|
||||
self.cmd.arg(arg);
|
||||
}
|
||||
fn optimize(&mut self) {
|
||||
// Needs more investigation of `/OPT` arguments
|
||||
|
|
|
|||
|
|
@ -89,10 +89,12 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
|
|||
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
|
||||
let def_id = tcx.hir().local_def_id(hir_id);
|
||||
let generics = tcx.generics_of(def_id);
|
||||
if !generics.requires_monomorphization(tcx) &&
|
||||
// Functions marked with #[inline] are only ever codegened
|
||||
// with "internal" linkage and are never exported.
|
||||
!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
|
||||
if !generics.requires_monomorphization(tcx)
|
||||
// Functions marked with #[inline] are codegened with "internal"
|
||||
// linkage and are not exported unless marked with an extern
|
||||
// inidicator
|
||||
&& (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator())
|
||||
{
|
||||
Some(def_id)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -175,6 +175,12 @@ impl ModuleConfig {
|
|||
if sess.opts.debugging_opts.profile && !is_compiler_builtins {
|
||||
passes.push("insert-gcov-profiling".to_owned());
|
||||
}
|
||||
|
||||
// The rustc option `-Zinstrument_coverage` injects intrinsic calls to
|
||||
// `llvm.instrprof.increment()`, which requires the LLVM `instrprof` pass.
|
||||
if sess.opts.debugging_opts.instrument_coverage {
|
||||
passes.push("instrprof".to_owned());
|
||||
}
|
||||
passes
|
||||
},
|
||||
vec![]
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
tcx.def_key(def_id).disambiguated_data.disambiguator
|
||||
));
|
||||
}
|
||||
ty::Error
|
||||
ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Projection(..)
|
||||
|
|
|
|||
|
|
@ -234,8 +234,8 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
self.visit_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
|
||||
let check = match *kind {
|
||||
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
|
||||
let check = match terminator.kind {
|
||||
mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
|
||||
match c.literal.ty.kind {
|
||||
ty::FnDef(did, _) => Some((did, args)),
|
||||
|
|
@ -259,7 +259,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
}
|
||||
}
|
||||
|
||||
self.super_terminator_kind(kind, location);
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
|
|
|
|||
|
|
@ -693,6 +693,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
&args,
|
||||
dest,
|
||||
terminator.source_info.span,
|
||||
self.instance,
|
||||
);
|
||||
|
||||
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
||||
|
|
@ -998,8 +999,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.unreachable();
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Drop { location, target, unwind } => {
|
||||
self.codegen_drop_terminator(helper, bx, location, target, unwind);
|
||||
mir::TerminatorKind::Drop { place, target, unwind } => {
|
||||
self.codegen_drop_terminator(helper, bx, place, target, unwind);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_middle::mir;
|
|||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int};
|
||||
use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
|
||||
use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -199,7 +199,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
if self.layout.abi.is_uninhabited() {
|
||||
return bx.cx().const_undef(cast_to);
|
||||
}
|
||||
let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
|
||||
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
|
||||
Variants::Single { index } => {
|
||||
let discr_val = self
|
||||
.layout
|
||||
|
|
@ -208,33 +208,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
.map_or(index.as_u32() as u128, |discr| discr.val);
|
||||
return bx.cx().const_uint_big(cast_to, discr_val);
|
||||
}
|
||||
Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
|
||||
(discr, discr_kind, discr_index)
|
||||
Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
|
||||
(tag, tag_encoding, tag_field)
|
||||
}
|
||||
};
|
||||
|
||||
// Read the tag/niche-encoded discriminant from memory.
|
||||
let encoded_discr = self.project_field(bx, discr_index);
|
||||
let encoded_discr = bx.load_operand(encoded_discr);
|
||||
let tag = self.project_field(bx, tag_field);
|
||||
let tag = bx.load_operand(tag);
|
||||
|
||||
// Decode the discriminant (specifically if it's niche-encoded).
|
||||
match *discr_kind {
|
||||
DiscriminantKind::Tag => {
|
||||
let signed = match discr_scalar.value {
|
||||
match *tag_encoding {
|
||||
TagEncoding::Direct => {
|
||||
let signed = match tag_scalar.value {
|
||||
// We use `i1` for bytes that are always `0` or `1`,
|
||||
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
|
||||
// let LLVM interpret the `i1` as signed, because
|
||||
// then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
|
||||
Int(_, signed) => !discr_scalar.is_bool() && signed,
|
||||
Int(_, signed) => !tag_scalar.is_bool() && signed,
|
||||
_ => false,
|
||||
};
|
||||
bx.intcast(encoded_discr.immediate(), cast_to, signed)
|
||||
bx.intcast(tag.immediate(), cast_to, signed)
|
||||
}
|
||||
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
|
||||
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
|
||||
// Rebase from niche values to discriminants, and check
|
||||
// whether the result is in range for the niche variants.
|
||||
let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout);
|
||||
let encoded_discr = encoded_discr.immediate();
|
||||
let niche_llty = bx.cx().immediate_backend_type(tag.layout);
|
||||
let tag = tag.immediate();
|
||||
|
||||
// We first compute the "relative discriminant" (wrt `niche_variants`),
|
||||
// that is, if `n = niche_variants.end() - niche_variants.start()`,
|
||||
|
|
@ -248,9 +248,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
let relative_discr = if niche_start == 0 {
|
||||
// Avoid subtracting `0`, which wouldn't work for pointers.
|
||||
// FIXME(eddyb) check the actual primitive type here.
|
||||
encoded_discr
|
||||
tag
|
||||
} else {
|
||||
bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start))
|
||||
bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
|
||||
};
|
||||
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
|
||||
let is_niche = {
|
||||
|
|
@ -312,8 +312,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
Variants::Single { index } => {
|
||||
assert_eq!(index, variant_index);
|
||||
}
|
||||
Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => {
|
||||
let ptr = self.project_field(bx, discr_index);
|
||||
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
|
||||
let ptr = self.project_field(bx, tag_field);
|
||||
let to =
|
||||
self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
|
||||
bx.store(
|
||||
|
|
@ -323,9 +323,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
);
|
||||
}
|
||||
Variants::Multiple {
|
||||
discr_kind:
|
||||
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
|
||||
discr_index,
|
||||
tag_encoding:
|
||||
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
|
||||
tag_field,
|
||||
..
|
||||
} => {
|
||||
if variant_index != dataful_variant {
|
||||
|
|
@ -339,7 +339,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
|
||||
}
|
||||
|
||||
let niche = self.project_field(bx, discr_index);
|
||||
let niche = self.project_field(bx, tag_field);
|
||||
let niche_llty = bx.cx().immediate_backend_type(niche.layout);
|
||||
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
|
||||
let niche_value = (niche_value as u128).wrapping_add(niche_start);
|
||||
|
|
|
|||
|
|
@ -260,6 +260,14 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
/// Called for `StorageDead`
|
||||
fn lifetime_end(&mut self, ptr: Self::Value, size: Size);
|
||||
|
||||
fn instrprof_increment(
|
||||
&mut self,
|
||||
fn_name: Self::Value,
|
||||
hash: Self::Value,
|
||||
num_counters: Self::Value,
|
||||
index: Self::Value,
|
||||
) -> Self::Value;
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
llfn: Self::Value,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
|
|||
args: &[OperandRef<'tcx, Self::Value>],
|
||||
llresult: Self::Value,
|
||||
span: Span,
|
||||
caller_instance: ty::Instance<'tcx>,
|
||||
);
|
||||
|
||||
fn abort(&mut self);
|
||||
|
|
|
|||
|
|
@ -439,9 +439,11 @@ E0752: include_str!("./error_codes/E0752.md"),
|
|||
E0753: include_str!("./error_codes/E0753.md"),
|
||||
E0754: include_str!("./error_codes/E0754.md"),
|
||||
E0758: include_str!("./error_codes/E0758.md"),
|
||||
E0759: include_str!("./error_codes/E0759.md"),
|
||||
E0760: include_str!("./error_codes/E0760.md"),
|
||||
E0761: include_str!("./error_codes/E0761.md"),
|
||||
E0762: include_str!("./error_codes/E0762.md"),
|
||||
E0763: include_str!("./error_codes/E0763.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
|
|
|||
67
src/librustc_error_codes/error_codes/E0759.md
Normal file
67
src/librustc_error_codes/error_codes/E0759.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
A `'static` requirement in a return type involving a trait is not fulfilled.
|
||||
|
||||
Erroneous code examples:
|
||||
|
||||
```compile_fail,E0759
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn foo(x: &i32) -> impl Debug {
|
||||
x
|
||||
}
|
||||
```
|
||||
|
||||
```compile_fail,E0759
|
||||
# use std::fmt::Debug;
|
||||
fn bar(x: &i32) -> Box<dyn Debug> {
|
||||
Box::new(x)
|
||||
}
|
||||
```
|
||||
|
||||
These examples have the same semantics as the following:
|
||||
|
||||
```compile_fail,E0759
|
||||
# use std::fmt::Debug;
|
||||
fn foo(x: &i32) -> impl Debug + 'static {
|
||||
x
|
||||
}
|
||||
```
|
||||
|
||||
```compile_fail,E0759
|
||||
# use std::fmt::Debug;
|
||||
fn bar(x: &i32) -> Box<dyn Debug + 'static> {
|
||||
Box::new(x)
|
||||
}
|
||||
```
|
||||
|
||||
Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit
|
||||
`'static` requirement, meaning that the value implementing them that is being
|
||||
returned has to be either a `'static` borrow or an owned value.
|
||||
|
||||
In order to change the requirement from `'static` to be a lifetime derived from
|
||||
its arguments, you can add an explicit bound, either to an anonymous lifetime
|
||||
`'_` or some appropriate named lifetime.
|
||||
|
||||
```
|
||||
# use std::fmt::Debug;
|
||||
fn foo(x: &i32) -> impl Debug + '_ {
|
||||
x
|
||||
}
|
||||
fn bar(x: &i32) -> Box<dyn Debug + '_> {
|
||||
Box::new(x)
|
||||
}
|
||||
```
|
||||
|
||||
These are equivalent to the following explicit lifetime annotations:
|
||||
|
||||
```
|
||||
# use std::fmt::Debug;
|
||||
fn foo<'a>(x: &'a i32) -> impl Debug + 'a {
|
||||
x
|
||||
}
|
||||
fn bar<'a>(x: &'a i32) -> Box<dyn Debug + 'a> {
|
||||
Box::new(x)
|
||||
}
|
||||
```
|
||||
|
||||
[`dyn Trait`]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
|
||||
[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits
|
||||
13
src/librustc_error_codes/error_codes/E0763.md
Normal file
13
src/librustc_error_codes/error_codes/E0763.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
A byte constant wasn't correctly ended.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0763
|
||||
let c = b'a; // error!
|
||||
```
|
||||
|
||||
To fix this error, add the missing quote:
|
||||
|
||||
```
|
||||
let c = b'a'; // ok!
|
||||
```
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(nll)]
|
||||
#![feature(track_caller)]
|
||||
|
||||
pub use emitter::ColorConfig;
|
||||
|
||||
|
|
@ -621,6 +622,7 @@ impl Handler {
|
|||
self.inner.borrow_mut().span_bug(span, msg)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
|
||||
self.inner.borrow_mut().delay_span_bug(span, msg)
|
||||
}
|
||||
|
|
@ -873,6 +875,7 @@ impl HandlerInner {
|
|||
self.emit_diagnostic(diag.set_span(sp));
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
|
||||
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
|
||||
// incrementing `err_count` by one, so we need to +1 the comparing.
|
||||
|
|
@ -883,6 +886,7 @@ impl HandlerInner {
|
|||
}
|
||||
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
|
||||
diagnostic.set_span(sp.into());
|
||||
diagnostic.note(&format!("delayed at {}", std::panic::Location::caller()));
|
||||
self.delay_as_bug(diagnostic)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2726,6 +2726,18 @@ impl Node<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn body_id(&self) -> Option<BodyId> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem {
|
||||
kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
|
||||
| Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generics(&self) -> Option<&Generics<'_>> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem { generics, .. })
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ language_item_table! {
|
|||
|
||||
StartFnLangItem, "start", start_fn, Target::Fn;
|
||||
|
||||
CountCodeRegionFnLangItem, "count_code_region", count_code_region_fn, Target::Fn;
|
||||
|
||||
EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn;
|
||||
EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static;
|
||||
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
|||
| ty::Float(..)
|
||||
| ty::Adt(..)
|
||||
| ty::Str
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Array(..)
|
||||
| ty::Slice(..)
|
||||
| ty::RawPtr(..)
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
self.tcx
|
||||
.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Placeholder(placeholder_mapped),
|
||||
ty: self.tcx.types.err, // FIXME(const_generics)
|
||||
ty: self.tcx.ty_error(), // FIXME(const_generics)
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2035,8 +2035,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.tcx.sess,
|
||||
var_origin.span(),
|
||||
E0495,
|
||||
"cannot infer an appropriate lifetime{} \
|
||||
due to conflicting requirements",
|
||||
"cannot infer an appropriate lifetime{} due to conflicting requirements",
|
||||
var_description
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
//! Error Reporting for static impl Traits.
|
||||
|
||||
use crate::infer::error_reporting::msg_span_from_free_region;
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use rustc_errors::{Applicability, ErrorReported};
|
||||
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
|
||||
use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
|
||||
use rustc_middle::ty::RegionKind;
|
||||
|
||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
/// Print the error message for lifetime errors when the return type is a static impl Trait.
|
||||
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
|
||||
debug!("try_report_static_impl_trait(error={:?})", self.error);
|
||||
if let Some(ref error) = self.error {
|
||||
if let RegionResolutionError::SubSupConflict(
|
||||
_,
|
||||
|
|
@ -17,18 +18,36 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
sub_r,
|
||||
sup_origin,
|
||||
sup_r,
|
||||
) = error.clone()
|
||||
) = error
|
||||
{
|
||||
debug!(
|
||||
"try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
|
||||
var_origin, sub_origin, sub_r, sup_origin, sup_r
|
||||
);
|
||||
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
|
||||
let (fn_return_span, is_dyn) =
|
||||
self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
|
||||
if sub_r == &RegionKind::ReStatic {
|
||||
debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
|
||||
let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
|
||||
debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
|
||||
if **sub_r == RegionKind::ReStatic {
|
||||
let sp = var_origin.span();
|
||||
let return_sp = sub_origin.span();
|
||||
let mut err =
|
||||
self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime");
|
||||
let param_info = self.find_param_with_region(sup_r, sub_r)?;
|
||||
err.span_label(param_info.param_ty_span, "data with this lifetime...");
|
||||
let (lifetime_name, lifetime) = if sup_r.has_name() {
|
||||
(sup_r.to_string(), format!("lifetime `{}`", sup_r))
|
||||
} else {
|
||||
("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
|
||||
};
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx().sess,
|
||||
sp,
|
||||
E0759,
|
||||
"cannot infer an appropriate lifetime"
|
||||
);
|
||||
err.span_label(
|
||||
param_info.param_ty_span,
|
||||
&format!("this data with {}...", lifetime),
|
||||
);
|
||||
debug!("try_report_static_impl_trait: param_info={:?}", param_info);
|
||||
|
||||
// We try to make the output have fewer overlapping spans if possible.
|
||||
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
|
||||
|
|
@ -38,41 +57,146 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
|
||||
// Customize the spans and labels depending on their relative order so
|
||||
// that split sentences flow correctly.
|
||||
if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() {
|
||||
err.span_label(sup_origin.span(), "...is captured here...");
|
||||
err.span_label(return_sp, "...and required to be `'static` by this");
|
||||
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
|
||||
// Avoid the following:
|
||||
//
|
||||
// error: cannot infer an appropriate lifetime
|
||||
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
|
||||
// |
|
||||
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
|
||||
// | ---- ---------^-
|
||||
//
|
||||
// and instead show:
|
||||
//
|
||||
// error: cannot infer an appropriate lifetime
|
||||
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
|
||||
// |
|
||||
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
|
||||
// | ---- ^
|
||||
err.span_label(
|
||||
sup_origin.span(),
|
||||
"...is captured here, requiring it to live as long as `'static`",
|
||||
);
|
||||
} else {
|
||||
err.span_label(return_sp, "...is required to be `'static` by this...");
|
||||
err.span_label(sup_origin.span(), "...and is captured here");
|
||||
err.span_label(sup_origin.span(), "...is captured here...");
|
||||
if return_sp < sup_origin.span() {
|
||||
err.span_note(
|
||||
return_sp,
|
||||
"...and is required to live as long as `'static` here",
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
return_sp,
|
||||
"...and is required to live as long as `'static` here",
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
return_sp,
|
||||
"...is captured and required to be `'static` here",
|
||||
"...is captured and required to live as long as `'static` here",
|
||||
);
|
||||
}
|
||||
|
||||
let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r);
|
||||
|
||||
let lifetime_name =
|
||||
if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
|
||||
// only apply this suggestion onto functions with
|
||||
// explicit non-desugar'able return.
|
||||
if fn_return_span.desugaring_kind().is_none() {
|
||||
let msg = format!(
|
||||
"to permit non-static references in {} `{} Trait` value, you can add \
|
||||
an explicit bound for {}",
|
||||
if is_dyn { "a" } else { "an" },
|
||||
if is_dyn { "dyn" } else { "impl" },
|
||||
lifetime,
|
||||
);
|
||||
if fn_return.span.desugaring_kind().is_none() {
|
||||
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
|
||||
err.span_suggestion_verbose(
|
||||
fn_return_span.shrink_to_hi(),
|
||||
&msg,
|
||||
format!(" + {}", lifetime_name),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
let consider = "consider changing the";
|
||||
let declare = "to declare that the";
|
||||
let arg = match param_info.param.pat.simple_ident() {
|
||||
Some(simple_ident) => format!("argument `{}`", simple_ident),
|
||||
None => "the argument".to_string(),
|
||||
};
|
||||
let explicit =
|
||||
format!("you can add an explicit `{}` lifetime bound", lifetime_name);
|
||||
let explicit_static =
|
||||
format!("explicit `'static` bound to the lifetime of {}", arg);
|
||||
let captures = format!("captures data from {}", arg);
|
||||
let add_static_bound =
|
||||
"alternatively, add an explicit `'static` bound to this reference";
|
||||
let plus_lt = format!(" + {}", lifetime_name);
|
||||
match fn_return.kind {
|
||||
TyKind::OpaqueDef(item_id, _) => {
|
||||
let item = self.tcx().hir().item(item_id.id);
|
||||
let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
|
||||
opaque
|
||||
} else {
|
||||
err.emit();
|
||||
return Some(ErrorReported);
|
||||
};
|
||||
|
||||
if let Some(span) = opaque
|
||||
.bounds
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
GenericBound::Outlives(Lifetime {
|
||||
name: LifetimeName::Static,
|
||||
span,
|
||||
..
|
||||
}) => Some(*span),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!("{} `impl Trait`'s {}", consider, explicit_static),
|
||||
lifetime_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
param_info.param_ty_span,
|
||||
add_static_bound,
|
||||
param_info.param_ty.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
fn_return.span.shrink_to_hi(),
|
||||
&format!(
|
||||
"{declare} `impl Trait` {captures}, {explicit}",
|
||||
declare = declare,
|
||||
captures = captures,
|
||||
explicit = explicit,
|
||||
),
|
||||
plus_lt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
};
|
||||
}
|
||||
TyKind::TraitObject(_, lt) => match lt.name {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
err.span_suggestion_verbose(
|
||||
fn_return.span.shrink_to_hi(),
|
||||
&format!(
|
||||
"{declare} trait object {captures}, {explicit}",
|
||||
declare = declare,
|
||||
captures = captures,
|
||||
explicit = explicit,
|
||||
),
|
||||
plus_lt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_suggestion_verbose(
|
||||
lt.span,
|
||||
&format!("{} trait object's {}", consider, explicit_static),
|
||||
lifetime_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
param_info.param_ty_span,
|
||||
add_static_bound,
|
||||
param_info.param_ty.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
return Some(ErrorReported);
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||
| ty::Float(..)
|
||||
| ty::Adt(..)
|
||||
| ty::Str
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Array(..)
|
||||
| ty::Slice(..)
|
||||
| ty::RawPtr(..)
|
||||
|
|
@ -250,7 +250,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Unevaluated(..)
|
||||
| ty::ConstKind::Error => {}
|
||||
| ty::ConstKind::Error(_) => {}
|
||||
}
|
||||
|
||||
ct.super_fold_with(self)
|
||||
|
|
|
|||
|
|
@ -1751,9 +1751,10 @@ impl<'tcx> TypeTrace<'tcx> {
|
|||
}
|
||||
|
||||
pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
|
||||
let err = tcx.ty_error();
|
||||
TypeTrace {
|
||||
cause: ObligationCause::dummy(),
|
||||
values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }),
|
||||
values: Types(ExpectedFound { expected: err, found: err }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,15 +189,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
|
|||
match t.kind {
|
||||
ty::Infer(ty::TyVar(vid)) => {
|
||||
self.err = Some(FixupError::UnresolvedTy(vid));
|
||||
self.tcx().types.err
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
ty::Infer(ty::IntVar(vid)) => {
|
||||
self.err = Some(FixupError::UnresolvedIntTy(vid));
|
||||
self.tcx().types.err
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
ty::Infer(ty::FloatVar(vid)) => {
|
||||
self.err = Some(FixupError::UnresolvedFloatTy(vid));
|
||||
self.tcx().types.err
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
ty::Infer(_) => {
|
||||
bug!("Unexpected type in full type resolver: {:?}", t);
|
||||
|
|
@ -228,7 +228,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
|
|||
match c.val {
|
||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||
self.err = Some(FixupError::UnresolvedConst(vid));
|
||||
return self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: c.ty });
|
||||
return self.tcx().const_error(c.ty);
|
||||
}
|
||||
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
|
||||
bug!("Unexpected const in full const resolver: {:?}", c);
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
|
|||
Ok(a)
|
||||
}
|
||||
|
||||
(&ty::Error, _) | (_, &ty::Error) => {
|
||||
(&ty::Error(_), _) | (_, &ty::Error(_)) => {
|
||||
infcx.set_tainted_by_errors();
|
||||
Ok(self.tcx().types.err)
|
||||
Ok(self.tcx().ty_error())
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -548,6 +548,7 @@ fn test_debugging_options_tracking_hash() {
|
|||
tracked!(human_readable_cgu_names, true);
|
||||
tracked!(inline_in_all_cgus, Some(true));
|
||||
tracked!(insert_sideeffect, true);
|
||||
tracked!(instrument_coverage, true);
|
||||
tracked!(instrument_mcount, true);
|
||||
tracked!(link_only, true);
|
||||
tracked!(merge_functions, Some(MergeFunctions::Disabled));
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
|
|||
use rustc_span::source_map;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants};
|
||||
use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use log::debug;
|
||||
|
|
@ -889,7 +889,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
ty::Param(..)
|
||||
| ty::Infer(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
|
|
@ -1056,15 +1056,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
|||
};
|
||||
let (variants, tag) = match layout.variants {
|
||||
Variants::Multiple {
|
||||
discr_kind: DiscriminantKind::Tag,
|
||||
ref discr,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
ref tag,
|
||||
ref variants,
|
||||
..
|
||||
} => (variants, discr),
|
||||
} => (variants, tag),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let discr_size = tag.value.size(&cx.tcx).bytes();
|
||||
let tag_size = tag.value.size(&cx.tcx).bytes();
|
||||
|
||||
debug!(
|
||||
"enum `{}` is {} bytes large with layout:\n{:#?}",
|
||||
|
|
@ -1078,8 +1078,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
|||
.iter()
|
||||
.zip(variants)
|
||||
.map(|(variant, variant_layout)| {
|
||||
// Subtract the size of the enum discriminant.
|
||||
let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
|
||||
// Subtract the size of the enum tag.
|
||||
let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
|
||||
|
||||
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
|
||||
bytes
|
||||
|
|
|
|||
|
|
@ -452,6 +452,14 @@ impl<'a> CrateLoader<'a> {
|
|||
if dep.is_none() {
|
||||
self.used_extern_options.insert(name);
|
||||
}
|
||||
if !name.as_str().is_ascii() {
|
||||
self.sess
|
||||
.struct_span_err(
|
||||
span,
|
||||
&format!("cannot load a crate with a non-ascii name `{}`", name,),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
|
||||
}
|
||||
|
||||
|
|
@ -698,7 +706,9 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn inject_profiler_runtime(&mut self) {
|
||||
if (self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled())
|
||||
if (self.sess.opts.debugging_opts.instrument_coverage
|
||||
|| self.sess.opts.debugging_opts.profile
|
||||
|| self.sess.opts.cg.profile_generate.enabled())
|
||||
&& !self.sess.opts.debugging_opts.no_profiler_runtime
|
||||
{
|
||||
info!("loading profiler");
|
||||
|
|
|
|||
|
|
@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
|
|||
InvalidBool(u8),
|
||||
/// Using a non-character `u32` as character.
|
||||
InvalidChar(u32),
|
||||
/// An enum discriminant was set to a value which was outside the range of valid values.
|
||||
InvalidDiscriminant(Scalar),
|
||||
/// The tag of an enum does not encode an actual discriminant.
|
||||
InvalidTag(Scalar),
|
||||
/// Using a pointer-not-to-a-function as function pointer.
|
||||
InvalidFunctionPointer(Pointer),
|
||||
/// Using a string that is not valid UTF-8,
|
||||
|
|
@ -463,7 +463,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
|||
InvalidChar(c) => {
|
||||
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
|
||||
}
|
||||
InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val),
|
||||
InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
|
||||
InvalidFunctionPointer(p) => {
|
||||
write!(f, "using {} as function pointer but it does not point to a function", p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use rustc_macros::HashStable;
|
|||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi;
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||
|
|
@ -1112,7 +1113,7 @@ pub enum TerminatorKind<'tcx> {
|
|||
Unreachable,
|
||||
|
||||
/// Drop the `Place`.
|
||||
Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
|
||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
|
||||
|
||||
/// Drop the `Place` and assign the new value over it. This ensures
|
||||
/// that the assignment to `P` occurs *even if* the destructor for
|
||||
|
|
@ -1141,7 +1142,7 @@ pub enum TerminatorKind<'tcx> {
|
|||
/// }
|
||||
/// ```
|
||||
DropAndReplace {
|
||||
location: Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
value: Operand<'tcx>,
|
||||
target: BasicBlock,
|
||||
unwind: Option<BasicBlock>,
|
||||
|
|
@ -1607,9 +1608,9 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
Abort => write!(fmt, "abort"),
|
||||
Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
|
||||
Unreachable => write!(fmt, "unreachable"),
|
||||
Drop { location, .. } => write!(fmt, "drop({:?})", location),
|
||||
DropAndReplace { location, value, .. } => {
|
||||
write!(fmt, "replace({:?} <- {:?})", location, value)
|
||||
Drop { place, .. } => write!(fmt, "drop({:?})", place),
|
||||
DropAndReplace { place, value, .. } => {
|
||||
write!(fmt, "replace({:?} <- {:?})", place, value)
|
||||
}
|
||||
Call { func, args, destination, .. } => {
|
||||
if let Some((destination, _)) = destination {
|
||||
|
|
@ -2218,6 +2219,33 @@ impl<'tcx> Operand<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Convenience helper to make a literal-like constant from a given scalar value.
|
||||
/// Since this is used to synthesize MIR, assumes `user_ty` is None.
|
||||
pub fn const_from_scalar(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
val: Scalar,
|
||||
span: Span,
|
||||
) -> Operand<'tcx> {
|
||||
debug_assert!({
|
||||
let param_env_and_ty = ty::ParamEnv::empty().and(ty);
|
||||
let type_size = tcx
|
||||
.layout_of(param_env_and_ty)
|
||||
.unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
|
||||
.size;
|
||||
let scalar_size = abi::Size::from_bytes(match val {
|
||||
Scalar::Raw { size, .. } => size,
|
||||
_ => panic!("Invalid scalar type {:?}", val),
|
||||
});
|
||||
scalar_size == type_size
|
||||
});
|
||||
Operand::Constant(box Constant {
|
||||
span,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_scalar(tcx, val, ty),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_copy(&self) -> Self {
|
||||
match *self {
|
||||
Operand::Copy(_) | Operand::Constant(_) => self.clone(),
|
||||
|
|
|
|||
|
|
@ -91,9 +91,9 @@ impl<'tcx> MonoItem<'tcx> {
|
|||
match *self {
|
||||
MonoItem::Fn(ref instance) => {
|
||||
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
|
||||
// If this function isn't inlined or otherwise has explicit
|
||||
// linkage, then we'll be creating a globally shared version.
|
||||
if self.explicit_linkage(tcx).is_some()
|
||||
// If this function isn't inlined or otherwise has an extern
|
||||
// indicator, then we'll be creating a globally shared version.
|
||||
if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
|
||||
|| !instance.def.generates_cgu_internal_copy(tcx)
|
||||
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
|
||||
{
|
||||
|
|
@ -102,7 +102,7 @@ impl<'tcx> MonoItem<'tcx> {
|
|||
|
||||
// At this point we don't have explicit linkage and we're an
|
||||
// inlined function. If we're inlining into all CGUs then we'll
|
||||
// be creating a local copy per CGU
|
||||
// be creating a local copy per CGU.
|
||||
if generate_cgu_internal_copies {
|
||||
return InstantiationMode::LocalCopy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||
values: values.clone(),
|
||||
targets: targets.clone(),
|
||||
},
|
||||
Drop { ref location, target, unwind } => {
|
||||
Drop { location: location.fold_with(folder), target, unwind }
|
||||
Drop { ref place, target, unwind } => {
|
||||
Drop { place: place.fold_with(folder), target, unwind }
|
||||
}
|
||||
DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
|
||||
location: location.fold_with(folder),
|
||||
DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace {
|
||||
place: place.fold_with(folder),
|
||||
value: value.fold_with(folder),
|
||||
target,
|
||||
unwind,
|
||||
|
|
@ -97,9 +97,9 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||
SwitchInt { ref discr, switch_ty, .. } => {
|
||||
discr.visit_with(visitor) || switch_ty.visit_with(visitor)
|
||||
}
|
||||
Drop { ref location, .. } => location.visit_with(visitor),
|
||||
DropAndReplace { ref location, ref value, .. } => {
|
||||
location.visit_with(visitor) || value.visit_with(visitor)
|
||||
Drop { ref place, .. } => place.visit_with(visitor),
|
||||
DropAndReplace { ref place, ref value, .. } => {
|
||||
place.visit_with(visitor) || value.visit_with(visitor)
|
||||
}
|
||||
Yield { ref value, .. } => value.visit_with(visitor),
|
||||
Call { ref func, ref args, ref destination, .. } => {
|
||||
|
|
|
|||
|
|
@ -108,12 +108,6 @@ macro_rules! make_mir_visitor {
|
|||
self.super_terminator(terminator, location);
|
||||
}
|
||||
|
||||
fn visit_terminator_kind(&mut self,
|
||||
kind: & $($mutability)? TerminatorKind<'tcx>,
|
||||
location: Location) {
|
||||
self.super_terminator_kind(kind, location);
|
||||
}
|
||||
|
||||
fn visit_assert_message(&mut self,
|
||||
msg: & $($mutability)? AssertMessage<'tcx>,
|
||||
location: Location) {
|
||||
|
|
@ -417,12 +411,6 @@ macro_rules! make_mir_visitor {
|
|||
let Terminator { source_info, kind } = terminator;
|
||||
|
||||
self.visit_source_info(source_info);
|
||||
self.visit_terminator_kind(kind, location);
|
||||
}
|
||||
|
||||
fn super_terminator_kind(&mut self,
|
||||
kind: & $($mutability)? TerminatorKind<'tcx>,
|
||||
source_location: Location) {
|
||||
match kind {
|
||||
TerminatorKind::Goto { .. } |
|
||||
TerminatorKind::Resume |
|
||||
|
|
@ -440,7 +428,7 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_local(
|
||||
& $($mutability)? local,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
|
||||
source_location,
|
||||
location,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -456,34 +444,34 @@ macro_rules! make_mir_visitor {
|
|||
values: _,
|
||||
targets: _
|
||||
} => {
|
||||
self.visit_operand(discr, source_location);
|
||||
self.visit_ty(switch_ty, TyContext::Location(source_location));
|
||||
self.visit_operand(discr, location);
|
||||
self.visit_ty(switch_ty, TyContext::Location(location));
|
||||
}
|
||||
|
||||
TerminatorKind::Drop {
|
||||
location,
|
||||
place,
|
||||
target: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
self.visit_place(
|
||||
location,
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop),
|
||||
source_location
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
TerminatorKind::DropAndReplace {
|
||||
location,
|
||||
place,
|
||||
value,
|
||||
target: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
self.visit_place(
|
||||
location,
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop),
|
||||
source_location
|
||||
location
|
||||
);
|
||||
self.visit_operand(value, source_location);
|
||||
self.visit_operand(value, location);
|
||||
}
|
||||
|
||||
TerminatorKind::Call {
|
||||
|
|
@ -494,15 +482,15 @@ macro_rules! make_mir_visitor {
|
|||
from_hir_call: _,
|
||||
fn_span: _
|
||||
} => {
|
||||
self.visit_operand(func, source_location);
|
||||
self.visit_operand(func, location);
|
||||
for arg in args {
|
||||
self.visit_operand(arg, source_location);
|
||||
self.visit_operand(arg, location);
|
||||
}
|
||||
if let Some((destination, _)) = destination {
|
||||
self.visit_place(
|
||||
destination,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Call),
|
||||
source_location
|
||||
location
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -514,8 +502,8 @@ macro_rules! make_mir_visitor {
|
|||
target: _,
|
||||
cleanup: _,
|
||||
} => {
|
||||
self.visit_operand(cond, source_location);
|
||||
self.visit_assert_message(msg, source_location);
|
||||
self.visit_operand(cond, location);
|
||||
self.visit_assert_message(msg, location);
|
||||
}
|
||||
|
||||
TerminatorKind::Yield {
|
||||
|
|
@ -524,11 +512,11 @@ macro_rules! make_mir_visitor {
|
|||
resume_arg,
|
||||
drop: _,
|
||||
} => {
|
||||
self.visit_operand(value, source_location);
|
||||
self.visit_operand(value, location);
|
||||
self.visit_place(
|
||||
resume_arg,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Yield),
|
||||
source_location,
|
||||
location,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -543,29 +531,29 @@ macro_rules! make_mir_visitor {
|
|||
match op {
|
||||
InlineAsmOperand::In { value, .. }
|
||||
| InlineAsmOperand::Const { value } => {
|
||||
self.visit_operand(value, source_location);
|
||||
self.visit_operand(value, location);
|
||||
}
|
||||
InlineAsmOperand::Out { place, .. } => {
|
||||
if let Some(place) = place {
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
source_location,
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::InOut { in_value, out_place, .. } => {
|
||||
self.visit_operand(in_value, source_location);
|
||||
self.visit_operand(in_value, location);
|
||||
if let Some(out_place) = out_place {
|
||||
self.visit_place(
|
||||
out_place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
source_location,
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SymFn { value } => {
|
||||
self.visit_constant(value, source_location);
|
||||
self.visit_constant(value, location);
|
||||
}
|
||||
InlineAsmOperand::SymStatic { def_id: _ } => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
| ty::Ref(..)
|
||||
| ty::Str
|
||||
| ty::Foreign(..)
|
||||
| ty::Error => true,
|
||||
| ty::Error(_) => true,
|
||||
|
||||
// [T; N] and [T] have same properties as T.
|
||||
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl TypeRelation<'tcx> for Match<'tcx> {
|
|||
Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
|
||||
}
|
||||
|
||||
(&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().types.err),
|
||||
(&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()),
|
||||
|
||||
_ => relate::super_relate_tys(self, a, b),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ use rustc_session::lint::{Level, Lint};
|
|||
use rustc_session::Session;
|
||||
use rustc_span::source_map::MultiSpan;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
|
|
@ -145,7 +145,6 @@ pub struct CommonTypes<'tcx> {
|
|||
pub f64: Ty<'tcx>,
|
||||
pub never: Ty<'tcx>,
|
||||
pub self_param: Ty<'tcx>,
|
||||
pub err: Ty<'tcx>,
|
||||
|
||||
/// Dummy type used for the `Self` of a `TraitRef` created for converting
|
||||
/// a trait object, and which gets removed in `ExistentialTraitRef`.
|
||||
|
|
@ -803,7 +802,6 @@ impl<'tcx> CommonTypes<'tcx> {
|
|||
bool: mk(Bool),
|
||||
char: mk(Char),
|
||||
never: mk(Never),
|
||||
err: mk(Error),
|
||||
isize: mk(Int(ast::IntTy::Isize)),
|
||||
i8: mk(Int(ast::IntTy::I8)),
|
||||
i16: mk(Int(ast::IntTy::I16)),
|
||||
|
|
@ -1142,6 +1140,31 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
|
||||
#[track_caller]
|
||||
pub fn ty_error(self) -> Ty<'tcx> {
|
||||
self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported")
|
||||
}
|
||||
|
||||
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
|
||||
/// ensure it gets used.
|
||||
#[track_caller]
|
||||
pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
|
||||
self.sess.delay_span_bug(span, msg);
|
||||
self.mk_ty(Error(super::sty::DelaySpanBugEmitted(())))
|
||||
}
|
||||
|
||||
/// Like `err` but for constants.
|
||||
#[track_caller]
|
||||
pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
|
||||
self.sess
|
||||
.delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported.");
|
||||
self.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Error(super::sty::DelaySpanBugEmitted(())),
|
||||
ty,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
|
||||
let cname = self.crate_name(LOCAL_CRATE).as_str();
|
||||
self.sess.consider_optimizing(&cname, msg)
|
||||
|
|
@ -1382,7 +1405,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> {
|
||||
pub fn return_type_impl_or_dyn_trait(
|
||||
&self,
|
||||
scope_def_id: DefId,
|
||||
) -> Option<&'tcx hir::Ty<'tcx>> {
|
||||
let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
|
||||
let hir_output = match self.hir().get(hir_id) {
|
||||
Node::Item(hir::Item {
|
||||
|
|
@ -1428,15 +1454,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let output = self.erase_late_bound_regions(&sig.output());
|
||||
if output.is_impl_trait() {
|
||||
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
|
||||
Some((fn_decl.output.span(), false))
|
||||
if let hir::FnRetTy::Return(ty) = fn_decl.output {
|
||||
return Some(ty);
|
||||
}
|
||||
} else {
|
||||
let mut v = TraitObjectVisitor(vec![]);
|
||||
rustc_hir::intravisit::walk_ty(&mut v, hir_output);
|
||||
if v.0.len() == 1 {
|
||||
return Some((v.0[0], true));
|
||||
return Some(v.0[0]);
|
||||
}
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -1845,7 +1873,7 @@ macro_rules! sty_debug_print {
|
|||
let variant = match t.kind {
|
||||
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
|
||||
ty::Float(..) | ty::Str | ty::Never => continue,
|
||||
ty::Error => /* unimportant */ continue,
|
||||
ty::Error(_) => /* unimportant */ continue,
|
||||
$(ty::$variant(..) => &mut $variant,)*
|
||||
};
|
||||
let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
|
||||
|
|
|
|||
|
|
@ -236,21 +236,24 @@ pub fn suggest_constraining_type_param(
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TraitObjectVisitor(pub Vec<rustc_span::Span>);
|
||||
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor {
|
||||
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
|
||||
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
|
||||
type Map = rustc_hir::intravisit::ErasedMap<'v>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
|
||||
hir::intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||
if let hir::TyKind::TraitObject(
|
||||
_,
|
||||
hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
|
||||
hir::Lifetime {
|
||||
name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
|
||||
..
|
||||
},
|
||||
) = ty.kind
|
||||
{
|
||||
self.0.push(ty.span);
|
||||
self.0.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -286,14 +286,14 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
ty::Projection(_) => "associated type".into(),
|
||||
ty::Param(p) => format!("type parameter `{}`", p).into(),
|
||||
ty::Opaque(..) => "opaque type".into(),
|
||||
ty::Error => "type error".into(),
|
||||
ty::Error(_) => "type error".into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prefix_string(&self) -> Cow<'static, str> {
|
||||
match self.kind {
|
||||
ty::Infer(_)
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ pub fn simplify_type(
|
|||
}
|
||||
ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
|
||||
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
|
||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None,
|
||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ impl FlagComputation {
|
|||
| &ty::Str
|
||||
| &ty::Foreign(..) => {}
|
||||
|
||||
&ty::Error => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
&ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
|
||||
&ty::Param(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_PARAM);
|
||||
|
|
@ -227,7 +227,7 @@ impl FlagComputation {
|
|||
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||
}
|
||||
ty::ConstKind::Value(_) => {}
|
||||
ty::ConstKind::Error => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -974,13 +974,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
return Ok(tcx.intern_layout(Layout {
|
||||
variants: Variants::Multiple {
|
||||
discr: niche_scalar,
|
||||
discr_kind: DiscriminantKind::Niche {
|
||||
tag: niche_scalar,
|
||||
tag_encoding: TagEncoding::Niche {
|
||||
dataful_variant: i,
|
||||
niche_variants,
|
||||
niche_start,
|
||||
},
|
||||
discr_index: 0,
|
||||
tag_field: 0,
|
||||
variants: st,
|
||||
},
|
||||
fields: FieldsShape::Arbitrary {
|
||||
|
|
@ -1216,9 +1216,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
tcx.intern_layout(Layout {
|
||||
variants: Variants::Multiple {
|
||||
discr: tag,
|
||||
discr_kind: DiscriminantKind::Tag,
|
||||
discr_index: 0,
|
||||
tag,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
tag_field: 0,
|
||||
variants: layout_variants,
|
||||
},
|
||||
fields: FieldsShape::Arbitrary {
|
||||
|
|
@ -1245,7 +1245,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
bug!("Layout::compute: unexpected type `{}`", ty)
|
||||
}
|
||||
|
||||
ty::Param(_) | ty::Error => {
|
||||
ty::Param(_) | ty::Error(_) => {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
}
|
||||
})
|
||||
|
|
@ -1399,15 +1399,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
// Build a prefix layout, including "promoting" all ineligible
|
||||
// locals as part of the prefix. We compute the layout of all of
|
||||
// these fields at once to get optimal packing.
|
||||
let discr_index = substs.as_generator().prefix_tys().count();
|
||||
let tag_index = substs.as_generator().prefix_tys().count();
|
||||
|
||||
// `info.variant_fields` already accounts for the reserved variants, so no need to add them.
|
||||
let max_discr = (info.variant_fields.len() - 1) as u128;
|
||||
let discr_int = Integer::fit_unsigned(max_discr);
|
||||
let discr_int_ty = discr_int.to_ty(tcx, false);
|
||||
let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
|
||||
let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone()));
|
||||
let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout };
|
||||
let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
|
||||
let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
|
||||
let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
|
||||
|
||||
let promoted_layouts = ineligible_locals
|
||||
.iter()
|
||||
|
|
@ -1418,7 +1418,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
.as_generator()
|
||||
.prefix_tys()
|
||||
.map(|ty| self.layout_of(ty))
|
||||
.chain(iter::once(Ok(discr_layout)))
|
||||
.chain(iter::once(Ok(tag_layout)))
|
||||
.chain(promoted_layouts)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let prefix = self.univariant_uninterned(
|
||||
|
|
@ -1441,7 +1441,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
|
||||
// "outer" and "promoted" fields respectively.
|
||||
let b_start = (discr_index + 1) as u32;
|
||||
let b_start = (tag_index + 1) as u32;
|
||||
let offsets_b = offsets.split_off(b_start as usize);
|
||||
let offsets_a = offsets;
|
||||
|
||||
|
|
@ -1558,9 +1558,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
let layout = tcx.intern_layout(Layout {
|
||||
variants: Variants::Multiple {
|
||||
discr,
|
||||
discr_kind: DiscriminantKind::Tag,
|
||||
discr_index,
|
||||
tag: tag,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
tag_field: tag_index,
|
||||
variants,
|
||||
},
|
||||
fields: outer_fields,
|
||||
|
|
@ -1680,7 +1680,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
Variants::Multiple { ref discr, ref discr_kind, .. } => {
|
||||
Variants::Multiple { ref tag, ref tag_encoding, .. } => {
|
||||
debug!(
|
||||
"print-type-size `{:#?}` adt general variants def {}",
|
||||
layout.ty,
|
||||
|
|
@ -1702,8 +1702,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
record(
|
||||
adt_kind.into(),
|
||||
adt_packed,
|
||||
match discr_kind {
|
||||
DiscriminantKind::Tag => Some(discr.value.size(self)),
|
||||
match tag_encoding {
|
||||
TagEncoding::Direct => Some(tag.value.size(self)),
|
||||
_ => None,
|
||||
},
|
||||
variant_infos,
|
||||
|
|
@ -2028,11 +2028,11 @@ where
|
|||
|
||||
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
|
||||
let tcx = cx.tcx();
|
||||
let discr_layout = |discr: &Scalar| -> C::TyAndLayout {
|
||||
let layout = Layout::scalar(cx, discr.clone());
|
||||
let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
|
||||
let layout = Layout::scalar(cx, tag.clone());
|
||||
MaybeResult::from(Ok(TyAndLayout {
|
||||
layout: tcx.intern_layout(layout),
|
||||
ty: discr.value.to_ty(tcx),
|
||||
ty: tag.value.to_ty(tcx),
|
||||
}))
|
||||
};
|
||||
|
||||
|
|
@ -2109,9 +2109,9 @@ where
|
|||
.unwrap()
|
||||
.nth(i)
|
||||
.unwrap(),
|
||||
Variants::Multiple { ref discr, discr_index, .. } => {
|
||||
if i == discr_index {
|
||||
return discr_layout(discr);
|
||||
Variants::Multiple { ref tag, tag_field, .. } => {
|
||||
if i == tag_field {
|
||||
return tag_layout(tag);
|
||||
}
|
||||
substs.as_generator().prefix_tys().nth(i).unwrap()
|
||||
}
|
||||
|
|
@ -2128,9 +2128,9 @@ where
|
|||
Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
|
||||
|
||||
// Discriminant field for enums (where applicable).
|
||||
Variants::Multiple { ref discr, .. } => {
|
||||
Variants::Multiple { ref tag, .. } => {
|
||||
assert_eq!(i, 0);
|
||||
return discr_layout(discr);
|
||||
return tag_layout(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2141,7 +2141,7 @@ where
|
|||
| ty::Opaque(..)
|
||||
| ty::Param(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Error => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
|
||||
| ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -2207,10 +2207,10 @@ where
|
|||
// using more niches than just null (e.g., the first page of
|
||||
// the address space, or unaligned pointers).
|
||||
Variants::Multiple {
|
||||
discr_kind: DiscriminantKind::Niche { dataful_variant, .. },
|
||||
discr_index,
|
||||
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
|
||||
tag_field,
|
||||
..
|
||||
} if this.fields.offset(discr_index) == offset => {
|
||||
} if this.fields.offset(tag_field) == offset => {
|
||||
Some(this.for_variant(cx, dataful_variant))
|
||||
}
|
||||
_ => Some(this),
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
|
|||
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
|
||||
ty::Placeholder(..) |
|
||||
ty::Bound(..) |
|
||||
ty::Error => {
|
||||
ty::Error(_) => {
|
||||
// (*) Function pointers and trait objects are both binders.
|
||||
// In the RFC, this means we would add the bound regions to
|
||||
// the "bound regions list". In our representation, no such
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
|
|||
| ty::Opaque(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Never
|
||||
| ty::Float(_) => None,
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ impl DefPathBasedNames<'tcx> {
|
|||
let substs = substs.truncate_to(self.tcx, generics);
|
||||
self.push_generic_params(substs, iter::empty(), output, debug);
|
||||
}
|
||||
ty::Error
|
||||
ty::Error(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||
p!(write("{}", infer_ty))
|
||||
}
|
||||
}
|
||||
ty::Error => p!(write("[type error]")),
|
||||
ty::Error(_) => p!(write("[type error]")),
|
||||
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
|
||||
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
|
||||
ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
|
||||
|
|
@ -919,7 +919,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||
self.pretty_print_bound_var(debruijn, bound_var)?
|
||||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
|
||||
ty::ConstKind::Error => p!(write("[const error]")),
|
||||
ty::ConstKind::Error(_) => p!(write("[const error]")),
|
||||
};
|
||||
Ok(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl<'tcx> Value<'tcx> for &'_ TyS<'_> {
|
|||
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
|
||||
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
|
||||
// FIXME: Represent the above fact in the trait system somehow.
|
||||
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.types.err) }
|
||||
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> {
|
|||
// FIXME: Represent the above fact in the trait system somehow.
|
||||
unsafe {
|
||||
std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
|
||||
AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])),
|
||||
AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
|
|||
bug!("bound types encountered in super_relate_tys")
|
||||
}
|
||||
|
||||
(&ty::Error, _) | (_, &ty::Error) => Ok(tcx.types.err),
|
||||
(&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(tcx.ty_error()),
|
||||
|
||||
(&ty::Never, _)
|
||||
| (&ty::Char, _)
|
||||
|
|
@ -524,7 +524,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
|
|||
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
|
||||
}
|
||||
|
||||
(ty::ConstKind::Error, _) | (_, ty::ConstKind::Error) => Ok(ty::ConstKind::Error),
|
||||
(ty::ConstKind::Error(d), _) | (_, ty::ConstKind::Error(d)) => Ok(ty::ConstKind::Error(d)),
|
||||
|
||||
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
|
||||
return Ok(a);
|
||||
|
|
|
|||
|
|
@ -911,7 +911,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
|
|||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Param(..)
|
||||
| ty::Bound(..)
|
||||
|
|
@ -952,7 +952,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
|
|||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
|
|
@ -1051,7 +1051,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
|
|||
ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Placeholder(..)
|
||||
| ty::ConstKind::Error => *self,
|
||||
| ty::ConstKind::Error(_) => *self,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1063,7 +1063,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
|
|||
ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Error => false,
|
||||
| ty::ConstKind::Error(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,9 +203,15 @@ pub enum TyKind<'tcx> {
|
|||
|
||||
/// A placeholder for a type which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
Error,
|
||||
Error(DelaySpanBugEmitted),
|
||||
}
|
||||
|
||||
/// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
|
||||
/// except through `tcx.err*()`.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
#[derive(RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct DelaySpanBugEmitted(pub(super) ());
|
||||
|
||||
// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static_assert_size!(TyKind<'_>, 24);
|
||||
|
|
@ -1984,7 +1990,7 @@ impl<'tcx> TyS<'tcx> {
|
|||
#[inline]
|
||||
pub fn has_concrete_skeleton(&self) -> bool {
|
||||
match self.kind {
|
||||
Param(_) | Infer(_) | Error => false,
|
||||
Param(_) | Infer(_) | Error(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
@ -2016,7 +2022,7 @@ impl<'tcx> TyS<'tcx> {
|
|||
match self.kind {
|
||||
FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs),
|
||||
FnPtr(f) => f,
|
||||
Error => {
|
||||
Error(_) => {
|
||||
// ignore errors (#54954)
|
||||
ty::Binder::dummy(FnSig::fake())
|
||||
}
|
||||
|
|
@ -2140,7 +2146,7 @@ impl<'tcx> TyS<'tcx> {
|
|||
// closure type is not yet known
|
||||
Bound(..) | Infer(_) => None,
|
||||
|
||||
Error => Some(ty::ClosureKind::Fn),
|
||||
Error(_) => Some(ty::ClosureKind::Fn),
|
||||
|
||||
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
|
||||
}
|
||||
|
|
@ -2167,7 +2173,7 @@ impl<'tcx> TyS<'tcx> {
|
|||
| ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Error => true,
|
||||
| ty::Error(_) => true,
|
||||
|
||||
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false,
|
||||
|
||||
|
|
@ -2372,9 +2378,7 @@ impl<'tcx> Const<'tcx> {
|
|||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Const::from_value(tcx, val, self.ty),
|
||||
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
|
||||
Err(ErrorHandled::Reported(ErrorReported)) => {
|
||||
tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: self.ty })
|
||||
}
|
||||
Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty),
|
||||
}
|
||||
} else {
|
||||
self
|
||||
|
|
@ -2434,7 +2438,7 @@ pub enum ConstKind<'tcx> {
|
|||
|
||||
/// A placeholder for a const which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
Error,
|
||||
Error(DelaySpanBugEmitted),
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
if let ty::Adt(def, substs) = ty.kind {
|
||||
for field in def.all_fields() {
|
||||
let field_ty = field.ty(self, substs);
|
||||
if let Error = field_ty.kind {
|
||||
if let Error(_) = field_ty.kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -731,7 +731,7 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
| ty::Ref(..)
|
||||
| ty::RawPtr(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::FnPtr(_) => true,
|
||||
ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze),
|
||||
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
|
||||
|
|
@ -826,7 +826,7 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
// called for known, fully-monomorphized types.
|
||||
Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false,
|
||||
|
||||
Foreign(_) | GeneratorWitness(..) | Error => false,
|
||||
Foreign(_) | GeneratorWitness(..) | Error(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1109,7 +1109,7 @@ pub fn needs_drop_components(
|
|||
// Foreign types can never have destructors.
|
||||
ty::Foreign(..) => Ok(SmallVec::new()),
|
||||
|
||||
ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop),
|
||||
ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
|
||||
|
||||
ty::Slice(ty) => needs_drop_components(ty, target_layout),
|
||||
ty::Array(elem_ty, size) => {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
| ty::Infer(_)
|
||||
| ty::Param(_)
|
||||
| ty::Never
|
||||
| ty::Error
|
||||
| ty::Error(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Foreign(..) => {}
|
||||
|
|
@ -171,7 +171,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Error => {}
|
||||
| ty::ConstKind::Error(_) => {}
|
||||
|
||||
ty::ConstKind::Unevaluated(_, substs, _) => {
|
||||
stack.extend(substs.iter().rev());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_data_structures::graph::dominators::Dominators;
|
|||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
|
||||
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
|
||||
use rustc_middle::mir::{InlineAsmOperand, TerminatorKind};
|
||||
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||
use rustc_middle::mir::{Statement, StatementKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
|
|
@ -112,14 +112,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
self.super_statement(statement, location);
|
||||
}
|
||||
|
||||
fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
|
||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||
self.check_activations(location);
|
||||
|
||||
match kind {
|
||||
match &terminator.kind {
|
||||
TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
|
||||
self.consume_operand(location, discr);
|
||||
}
|
||||
TerminatorKind::Drop { location: drop_place, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
|
||||
self.access_place(
|
||||
location,
|
||||
*drop_place,
|
||||
|
|
@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
TerminatorKind::DropAndReplace {
|
||||
location: drop_place,
|
||||
place: drop_place,
|
||||
value: ref new_value,
|
||||
target: _,
|
||||
unwind: _,
|
||||
|
|
@ -222,7 +222,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.super_terminator_kind(kind, location);
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
|
|||
TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
|
||||
self.consume_operand(loc, (discr, span), flow_state);
|
||||
}
|
||||
TerminatorKind::Drop { location: ref drop_place, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
// Compute the type with accurate region information.
|
||||
|
|
@ -692,7 +692,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
|
|||
);
|
||||
}
|
||||
TerminatorKind::DropAndReplace {
|
||||
location: drop_place,
|
||||
place: drop_place,
|
||||
value: ref new_value,
|
||||
target: _,
|
||||
unwind: _,
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
|||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
|
||||
(self.infcx.tcx.types.err, None)
|
||||
(self.infcx.tcx.ty_error(), None)
|
||||
});
|
||||
let constraints2 = self.add_implied_bounds(ty);
|
||||
normalized_inputs_and_output.push(ty);
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
if place_ty.variant_index.is_none() {
|
||||
if place_ty.ty.references_error() {
|
||||
assert!(self.errors_reported);
|
||||
return PlaceTy::from_ty(self.tcx().types.err);
|
||||
return PlaceTy::from_ty(self.tcx().ty_error());
|
||||
}
|
||||
}
|
||||
place_ty = self.sanitize_projection(place_ty, elem, place, location)
|
||||
|
|
@ -725,7 +725,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
fn error(&mut self) -> Ty<'tcx> {
|
||||
self.errors_reported = true;
|
||||
self.tcx().types.err
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
|
||||
fn field_ty(
|
||||
|
|
@ -1558,8 +1558,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// no checks needed for these
|
||||
}
|
||||
|
||||
TerminatorKind::DropAndReplace { ref location, ref value, target: _, unwind: _ } => {
|
||||
let place_ty = location.ty(body, tcx).ty;
|
||||
TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => {
|
||||
let place_ty = place.ty(body, tcx).ty;
|
||||
let rv_ty = value.ty(body, tcx);
|
||||
|
||||
let locations = term_location.to_locations();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind};
|
||||
use rustc_middle::mir::{
|
||||
Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
|
|
@ -62,20 +64,22 @@ impl GatherUsedMutsVisitor<'_, '_, '_> {
|
|||
}
|
||||
|
||||
impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
|
||||
fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, _location: Location) {
|
||||
debug!("visit_terminator_kind: kind={:?}", kind);
|
||||
match &kind {
|
||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||
debug!("visit_terminator: terminator={:?}", terminator);
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Call { destination: Some((into, _)), .. } => {
|
||||
self.remove_never_initialized_mut_locals(*into);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { location, .. } => {
|
||||
self.remove_never_initialized_mut_locals(*location);
|
||||
TerminatorKind::DropAndReplace { place, .. } => {
|
||||
self.remove_never_initialized_mut_locals(*place);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
if let StatementKind::Assign(box (into, _)) = &statement.kind {
|
||||
debug!(
|
||||
"visit_statement: statement={:?} local={:?} \
|
||||
|
|
@ -84,6 +88,8 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
|||
);
|
||||
self.remove_never_initialized_mut_locals(*into);
|
||||
}
|
||||
|
||||
self.super_statement(statement, location);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
|
||||
|
|
|
|||
|
|
@ -441,8 +441,8 @@ impl Direction for Forward {
|
|||
Goto { target } => propagate(target, exit_state),
|
||||
|
||||
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
|
||||
| Drop { target, unwind, location: _ }
|
||||
| DropAndReplace { target, unwind, value: _, location: _ }
|
||||
| Drop { target, unwind, place: _ }
|
||||
| DropAndReplace { target, unwind, value: _, place: _ }
|
||||
| FalseUnwind { real_target: target, unwind } => {
|
||||
if let Some(unwind) = unwind {
|
||||
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
|
||||
|
|
|
|||
|
|
@ -189,8 +189,8 @@ where
|
|||
self.super_terminator(terminator, location);
|
||||
|
||||
match terminator.kind {
|
||||
mir::TerminatorKind::Drop { location: dropped_place, .. }
|
||||
| mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
|
||||
mir::TerminatorKind::Drop { place: dropped_place, .. }
|
||||
| mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
||||
// See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
|
||||
if !self.ignore_borrow_on_drop {
|
||||
self.trans.gen(dropped_place.local);
|
||||
|
|
|
|||
|
|
@ -387,13 +387,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
self.gather_init(place.as_ref(), InitKind::Deep);
|
||||
}
|
||||
|
||||
TerminatorKind::Drop { location, target: _, unwind: _ } => {
|
||||
self.gather_move(location);
|
||||
TerminatorKind::Drop { place, target: _, unwind: _ } => {
|
||||
self.gather_move(place);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { location, ref value, .. } => {
|
||||
self.create_move_path(location);
|
||||
TerminatorKind::DropAndReplace { place, ref value, .. } => {
|
||||
self.create_move_path(place);
|
||||
self.gather_operand(value);
|
||||
self.gather_init(location.as_ref(), InitKind::Deep);
|
||||
self.gather_init(place.as_ref(), InitKind::Deep);
|
||||
}
|
||||
TerminatorKind::Call {
|
||||
ref func,
|
||||
|
|
|
|||
|
|
@ -293,7 +293,6 @@ pub enum InternKind {
|
|||
Static(hir::Mutability),
|
||||
Constant,
|
||||
Promoted,
|
||||
ConstProp,
|
||||
}
|
||||
|
||||
/// Intern `ret` and everything it references.
|
||||
|
|
@ -314,9 +313,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
|||
let base_intern_mode = match intern_kind {
|
||||
InternKind::Static(mutbl) => InternMode::Static(mutbl),
|
||||
// FIXME: what about array lengths, array initializers?
|
||||
InternKind::Constant | InternKind::ConstProp | InternKind::Promoted => {
|
||||
InternMode::ConstBase
|
||||
}
|
||||
InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
|
||||
};
|
||||
|
||||
// Type based interning.
|
||||
|
|
@ -358,7 +355,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
|||
Err(error) => {
|
||||
ecx.tcx.sess.delay_span_bug(
|
||||
ecx.tcx.span,
|
||||
"error during interning should later cause validation failure",
|
||||
&format!(
|
||||
"error during interning should later cause validation failure: {}",
|
||||
error
|
||||
),
|
||||
);
|
||||
// Some errors shouldn't come up because creating them causes
|
||||
// an allocation, which we should avoid. When that happens,
|
||||
|
|
@ -399,7 +399,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
|||
// immutability is so important.
|
||||
alloc.mutability = Mutability::Not;
|
||||
}
|
||||
InternKind::Constant | InternKind::ConstProp => {
|
||||
InternKind::Constant => {
|
||||
// If it's a constant, we should not have any "leftovers" as everything
|
||||
// is tracked by const-checking.
|
||||
// FIXME: downgrade this to a warning? It rejects some legitimate consts,
|
||||
|
|
|
|||
|
|
@ -389,6 +389,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
);
|
||||
self.copy_op(self.operand_index(args[0], index)?, dest)?;
|
||||
}
|
||||
// FIXME(#73156): Handle source code coverage in const eval
|
||||
sym::count_code_region => (),
|
||||
_ => return Ok(false),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
|||
| ty::Dynamic(_, _) => self.pretty_print_type(ty),
|
||||
|
||||
// Placeholders (all printed as `_` to uniformize them).
|
||||
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => {
|
||||
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
|
||||
write!(self, "_")?;
|
||||
Ok(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
|
|||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
|
||||
use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
|
||||
use rustc_target::abi::{VariantIdx, Variants};
|
||||
|
||||
use super::{
|
||||
|
|
@ -527,7 +527,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Early-return cases.
|
||||
let val_val = match val.val {
|
||||
ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
|
||||
ty::ConstKind::Error => throw_inval!(TypeckError(ErrorReported)),
|
||||
ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
// We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
|
||||
|
|
@ -587,7 +587,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
op: OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
|
||||
trace!("read_discriminant_value {:#?}", op.layout);
|
||||
|
||||
// Get type and layout of the discriminant.
|
||||
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
|
||||
trace!("discriminant type: {:?}", discr_layout.ty);
|
||||
|
|
@ -596,10 +595,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// This is not to be confused with its "variant index", which is just determining its position in the
|
||||
// declared list of variants -- they can differ with explicitly assigned discriminants.
|
||||
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
|
||||
// straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
|
||||
// Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
|
||||
// rather confusing.
|
||||
let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
|
||||
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
|
||||
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
|
||||
Variants::Single { index } => {
|
||||
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
|
||||
Some(discr) => {
|
||||
|
|
@ -615,8 +612,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
};
|
||||
return Ok((discr, index));
|
||||
}
|
||||
Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
|
||||
(discr, discr_kind, discr_index)
|
||||
Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
|
||||
(tag, tag_encoding, tag_field)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -633,21 +630,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
|
||||
|
||||
// Read tag and sanity-check `tag_layout`.
|
||||
let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
|
||||
let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
|
||||
assert_eq!(tag_layout.size, tag_val.layout.size);
|
||||
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
|
||||
let tag_val = tag_val.to_scalar()?;
|
||||
trace!("tag value: {:?}", tag_val);
|
||||
|
||||
// Figure out which discriminant and variant this corresponds to.
|
||||
Ok(match *tag_kind {
|
||||
DiscriminantKind::Tag => {
|
||||
Ok(match *tag_encoding {
|
||||
TagEncoding::Direct => {
|
||||
let tag_bits = self
|
||||
.force_bits(tag_val, tag_layout.size)
|
||||
.map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
|
||||
.map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?;
|
||||
// Cast bits from tag layout to discriminant layout.
|
||||
let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
|
||||
let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
|
||||
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
|
||||
let discr_bits = discr_val.assert_bits(discr_layout.size);
|
||||
// Convert discriminant to variant index, and catch invalid discriminants.
|
||||
let index = match op.layout.ty.kind {
|
||||
ty::Adt(adt, _) => {
|
||||
|
|
@ -661,11 +658,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
_ => bug!("tagged layout for non-adt non-generator"),
|
||||
}
|
||||
.ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
|
||||
.ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?;
|
||||
// Return the cast value, and the index.
|
||||
(discr_val_cast, index.0)
|
||||
(discr_val, index.0)
|
||||
}
|
||||
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
|
||||
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
|
||||
// Compute the variant this niche value/"tag" corresponds to. With niche layout,
|
||||
// discriminant (encoded in niche/tag) and variant index are the same.
|
||||
let variants_start = niche_variants.start().as_u32();
|
||||
|
|
@ -677,7 +674,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
&& variants_start == variants_end
|
||||
&& !self.memory.ptr_may_be_null(ptr);
|
||||
if !ptr_valid {
|
||||
throw_ub!(InvalidDiscriminant(tag_val.erase_tag()))
|
||||
throw_ub!(InvalidTag(tag_val.erase_tag()))
|
||||
}
|
||||
dataful_variant
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_macros::HashStable;
|
|||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape};
|
||||
use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
|
||||
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
|
||||
|
||||
use super::{
|
||||
|
|
@ -1045,7 +1045,8 @@ where
|
|||
MPlaceTy { mplace, layout }
|
||||
}
|
||||
|
||||
pub fn write_discriminant_index(
|
||||
/// Writes the discriminant of the given variant.
|
||||
pub fn write_discriminant(
|
||||
&mut self,
|
||||
variant_index: VariantIdx,
|
||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||
|
|
@ -1061,9 +1062,9 @@ where
|
|||
assert_eq!(index, variant_index);
|
||||
}
|
||||
Variants::Multiple {
|
||||
discr_kind: DiscriminantKind::Tag,
|
||||
discr: ref discr_layout,
|
||||
discr_index,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
tag: ref tag_layout,
|
||||
tag_field,
|
||||
..
|
||||
} => {
|
||||
// No need to validate that the discriminant here because the
|
||||
|
|
@ -1075,17 +1076,17 @@ where
|
|||
// raw discriminants for enums are isize or bigger during
|
||||
// their computation, but the in-memory tag is the smallest possible
|
||||
// representation
|
||||
let size = discr_layout.value.size(self);
|
||||
let discr_val = truncate(discr_val, size);
|
||||
let size = tag_layout.value.size(self);
|
||||
let tag_val = truncate(discr_val, size);
|
||||
|
||||
let discr_dest = self.place_field(dest, discr_index)?;
|
||||
self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
|
||||
let tag_dest = self.place_field(dest, tag_field)?;
|
||||
self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
|
||||
}
|
||||
Variants::Multiple {
|
||||
discr_kind:
|
||||
DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
|
||||
discr: ref discr_layout,
|
||||
discr_index,
|
||||
tag_encoding:
|
||||
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
|
||||
tag: ref tag_layout,
|
||||
tag_field,
|
||||
..
|
||||
} => {
|
||||
// No need to validate that the discriminant here because the
|
||||
|
|
@ -1098,19 +1099,19 @@ where
|
|||
.checked_sub(variants_start)
|
||||
.expect("overflow computing relative variant idx");
|
||||
// We need to use machine arithmetic when taking into account `niche_start`:
|
||||
// discr_val = variant_index_relative + niche_start_val
|
||||
let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
|
||||
// tag_val = variant_index_relative + niche_start_val
|
||||
let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
|
||||
let variant_index_relative_val =
|
||||
ImmTy::from_uint(variant_index_relative, discr_layout);
|
||||
let discr_val = self.binary_op(
|
||||
ImmTy::from_uint(variant_index_relative, tag_layout);
|
||||
let tag_val = self.binary_op(
|
||||
mir::BinOp::Add,
|
||||
variant_index_relative_val,
|
||||
niche_start_val,
|
||||
)?;
|
||||
// Write result.
|
||||
let niche_dest = self.place_field(dest, discr_index)?;
|
||||
self.write_immediate(*discr_val, niche_dest)?;
|
||||
let niche_dest = self.place_field(dest, tag_field)?;
|
||||
self.write_immediate(*tag_val, niche_dest)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
SetDiscriminant { place, variant_index } => {
|
||||
let dest = self.eval_place(**place)?;
|
||||
self.write_discriminant_index(*variant_index, dest)?;
|
||||
self.write_discriminant(*variant_index, dest)?;
|
||||
}
|
||||
|
||||
// Mark locals as alive
|
||||
|
|
@ -179,7 +179,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Aggregate(ref kind, ref operands) => {
|
||||
let (dest, active_field_index) = match **kind {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
self.write_discriminant_index(variant_index, dest)?;
|
||||
self.write_discriminant(variant_index, dest)?;
|
||||
if adt_def.is_enum() {
|
||||
(self.place_downcast(dest, variant_index)?, active_field_index)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -91,10 +91,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
Drop { location, target, unwind } => {
|
||||
let place = self.eval_place(location)?;
|
||||
Drop { place, target, unwind } => {
|
||||
let place = self.eval_place(place)?;
|
||||
let ty = place.layout.ty;
|
||||
trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
|
||||
trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
|
||||
|
||||
let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
|
||||
self.drop_in_place(place, instance, target, unwind)?;
|
||||
|
|
|
|||
|
|
@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
|
||||
// First, check if we are projecting to a variant.
|
||||
match layout.variants {
|
||||
Variants::Multiple { discr_index, .. } => {
|
||||
if discr_index == field {
|
||||
Variants::Multiple { tag_field, .. } => {
|
||||
if tag_field == field {
|
||||
return match layout.ty.kind {
|
||||
ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
|
||||
ty::Generator(..) => PathElem::GeneratorTag,
|
||||
|
|
@ -561,7 +561,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
| ty::Generator(..) => Ok(false),
|
||||
// Some types only occur during typechecking, they have no layout.
|
||||
// We should not see them here and we could not check them anyway.
|
||||
ty::Error
|
||||
ty::Error(_)
|
||||
| ty::Infer(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
|
|
@ -697,8 +697,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||
try_validation!(
|
||||
self.walk_value(op),
|
||||
self.path,
|
||||
err_ub!(InvalidDiscriminant(val)) =>
|
||||
{ "{}", val } expected { "a valid enum discriminant" },
|
||||
err_ub!(InvalidTag(val)) =>
|
||||
{ "{}", val } expected { "a valid enum tag" },
|
||||
err_unsup!(ReadPointerAsBytes) =>
|
||||
{ "a pointer" } expected { "plain (non-pointer) bytes" },
|
||||
);
|
||||
|
|
|
|||
|
|
@ -624,19 +624,19 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
self.super_const(constant);
|
||||
}
|
||||
|
||||
fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
|
||||
debug!("visiting terminator {:?} @ {:?}", kind, location);
|
||||
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
|
||||
debug!("visiting terminator {:?} @ {:?}", terminator, location);
|
||||
|
||||
let tcx = self.tcx;
|
||||
match *kind {
|
||||
match terminator.kind {
|
||||
mir::TerminatorKind::Call { ref func, .. } => {
|
||||
let callee_ty = func.ty(self.body, tcx);
|
||||
let callee_ty = self.monomorphize(callee_ty);
|
||||
visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
|
||||
}
|
||||
mir::TerminatorKind::Drop { ref location, .. }
|
||||
| mir::TerminatorKind::DropAndReplace { ref location, .. } => {
|
||||
let ty = location.ty(self.body, self.tcx).ty;
|
||||
mir::TerminatorKind::Drop { ref place, .. }
|
||||
| mir::TerminatorKind::DropAndReplace { ref place, .. } => {
|
||||
let ty = place.ty(self.body, self.tcx).ty;
|
||||
let ty = self.monomorphize(ty);
|
||||
visit_drop_use(self.tcx, ty, true, self.output);
|
||||
}
|
||||
|
|
@ -671,7 +671,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
| mir::TerminatorKind::FalseUnwind { .. } => bug!(),
|
||||
}
|
||||
|
||||
self.super_terminator_kind(kind, location);
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
|
||||
fn visit_local(
|
||||
|
|
|
|||
|
|
@ -454,18 +454,11 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
|
|||
fn merge_codegen_units<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
|
||||
mut target_cgu_count: usize,
|
||||
target_cgu_count: usize,
|
||||
) {
|
||||
assert!(target_cgu_count >= 1);
|
||||
let codegen_units = &mut initial_partitioning.codegen_units;
|
||||
|
||||
if tcx.is_compiler_builtins(LOCAL_CRATE) {
|
||||
// Compiler builtins require some degree of control over how mono items
|
||||
// are partitioned into compilation units. Provide it by keeping the
|
||||
// original partitioning when compiling the compiler builtins crate.
|
||||
target_cgu_count = codegen_units.len();
|
||||
}
|
||||
|
||||
// Note that at this point in time the `codegen_units` here may not be in a
|
||||
// deterministic order (but we know they're deterministically the same set).
|
||||
// We want this merging to produce a deterministic ordering of codegen units
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@ impl CloneShimBuilder<'tcx> {
|
|||
self.block(
|
||||
vec![],
|
||||
TerminatorKind::Drop {
|
||||
location: self.tcx.mk_place_index(dest, beg),
|
||||
place: self.tcx.mk_place_index(dest, beg),
|
||||
target: BasicBlock::new(8),
|
||||
unwind: None,
|
||||
},
|
||||
|
|
@ -634,7 +634,7 @@ impl CloneShimBuilder<'tcx> {
|
|||
self.block(
|
||||
vec![],
|
||||
TerminatorKind::Drop {
|
||||
location: previous_field,
|
||||
place: previous_field,
|
||||
target: previous_cleanup,
|
||||
unwind: None,
|
||||
},
|
||||
|
|
@ -799,11 +799,7 @@ fn build_call_shim<'tcx>(
|
|||
block(
|
||||
&mut blocks,
|
||||
vec![],
|
||||
TerminatorKind::Drop {
|
||||
location: rcvr_place(),
|
||||
target: BasicBlock::new(2),
|
||||
unwind: None,
|
||||
},
|
||||
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None },
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
|
@ -814,11 +810,7 @@ fn build_call_shim<'tcx>(
|
|||
block(
|
||||
&mut blocks,
|
||||
vec![],
|
||||
TerminatorKind::Drop {
|
||||
location: rcvr_place(),
|
||||
target: BasicBlock::new(4),
|
||||
unwind: None,
|
||||
},
|
||||
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None },
|
||||
true,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ fn add_moves_for_packed_drops_patch<'tcx>(
|
|||
let terminator = data.terminator();
|
||||
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { location, .. }
|
||||
if util::is_disaligned(tcx, body, param_env, location) =>
|
||||
TerminatorKind::Drop { place, .. }
|
||||
if util::is_disaligned(tcx, body, param_env, place) =>
|
||||
{
|
||||
add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
|
||||
}
|
||||
|
|
@ -88,13 +88,13 @@ fn add_move_for_packed_drop<'tcx>(
|
|||
is_cleanup: bool,
|
||||
) {
|
||||
debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
|
||||
let (location, target, unwind) = match terminator.kind {
|
||||
TerminatorKind::Drop { ref location, target, unwind } => (location, target, unwind),
|
||||
let (place, target, unwind) = match terminator.kind {
|
||||
TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let source_info = terminator.source_info;
|
||||
let ty = location.ty(body, tcx).ty;
|
||||
let ty = place.ty(body, tcx).ty;
|
||||
let temp = patch.new_temp(ty, terminator.source_info.span);
|
||||
|
||||
let storage_dead_block = patch.new_block(BasicBlockData {
|
||||
|
|
@ -104,9 +104,9 @@ fn add_move_for_packed_drop<'tcx>(
|
|||
});
|
||||
|
||||
patch.add_statement(loc, StatementKind::StorageLive(temp));
|
||||
patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*location)));
|
||||
patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
|
||||
patch.patch_terminator(
|
||||
loc.block,
|
||||
TerminatorKind::Drop { location: Place::from(temp), target: storage_dead_block, unwind },
|
||||
TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
|
|||
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
|
||||
|
||||
match &terminator.kind {
|
||||
mir::TerminatorKind::Drop { location: dropped_place, .. } => {
|
||||
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
|
||||
if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
|
||||
return;
|
||||
|
|
|
|||
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