Merge pull request #5 from rust-lang/master

update from origin 2020-06-19
This commit is contained in:
Rich Kadel 2020-06-19 09:50:00 -07:00 committed by GitHub
commit 791ccccddc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
301 changed files with 3922 additions and 1889 deletions

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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)

View file

@ -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");
}

View file

@ -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()));
}
}

View file

@ -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,

View file

@ -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());

View file

@ -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);

View file

@ -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
}

View file

@ -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);
}

View file

@ -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<'_>) {

View file

@ -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"

View file

@ -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]) }
}
}

View file

@ -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 }

View file

@ -19,6 +19,7 @@ path = "../libcore/tests/lib.rs"
[[bench]]
name = "corebenches"
path = "../libcore/benches/lib.rs"
test = true
[dev-dependencies]
rand = "0.7"

View file

@ -1,3 +1,5 @@
// wasm32 does not support benches (no time).
#![cfg(not(target_arch = "wasm32"))]
#![feature(flt2dec)]
#![feature(test)]

View file

@ -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"),

View file

@ -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)
}

View file

@ -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")]

View file

@ -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
}

View file

@ -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())
}

View file

@ -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();
}

View file

@ -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.

View file

@ -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,

View file

@ -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);

View file

@ -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,
}),

View file

@ -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" => {

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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![]

View file

@ -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(..)

View file

@ -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) {

View file

@ -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 } => {

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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

View 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

View 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!
```

View file

@ -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)
}

View file

@ -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, .. })

View file

@ -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;

View file

@ -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(..)

View file

@ -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()
}

View file

@ -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
)
}

View file

@ -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);

View file

@ -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)

View file

@ -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 }),
}
}
}

View file

@ -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);

View file

@ -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())
}
_ => {

View file

@ -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));

View file

@ -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

View file

@ -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");

View file

@ -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)
}

View file

@ -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(),

View file

@ -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;
}

View file

@ -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, .. } => {

View file

@ -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: _ } => {}
}

View file

@ -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),

View file

@ -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),
}

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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(_)

View file

@ -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,
}
}

View file

@ -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),
}
}

View file

@ -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),

View file

@ -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

View file

@ -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,

View file

@ -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(..)

View file

@ -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)
}

View file

@ -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()])),
)
}
}

View file

@ -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);

View file

@ -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,
}
}
}

View file

@ -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")]

View file

@ -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) => {

View file

@ -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());

View file

@ -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);
}
}

View file

@ -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: _,

View file

@ -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);

View file

@ -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();

View file

@ -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) {

View file

@ -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)) {

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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),
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)?;
}
}
}

View file

@ -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 {

View file

@ -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)?;

View file

@ -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" },
);

View file

@ -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(

View file

@ -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

View file

@ -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,
);

View file

@ -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 },
);
}

View file

@ -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