From 470cdf54ac9acee20ab8da46ef7899bae9f58f29 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 15 Jan 2020 16:39:08 +0100 Subject: [PATCH 01/18] add bare metal ARM Cortex-A targets to rustc -> `rustc --target armv7-none-eabi` will work also build rust-std (rustup) components for them -> `rustup target add armv7-none-eabi` will work --- src/ci/docker/dist-various-1/Dockerfile | 4 ++ src/librustc_target/spec/armv7a_none_eabi.rs | 48 +++++++++++++++++++ .../spec/armv7a_none_eabihf.rs | 36 ++++++++++++++ src/librustc_target/spec/mod.rs | 3 ++ src/tools/build-manifest/src/main.rs | 2 + 5 files changed, 93 insertions(+) create mode 100644 src/librustc_target/spec/armv7a_none_eabi.rs create mode 100644 src/librustc_target/spec/armv7a_none_eabihf.rs diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 6bbf092878311..689e18c3b40ba 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -134,6 +134,8 @@ ENV TARGETS=$TARGETS,armebv7r-none-eabihf ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf +ENV TARGETS=$TARGETS,armv7a-none-eabi +ENV TARGETS=$TARGETS,armv7a-none-eabihf # riscv targets currently do not need a C compiler, as compiler_builtins # doesn't currently have it enabled, and the riscv gcc compiler is not @@ -147,6 +149,8 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ \ + CC_armv7a_none_eabi=arm-none-eabi-gcc \ + CC_armv7a_none_eabihf=arm-none-eabi-gcc \ CC_riscv32i_unknown_none_elf=false \ CC_riscv32imc_unknown_none_elf=false \ CC_riscv32imac_unknown_none_elf=false \ diff --git a/src/librustc_target/spec/armv7a_none_eabi.rs b/src/librustc_target/spec/armv7a_none_eabi.rs new file mode 100644 index 0000000000000..2fbef154f814c --- /dev/null +++ b/src/librustc_target/spec/armv7a_none_eabi.rs @@ -0,0 +1,48 @@ +// Generic ARMv7-A target for bare-metal code - floating point disabled +// +// This is basically the `armv7-unknown-linux-gnueabi` target with some changes +// (listed below) to bring it closer to the bare-metal `thumb` & `aarch64` +// targets: +// +// - `TargetOptions.features`: added `+strict-align`. rationale: unaligned +// memory access is disabled on boot on these cores +// - linker changed to LLD. rationale: C is not strictly needed to build +// bare-metal binaries (the `gcc` linker has the advantage that it knows where C +// libraries and crt*.o are but it's not much of an advantage here); LLD is also +// faster +// - `target_os` set to `none`. rationale: matches `thumb` targets +// - `target_{env,vendor}` set to an empty string. rationale: matches `thumb` +// targets +// - `panic_strategy` set to `abort`. rationale: matches `thumb` targets +// - `relocation-model` set to `static`; also no PIE, no relro and no dynamic +// linking. rationale: matches `thumb` targets + +use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; + +pub fn target() -> Result { + let opts = TargetOptions { + linker: Some("rust-lld".to_owned()), + features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(), + executables: true, + relocation_model: "static".to_string(), + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + abi_blacklist: super::arm_base::abi_blacklist(), + emit_debug_gdb_scripts: false, + ..Default::default() + }; + Ok(Target { + llvm_target: "armv7a-none-eabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_os: "none".to_string(), + target_env: String::new(), + target_vendor: String::new(), + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + options: opts, + }) +} diff --git a/src/librustc_target/spec/armv7a_none_eabihf.rs b/src/librustc_target/spec/armv7a_none_eabihf.rs new file mode 100644 index 0000000000000..f31e68c5bd12a --- /dev/null +++ b/src/librustc_target/spec/armv7a_none_eabihf.rs @@ -0,0 +1,36 @@ +// Generic ARMv7-A target for bare-metal code - floating point enabled (assumes +// FPU is present and emits FPU instructions) +// +// This is basically the `armv7-unknown-linux-gnueabihf` target with some +// changes (list in `armv7a_none_eabi.rs`) to bring it closer to the bare-metal +// `thumb` & `aarch64` targets. + +use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; + +pub fn target() -> Result { + let opts = TargetOptions { + linker: Some("rust-lld".to_owned()), + features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(), + executables: true, + relocation_model: "static".to_string(), + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + abi_blacklist: super::arm_base::abi_blacklist(), + emit_debug_gdb_scripts: false, + ..Default::default() + }; + Ok(Target { + llvm_target: "armv7a-none-eabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_os: "none".to_string(), + target_env: String::new(), + target_vendor: String::new(), + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + options: opts, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 528ffdf93a01a..67f45d3d230ef 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -472,6 +472,9 @@ supported_targets! { ("thumbv8m.main-none-eabi", thumbv8m_main_none_eabi), ("thumbv8m.main-none-eabihf", thumbv8m_main_none_eabihf), + ("armv7a-none-eabi", armv7a_none_eabi), + ("armv7a-none-eabihf", armv7a_none_eabihf), + ("msp430-none-elf", msp430_none_elf), ("aarch64-unknown-cloudabi", aarch64_unknown_cloudabi), diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 481163a1a9abe..8281d20e4c886 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -69,6 +69,8 @@ static TARGETS: &[&str] = &[ "thumbv7neon-linux-androideabi", "armv7-unknown-linux-gnueabi", "armv7-unknown-linux-gnueabihf", + "armv7a-none-eabi", + "armv7a-none-eabihf", "thumbv7neon-unknown-linux-gnueabihf", "armv7-unknown-linux-musleabi", "armv7-unknown-linux-musleabihf", From de388032555b697d1b0ef197241886ab90ac39b2 Mon Sep 17 00:00:00 2001 From: Tobias Kortkamp Date: Sun, 19 Jan 2020 07:04:24 +0100 Subject: [PATCH 02/18] Add -Wl,-znotext to default linker flags to link with lld 9 on FreeBSD 13.0-CURRENT i386 rust-nightly has been failing to link since 2019-12-10 with variations of ``` = note: ld: error: relocation R_386_PC32 cannot be used against symbol __rust_probestack; recompile with -fPIC >>> defined in /wrkdirs/usr/ports/lang/rust-nightly/work/rustc-nightly-src/build/i686-unknown-freebsd/stage1/lib/rustlib/i686-unknown-freebsd/lib/libcompiler_builtins-6570a75fe85f0e1a.rlib(compiler_builtins-6570a75fe85f0e1a.compiler_builtins.2i519eqi-cgu.15.rcgu.o) >>> referenced by std.4xivr03c-cgu.14 >>> std-9bd70afd58e204b7.std.4xivr03c-cgu.14.rcgu.o:(_$LT$alloc..boxed..Box$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$::call_once::h1c78ed6e734a2bfc (.llvm.10122419023709863394)) in archive /wrkdirs/usr/ports/lang/rust-nightly/work/rustc-nightly-src/build/i686-unknown-freebsd/stage1/lib/rustlib/i686-unknown-freebsd/lib/libstd-9bd70afd58e204b7.rlib ld: error: relocation R_386_PC32 cannot be used against symbol __rust_probestack; recompile with -fPIC >>> defined in /wrkdirs/usr/ports/lang/rust-nightly/work/rustc-nightly-src/build/i686-unknown-freebsd/stage1/lib/rustlib/i686-unknown-freebsd/lib/libcompiler_builtins-6570a75fe85f0e1a.rlib(compiler_builtins-6570a75fe85f0e1a.compiler_builtins.2i519eqi-cgu.15.rcgu.o) >>> referenced by std.4xivr03c-cgu.14 >>> std-9bd70afd58e204b7.std.4xivr03c-cgu.14.rcgu.o:(std::io::util::copy::h9115f048f2203467) in archive /wrkdirs/usr/ports/lang/rust-nightly/work/rustc-nightly-src/build/i686-unknown-freebsd/stage1/lib/rustlib/i686-unknown-freebsd/lib/libstd-9bd70afd58e204b7.rlib clang-cpp: error: linker command failed with exit code 1 (use -v to see invocation) error: aborting due to previous error error: could not compile `rustc_macros`. ``` Full log: http://beefy17.nyi.freebsd.org/data/head-i386-default/p523508_s356869/logs/rust-nightly-1.42.0.20200118.log AFAICT it stopped building after bumping compiler_builtins to 0.1.22 in https://github.com/rust-lang/rust/pull/67110. --- src/librustc_target/spec/i686_unknown_freebsd.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_target/spec/i686_unknown_freebsd.rs b/src/librustc_target/spec/i686_unknown_freebsd.rs index 88c944a6cb7eb..60f2188514e1b 100644 --- a/src/librustc_target/spec/i686_unknown_freebsd.rs +++ b/src/librustc_target/spec/i686_unknown_freebsd.rs @@ -4,7 +4,9 @@ pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + let pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + pre_link_args.push("-m32".to_string()); + pre_link_args.push("-Wl,-znotext".to_string()); base.stack_probes = true; Ok(Target { From 358ade906830ae3d6cc665eae8aec0406e5904ba Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Sat, 21 Dec 2019 21:37:15 +1100 Subject: [PATCH 03/18] Add `-Z no-link` flag Adds a compiler option to allow rustc compile a crate without linking. With this flag, rustc serializes codegen_results into a .rlink file. --- Cargo.lock | 1 + src/librustc/middle/cstore.rs | 5 ++-- src/librustc/middle/dependency_format.rs | 2 +- src/librustc_codegen_llvm/Cargo.toml | 1 + src/librustc_codegen_llvm/lib.rs | 13 ++++++++++ src/librustc_codegen_ssa/back/linker.rs | 1 + src/librustc_codegen_ssa/lib.rs | 7 +++--- src/librustc_hir/def_id.rs | 32 ++++++++++++++++++++---- src/librustc_session/config.rs | 2 +- src/librustc_session/options.rs | 2 ++ src/librustc_session/search_paths.rs | 2 +- 11 files changed, 55 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f33d7ff12febf..1863c3569ef06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3426,6 +3426,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "serialize", "smallvec 1.0.0", "syntax", ] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 5b1e7673629b1..0e7ff3a3393ef 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -27,7 +27,7 @@ pub use rustc_session::utils::NativeLibraryKind; /// Where a crate came from on the local filesystem. One of these three options /// must be non-None. -#[derive(PartialEq, Clone, Debug, HashStable)] +#[derive(PartialEq, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)] pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, @@ -75,7 +75,7 @@ impl DepKind { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)] pub enum LibSource { Some(PathBuf), MetadataOnly, @@ -160,6 +160,7 @@ pub enum ExternCrateSource { Path, } +#[derive(RustcEncodable, RustcDecodable)] pub struct EncodedMetadata { pub raw_data: Vec, } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 8b2bf55ccc120..6ece51fe86674 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -19,7 +19,7 @@ pub type DependencyList = Vec; /// This is local to the tcx, and is generally relevant to one session. pub type Dependencies = Vec<(config::CrateType, DependencyList)>; -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable, RustcEncodable, RustcDecodable)] pub enum Linkage { NotLinked, IncludedFromDylib, diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 3ff5495e29136..dd9eadde098ec 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -28,6 +28,7 @@ rustc_incremental = { path = "../librustc_incremental" } rustc_index = { path = "../librustc_index" } rustc_llvm = { path = "../librustc_llvm" } rustc_session = { path = "../librustc_session" } +rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } syntax = { path = "../libsyntax" } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index a6168128c4d44..5af0e404183a9 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -33,6 +33,7 @@ use rustc_codegen_ssa::CompiledModule; use rustc_errors::{FatalError, Handler}; use std::any::Any; use std::ffi::CStr; +use std::fs; use std::sync::Arc; use syntax::expand::allocator::AllocatorKind; @@ -44,6 +45,7 @@ use rustc::ty::{self, TyCtxt}; use rustc::util::common::ErrorReported; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_serialize::json; mod back { pub mod archive; @@ -298,6 +300,17 @@ impl CodegenBackend for LlvmCodegenBackend { return Ok(()); } + if sess.opts.debugging_opts.no_link { + let rlink_data = json::encode(&codegen_results).map_err(|err| { + sess.fatal(&format!("failed to encode rlink: {}", err)); + })?; + let rlink_file = outputs.with_extension("rlink"); + fs::write(&rlink_file, rlink_data).map_err(|err| { + sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); + })?; + return Ok(()); + } + // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. sess.time("link_crate", || { diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 11f5d3007e6b4..debde17efbb63 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -20,6 +20,7 @@ use rustc_target::spec::{LinkerFlavor, LldFlavor}; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. +#[derive(RustcEncodable, RustcDecodable)] pub struct LinkerInfo { exports: FxHashMap>, } diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index aba77231268e7..0ca9bbb74e5bb 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -87,7 +87,7 @@ impl ModuleCodegen { } } -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CompiledModule { pub name: String, pub kind: ModuleKind, @@ -101,7 +101,7 @@ pub struct CachedModuleCodegen { pub source: WorkProduct, } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum ModuleKind { Regular, Metadata, @@ -117,7 +117,7 @@ bitflags::bitflags! { } /// Misc info we load from metadata to persist beyond the tcx. -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CrateInfo { pub panic_runtime: Option, pub compiler_builtins: Option, @@ -135,6 +135,7 @@ pub struct CrateInfo { pub dependency_formats: Lrc, } +#[derive(RustcEncodable, RustcDecodable)] pub struct CodegenResults { pub crate_name: Symbol, pub modules: Vec, diff --git a/src/librustc_hir/def_id.rs b/src/librustc_hir/def_id.rs index f8cacdc6238e8..80aa3ce6a4e14 100644 --- a/src/librustc_hir/def_id.rs +++ b/src/librustc_hir/def_id.rs @@ -1,7 +1,8 @@ use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; +use rustc_serialize::{Decoder, Encoder}; use std::fmt; -use std::u32; +use std::{u32, u64}; rustc_index::newtype_index! { pub struct CrateId { @@ -86,8 +87,16 @@ impl fmt::Display for CrateNum { } } -impl rustc_serialize::UseSpecializedEncodable for CrateNum {} -impl rustc_serialize::UseSpecializedDecodable for CrateNum {} +impl rustc_serialize::UseSpecializedEncodable for CrateNum { + fn default_encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_u32(self.as_u32()) + } +} +impl rustc_serialize::UseSpecializedDecodable for CrateNum { + fn default_decode(d: &mut D) -> Result { + Ok(CrateNum::from_u32(d.read_u32()?)) + } +} rustc_index::newtype_index! { /// A DefIndex is an index into the hir-map for a crate, identifying a @@ -135,8 +144,21 @@ impl DefId { } } -impl rustc_serialize::UseSpecializedEncodable for DefId {} -impl rustc_serialize::UseSpecializedDecodable for DefId {} +impl rustc_serialize::UseSpecializedEncodable for DefId { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + let krate = u64::from(self.krate.as_u32()); + let index = u64::from(self.index.as_u32()); + s.emit_u64((krate << 32) | index) + } +} +impl rustc_serialize::UseSpecializedDecodable for DefId { + fn default_decode(d: &mut D) -> Result { + let def_id = d.read_u64()?; + let krate = CrateNum::from_u32((def_id >> 32) as u32); + let index = DefIndex::from_u32((def_id & 0xffffffff) as u32); + Ok(DefId { krate, index }) + } +} pub fn default_def_id_debug(def_id: DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DefId").field("krate", &def_id.krate).field("index", &def_id.index).finish() diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index b6b22e298ca62..b1ba81aa95b19 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -619,7 +619,7 @@ pub enum EntryFnType { impl_stable_hash_via_hash!(EntryFnType); -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum CrateType { Executable, Dylib, diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 2a0ed27b63b08..34da2188a51d2 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -950,4 +950,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, (such as entering an empty infinite loop) by inserting llvm.sideeffect"), deduplicate_diagnostics: Option = (None, parse_opt_bool, [UNTRACKED], "deduplicate identical diagnostics"), + no_link: bool = (false, parse_bool, [TRACKED], + "compile without linking"), } diff --git a/src/librustc_session/search_paths.rs b/src/librustc_session/search_paths.rs index b15f4e8f6c18e..06f408b4a8d64 100644 --- a/src/librustc_session/search_paths.rs +++ b/src/librustc_session/search_paths.rs @@ -9,7 +9,7 @@ pub struct SearchPath { pub files: Vec, } -#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)] +#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, RustcEncodable, RustcDecodable)] pub enum PathKind { Native, Crate, From 6d218db26df424722d13db0ed3babae3cf450bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 20 Jan 2020 00:00:00 +0000 Subject: [PATCH 04/18] compiletest: Simplify multi-debugger support Previous implementation used a single mode type to store various pieces of otherwise loosely related information: * Whether debuginfo mode is in use or not. * Which debuggers should run in general. * Which debuggers are enabled for particular test case. The new implementation introduces a separation between those aspects. There is a single debuginfo mode parametrized by a debugger type. The debugger detection is performed first and a separate configuration is created for each detected debugger. The test cases are gathered independently for each debugger which makes it trivial to implement support for `ignore` / `only` conditions. Functional changes: * A single `debuginfo` entry point (rather than `debuginfo-cdb`, `debuginfo-gdb+lldb`, etc.). * Debugger name is included in the test name. * Test outputs are placed in per-debugger directory. * Fixed spurious hash mismatch. Previously, the config mode would change from `DebugInfoGdbLldb` (when collecting tests) to `DebugInfoGdb` or `DebugInfoLldb` (when running them) which would affect hash computation. * PYTHONPATH is additionally included in gdb hash. * lldb-python and lldb-python-dir are additionally included in lldb hash. --- src/bootstrap/test.rs | 8 -- src/tools/compiletest/src/common.rs | 49 ++++--- src/tools/compiletest/src/header.rs | 193 +++++++-------------------- src/tools/compiletest/src/main.rs | 189 ++++++++++++++------------ src/tools/compiletest/src/runtest.rs | 58 ++++---- 5 files changed, 211 insertions(+), 286 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 10e07489e1212..a186c16f1aa71 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -957,14 +957,6 @@ impl Step for Compiletest { } if suite == "debuginfo" { - let msvc = builder.config.build.contains("msvc"); - if mode == "debuginfo" { - return builder.ensure(Compiletest { - mode: if msvc { "debuginfo-cdb" } else { "debuginfo-gdb+lldb" }, - ..self - }); - } - builder .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target }); } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 01001ff708c79..9cc19060cbddc 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -14,10 +14,7 @@ pub enum Mode { RunFail, RunPassValgrind, Pretty, - DebugInfoCdb, - DebugInfoGdbLldb, - DebugInfoGdb, - DebugInfoLldb, + DebugInfo, Codegen, Rustdoc, CodegenUnits, @@ -32,13 +29,9 @@ pub enum Mode { impl Mode { pub fn disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, - // they need to keep their output segregated. Same is true for debuginfo tests that - // can be run on cdb, gdb, and lldb. + // they need to keep their output segregated. match self { Pretty => ".pretty", - DebugInfoCdb => ".cdb", - DebugInfoGdb => ".gdb", - DebugInfoLldb => ".lldb", _ => "", } } @@ -52,10 +45,7 @@ impl FromStr for Mode { "run-fail" => Ok(RunFail), "run-pass-valgrind" => Ok(RunPassValgrind), "pretty" => Ok(Pretty), - "debuginfo-cdb" => Ok(DebugInfoCdb), - "debuginfo-gdb+lldb" => Ok(DebugInfoGdbLldb), - "debuginfo-lldb" => Ok(DebugInfoLldb), - "debuginfo-gdb" => Ok(DebugInfoGdb), + "debuginfo" => Ok(DebugInfo), "codegen" => Ok(Codegen), "rustdoc" => Ok(Rustdoc), "codegen-units" => Ok(CodegenUnits), @@ -77,10 +67,7 @@ impl fmt::Display for Mode { RunFail => "run-fail", RunPassValgrind => "run-pass-valgrind", Pretty => "pretty", - DebugInfoCdb => "debuginfo-cdb", - DebugInfoGdbLldb => "debuginfo-gdb+lldb", - DebugInfoGdb => "debuginfo-gdb", - DebugInfoLldb => "debuginfo-lldb", + DebugInfo => "debuginfo", Codegen => "codegen", Rustdoc => "rustdoc", CodegenUnits => "codegen-units", @@ -155,6 +142,29 @@ impl CompareMode { } } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Debugger { + Cdb, + Gdb, + Lldb, +} + +impl Debugger { + fn to_str(&self) -> &'static str { + match self { + Debugger::Cdb => "cdb", + Debugger::Gdb => "gdb", + Debugger::Lldb => "lldb", + } + } +} + +impl fmt::Display for Debugger { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.to_str(), f) + } +} + /// Configuration for compiletest #[derive(Clone)] pub struct Config { @@ -208,6 +218,9 @@ pub struct Config { /// The test mode, compile-fail, run-fail, ui pub mode: Mode, + /// The debugger to use in debuginfo mode. Unset otherwise. + pub debugger: Option, + /// Run ignored tests pub run_ignored: bool, @@ -362,9 +375,11 @@ pub fn output_testname_unique( revision: Option<&str>, ) -> PathBuf { let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str()); + let debugger = config.debugger.as_ref().map_or("", |m| m.to_str()); PathBuf::from(&testpaths.file.file_stem().unwrap()) .with_extra_extension(revision.unwrap_or("")) .with_extra_extension(mode) + .with_extra_extension(debugger) } /// Absolute path to the directory where all output for the given diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 691b8d3ccfd39..34f9ac037b4b8 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -6,52 +6,13 @@ use std::path::{Path, PathBuf}; use log::*; -use crate::common::{self, CompareMode, Config, FailMode, Mode, PassMode}; +use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode}; use crate::extract_gdb_version; use crate::util; #[cfg(test)] mod tests; -/// Whether to ignore the test. -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum Ignore { - /// Runs it. - Run, - /// Ignore it totally. - Ignore, - /// Ignore only the gdb test, but run the lldb test. - IgnoreGdb, - /// Ignore only the lldb test, but run the gdb test. - IgnoreLldb, -} - -impl Ignore { - pub fn can_run_gdb(&self) -> bool { - *self == Ignore::Run || *self == Ignore::IgnoreLldb - } - - pub fn can_run_lldb(&self) -> bool { - *self == Ignore::Run || *self == Ignore::IgnoreGdb - } - - pub fn no_gdb(&self) -> Ignore { - match *self { - Ignore::Run => Ignore::IgnoreGdb, - Ignore::IgnoreGdb => Ignore::IgnoreGdb, - _ => Ignore::Ignore, - } - } - - pub fn no_lldb(&self) -> Ignore { - match *self { - Ignore::Run => Ignore::IgnoreLldb, - Ignore::IgnoreLldb => Ignore::IgnoreLldb, - _ => Ignore::Ignore, - } - } -} - /// The result of parse_cfg_name_directive. #[derive(Clone, Copy, PartialEq, Debug)] enum ParsedNameDirective { @@ -59,16 +20,12 @@ enum ParsedNameDirective { NoMatch, /// Match. Match, - /// Mode was DebugInfoGdbLldb and this matched gdb. - MatchGdb, - /// Mode was DebugInfoGdbLldb and this matched lldb. - MatchLldb, } /// Properties which must be known very early, before actually running /// the test. pub struct EarlyProps { - pub ignore: Ignore, + pub ignore: bool, pub should_fail: bool, pub aux: Vec, pub aux_crate: Vec<(String, String)>, @@ -78,84 +35,61 @@ pub struct EarlyProps { impl EarlyProps { pub fn from_file(config: &Config, testfile: &Path) -> Self { let mut props = EarlyProps { - ignore: Ignore::Run, + ignore: false, should_fail: false, aux: Vec::new(), aux_crate: Vec::new(), revisions: vec![], }; - if config.mode == common::DebugInfoGdbLldb { - if config.lldb_python_dir.is_none() { - props.ignore = props.ignore.no_lldb(); - } - if config.gdb_version.is_none() { - props.ignore = props.ignore.no_gdb(); - } - } else if config.mode == common::DebugInfoCdb { - if config.cdb.is_none() { - props.ignore = Ignore::Ignore; - } - } - let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); iter_header(testfile, None, &mut |ln| { // we should check if any only- exists and if it exists // and does not matches the current platform, skip the test - if props.ignore != Ignore::Ignore { + if !props.ignore { props.ignore = match config.parse_cfg_name_directive(ln, "ignore") { - ParsedNameDirective::Match => Ignore::Ignore, + ParsedNameDirective::Match => true, ParsedNameDirective::NoMatch => props.ignore, - ParsedNameDirective::MatchGdb => props.ignore.no_gdb(), - ParsedNameDirective::MatchLldb => props.ignore.no_lldb(), }; if config.has_cfg_prefix(ln, "only") { props.ignore = match config.parse_cfg_name_directive(ln, "only") { ParsedNameDirective::Match => props.ignore, - ParsedNameDirective::NoMatch => Ignore::Ignore, - ParsedNameDirective::MatchLldb => props.ignore.no_gdb(), - ParsedNameDirective::MatchGdb => props.ignore.no_lldb(), + ParsedNameDirective::NoMatch => true, }; } if ignore_llvm(config, ln) { - props.ignore = Ignore::Ignore; + props.ignore = true; } if config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln) { - props.ignore = Ignore::Ignore; + props.ignore = true; } if !rustc_has_profiler_support && config.parse_needs_profiler_support(ln) { - props.ignore = Ignore::Ignore; + props.ignore = true; } if !rustc_has_sanitizer_support && config.parse_needs_sanitizer_support(ln) { - props.ignore = Ignore::Ignore; + props.ignore = true; } if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) { - props.ignore = Ignore::Ignore; + props.ignore = true; } - } - if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) - && props.ignore.can_run_gdb() - && ignore_gdb(config, ln) - { - props.ignore = props.ignore.no_gdb(); - } + if config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln) { + props.ignore = true; + } - if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoGdbLldb) - && props.ignore.can_run_lldb() - && ignore_lldb(config, ln) - { - props.ignore = props.ignore.no_lldb(); + if config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln) { + props.ignore = true; + } } if let Some(s) = config.parse_aux_build(ln) { @@ -881,70 +815,37 @@ impl Config { /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `normalize-stderr-32bit`. fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective { - if line.starts_with(prefix) && line.as_bytes().get(prefix.len()) == Some(&b'-') { - let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap(); - - if name == "test" || - &self.target == name || // triple - util::matches_os(&self.target, name) || // target - util::matches_env(&self.target, name) || // env - name == util::get_arch(&self.target) || // architecture - name == util::get_pointer_width(&self.target) || // pointer width - name == self.stage_id.split('-').next().unwrap() || // stage - (self.target != self.host && name == "cross-compile") || - match self.compare_mode { - Some(CompareMode::Nll) => name == "compare-mode-nll", - Some(CompareMode::Polonius) => name == "compare-mode-polonius", - None => false, - } || - (cfg!(debug_assertions) && name == "debug") - { - ParsedNameDirective::Match - } else { - match self.mode { - common::DebugInfoGdbLldb => { - if name == "gdb" { - ParsedNameDirective::MatchGdb - } else if name == "lldb" { - ParsedNameDirective::MatchLldb - } else { - ParsedNameDirective::NoMatch - } - } - common::DebugInfoCdb => { - if name == "cdb" { - ParsedNameDirective::Match - } else { - ParsedNameDirective::NoMatch - } - } - common::DebugInfoGdb => { - if name == "gdb" { - ParsedNameDirective::Match - } else { - ParsedNameDirective::NoMatch - } - } - common::DebugInfoLldb => { - if name == "lldb" { - ParsedNameDirective::Match - } else { - ParsedNameDirective::NoMatch - } - } - common::Pretty => { - if name == "pretty" { - ParsedNameDirective::Match - } else { - ParsedNameDirective::NoMatch - } - } - _ => ParsedNameDirective::NoMatch, - } - } - } else { - ParsedNameDirective::NoMatch + if !line.as_bytes().starts_with(prefix.as_bytes()) { + return ParsedNameDirective::NoMatch; + } + if line.as_bytes().get(prefix.len()) != Some(&b'-') { + return ParsedNameDirective::NoMatch; } + + let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap(); + + let is_match = name == "test" || + &self.target == name || // triple + util::matches_os(&self.target, name) || // target + util::matches_env(&self.target, name) || // env + name == util::get_arch(&self.target) || // architecture + name == util::get_pointer_width(&self.target) || // pointer width + name == self.stage_id.split('-').next().unwrap() || // stage + (self.target != self.host && name == "cross-compile") || + match self.compare_mode { + Some(CompareMode::Nll) => name == "compare-mode-nll", + Some(CompareMode::Polonius) => name == "compare-mode-polonius", + None => false, + } || + (cfg!(debug_assertions) && name == "debug") || + match self.debugger { + Some(Debugger::Cdb) => name == "cdb", + Some(Debugger::Gdb) => name == "gdb", + Some(Debugger::Lldb) => name == "lldb", + None => false, + }; + + if is_match { ParsedNameDirective::Match } else { ParsedNameDirective::NoMatch } } fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index efa9d05f16c38..0c8f4dd5eaaa1 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -8,9 +8,7 @@ extern crate test; use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; -use crate::common::{CompareMode, PassMode}; -use crate::common::{Config, TestPaths}; -use crate::common::{DebugInfoCdb, DebugInfoGdb, DebugInfoGdbLldb, DebugInfoLldb, Mode, Pretty}; +use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths}; use crate::util::logv; use env_logger; use getopts; @@ -26,7 +24,7 @@ use std::time::SystemTime; use test::ColorConfig; use walkdir::WalkDir; -use self::header::{EarlyProps, Ignore}; +use self::header::EarlyProps; #[cfg(test)] mod tests; @@ -50,7 +48,7 @@ fn main() { } log_config(&config); - run_tests(&config); + run_tests(config); } pub fn parse_config(args: Vec) -> Config { @@ -199,6 +197,7 @@ pub fn parse_config(args: Vec) -> Config { build_base: opt_path(matches, "build-base"), stage_id: matches.opt_str("stage-id").unwrap(), mode: matches.opt_str("mode").unwrap().parse().expect("invalid mode"), + debugger: None, run_ignored, filter: matches.free.first().cloned(), filter_exact: matches.opt_present("exact"), @@ -293,61 +292,7 @@ pub fn opt_str2(maybestr: Option) -> String { } } -pub fn run_tests(config: &Config) { - if config.target.contains("android") { - if config.mode == DebugInfoGdb || config.mode == DebugInfoGdbLldb { - println!( - "{} debug-info test uses tcp 5039 port.\ - please reserve it", - config.target - ); - - // android debug-info test uses remote debugger so, we test 1 thread - // at once as they're all sharing the same TCP port to communicate - // over. - // - // we should figure out how to lift this restriction! (run them all - // on different ports allocated dynamically). - env::set_var("RUST_TEST_THREADS", "1"); - } - } - - match config.mode { - // Note that we don't need to emit the gdb warning when - // DebugInfoGdbLldb, so it is ok to list that here. - DebugInfoGdbLldb | DebugInfoLldb => { - if let Some(lldb_version) = config.lldb_version.as_ref() { - if is_blacklisted_lldb_version(&lldb_version[..]) { - println!( - "WARNING: The used version of LLDB ({}) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - lldb_version - ); - return; - } - } - - // Some older versions of LLDB seem to have problems with multiple - // instances running in parallel, so only run one test thread at a - // time. - env::set_var("RUST_TEST_THREADS", "1"); - } - - DebugInfoGdb => { - if config.remote_test_client.is_some() && !config.target.contains("android") { - println!( - "WARNING: debuginfo tests are not available when \ - testing with remote" - ); - return; - } - } - - DebugInfoCdb | _ => { /* proceed */ } - } - +pub fn run_tests(config: Config) { // FIXME(#33435) Avoid spurious failures in codegen-units/partitioning tests. if let Mode::CodegenUnits = config.mode { let _ = fs::remove_dir_all("tmp/partitioning-tests"); @@ -366,8 +311,6 @@ pub fn run_tests(config: &Config) { } } - let opts = test_opts(config); - let tests = make_tests(config); // sadly osx needs some file descriptor limits raised for running tests in // parallel (especially when we have lots and lots of child processes). // For context, see #8904 @@ -381,6 +324,25 @@ pub fn run_tests(config: &Config) { // Let tests know which target they're running as env::set_var("TARGET", &config.target); + let opts = test_opts(&config); + + let mut configs = Vec::new(); + if let Mode::DebugInfo = config.mode { + // Debugging emscripten code doesn't make sense today + if !config.target.contains("emscripten") { + configs.extend(configure_cdb(&config)); + configs.extend(configure_gdb(&config)); + configs.extend(configure_lldb(&config)); + } + } else { + configs.push(config); + }; + + let mut tests = Vec::new(); + for c in &configs { + make_tests(c, &mut tests); + } + let res = test::run_tests_console(&opts, tests); match res { Ok(true) => {} @@ -391,6 +353,72 @@ pub fn run_tests(config: &Config) { } } +fn configure_cdb(config: &Config) -> Option { + if config.cdb.is_none() { + return None; + } + + Some(Config { debugger: Some(Debugger::Cdb), ..config.clone() }) +} + +fn configure_gdb(config: &Config) -> Option { + if config.gdb_version.is_none() { + return None; + } + + if config.remote_test_client.is_some() && !config.target.contains("android") { + println!( + "WARNING: debuginfo tests are not available when \ + testing with remote" + ); + return None; + } + + if config.target.contains("android") { + println!( + "{} debug-info test uses tcp 5039 port.\ + please reserve it", + config.target + ); + + // android debug-info test uses remote debugger so, we test 1 thread + // at once as they're all sharing the same TCP port to communicate + // over. + // + // we should figure out how to lift this restriction! (run them all + // on different ports allocated dynamically). + env::set_var("RUST_TEST_THREADS", "1"); + } + + Some(Config { debugger: Some(Debugger::Gdb), ..config.clone() }) +} + +fn configure_lldb(config: &Config) -> Option { + if config.lldb_python_dir.is_none() { + return None; + } + + if let Some(lldb_version) = config.lldb_version.as_ref() { + if is_blacklisted_lldb_version(&lldb_version) { + println!( + "WARNING: The used version of LLDB ({}) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + lldb_version + ); + return None; + } + } + + // Some older versions of LLDB seem to have problems with multiple + // instances running in parallel, so only run one test thread at a + // time. + env::set_var("RUST_TEST_THREADS", "1"); + + Some(Config { debugger: Some(Debugger::Lldb), ..config.clone() }) +} + pub fn test_opts(config: &Config) -> test::TestOpts { test::TestOpts { exclude_should_panic: false, @@ -415,20 +443,18 @@ pub fn test_opts(config: &Config) -> test::TestOpts { } } -pub fn make_tests(config: &Config) -> Vec { +pub fn make_tests(config: &Config, tests: &mut Vec) { debug!("making tests from {:?}", config.src_base.display()); let inputs = common_inputs_stamp(config); - let mut tests = Vec::new(); collect_tests_from_dir( config, &config.src_base, &config.src_base, &PathBuf::new(), &inputs, - &mut tests, + tests, ) .expect(&format!("Could not read tests from {}", config.src_base.display())); - tests } /// Returns a stamp constructed from input files common to all test cases. @@ -570,13 +596,7 @@ fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec Vec format!("-{}", d), + None => String::new(), + }; let mode_suffix = match config.compare_mode { Some(ref mode) => format!(" ({})", mode.to_str()), None => String::new(), }; + test::DynTestName(format!( - "[{}{}] {}{}", + "[{}{}{}] {}{}", config.mode, + debugger, mode_suffix, path.display(), revision.map_or("".to_string(), |rev| format!("#{}", rev)) @@ -700,21 +726,10 @@ fn make_test_name( fn make_test_closure( config: &Config, - ignore: Ignore, testpaths: &TestPaths, revision: Option<&String>, ) -> test::TestFn { - let mut config = config.clone(); - if config.mode == DebugInfoGdbLldb { - // If both gdb and lldb were ignored, then the test as a whole - // would be ignored. - if !ignore.can_run_gdb() { - config.mode = DebugInfoLldb; - } else if !ignore.can_run_lldb() { - config.mode = DebugInfoGdb; - } - } - + let config = config.clone(); let testpaths = testpaths.clone(); let revision = revision.cloned(); test::DynTestFn(Box::new(move || { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3a114a0b71517..d1ee60d74e7e2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3,11 +3,10 @@ use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; use crate::common::{output_base_dir, output_base_name, output_testname_unique}; use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, Ui}; -use crate::common::{Codegen, CodegenUnits, Rustdoc}; +use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind}; use crate::common::{Config, TestPaths}; -use crate::common::{DebugInfoCdb, DebugInfoGdb, DebugInfoGdbLldb, DebugInfoLldb}; use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; @@ -192,7 +191,7 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) { _ => { // android has its own gdb handling - if config.mode == DebugInfoGdb && config.gdb.is_none() { + if config.debugger == Some(Debugger::Gdb) && config.gdb.is_none() { panic!("gdb not available but debuginfo gdb debuginfo test requested"); } } @@ -234,21 +233,25 @@ pub fn compute_stamp_hash(config: &Config) -> String { let mut hash = DefaultHasher::new(); config.stage_id.hash(&mut hash); - if config.mode == DebugInfoCdb { - config.cdb.hash(&mut hash); - } + match config.debugger { + Some(Debugger::Cdb) => { + config.cdb.hash(&mut hash); + } - if config.mode == DebugInfoGdb || config.mode == DebugInfoGdbLldb { - match config.gdb { - None => env::var_os("PATH").hash(&mut hash), - Some(ref s) if s.is_empty() => env::var_os("PATH").hash(&mut hash), - Some(ref s) => s.hash(&mut hash), - }; - } + Some(Debugger::Gdb) => { + config.gdb.hash(&mut hash); + env::var_os("PATH").hash(&mut hash); + env::var_os("PYTHONPATH").hash(&mut hash); + } - if config.mode == DebugInfoLldb || config.mode == DebugInfoGdbLldb { - env::var_os("PATH").hash(&mut hash); - env::var_os("PYTHONPATH").hash(&mut hash); + Some(Debugger::Lldb) => { + config.lldb_python.hash(&mut hash); + config.lldb_python_dir.hash(&mut hash); + env::var_os("PATH").hash(&mut hash); + env::var_os("PYTHONPATH").hash(&mut hash); + } + + None => {} } if let Ui = config.mode { @@ -309,13 +312,7 @@ impl<'test> TestCx<'test> { RunFail => self.run_rfail_test(), RunPassValgrind => self.run_valgrind_test(), Pretty => self.run_pretty_test(), - DebugInfoGdbLldb => { - self.run_debuginfo_gdb_test(); - self.run_debuginfo_lldb_test(); - } - DebugInfoCdb => self.run_debuginfo_cdb_test(), - DebugInfoGdb => self.run_debuginfo_gdb_test(), - DebugInfoLldb => self.run_debuginfo_lldb_test(), + DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), Rustdoc => self.run_rustdoc_test(), CodegenUnits => self.run_codegen_units_test(), @@ -680,13 +677,20 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, Some(src)) } + fn run_debuginfo_test(&self) { + match self.config.debugger.unwrap() { + Debugger::Cdb => self.run_debuginfo_cdb_test(), + Debugger::Gdb => self.run_debuginfo_gdb_test(), + Debugger::Lldb => self.run_debuginfo_lldb_test(), + } + } + fn run_debuginfo_cdb_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), - mode: DebugInfoCdb, ..self.config.clone() }; @@ -765,7 +769,6 @@ impl<'test> TestCx<'test> { let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), - mode: DebugInfoGdb, ..self.config.clone() }; @@ -999,7 +1002,6 @@ impl<'test> TestCx<'test> { let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), - mode: DebugInfoLldb, ..self.config.clone() }; @@ -1887,8 +1889,8 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } - RunFail | RunPassValgrind | Pretty | DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb - | DebugInfoLldb | Codegen | Rustdoc | RunMake | CodegenUnits | JsDocTest | Assembly => { + RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RunMake + | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output } } From 2c0845c6ccfdee7fb255756918a22101376efa7e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 19 Jan 2020 22:08:15 +0100 Subject: [PATCH 05/18] Mark __msan_track_origins as an exported symbol for LTO --- src/librustc_codegen_ssa/back/symbol_export.rs | 8 +++++++- src/test/codegen/sanitizer-memory-track-orgins.rs | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index bd44b4a38fd58..c5989748560ce 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::middle::exported_symbols::{metadata_symbol_name, ExportedSymbol, SymbolExportLevel}; -use rustc::session::config; +use rustc::session::config::{self, Sanitizer}; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::ty::Instance; @@ -206,6 +206,12 @@ fn exported_symbols_provider_local( })); } + if let Some(Sanitizer::Memory) = tcx.sess.opts.debugging_opts.sanitizer { + // Similar to profiling, preserve weak msan symbol during LTO. + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("__msan_track_origins")); + symbols.push((exported_symbol, SymbolExportLevel::C)); + } + if tcx.sess.crate_types.borrow().contains(&config::CrateType::Dylib) { let symbol_name = metadata_symbol_name(tcx); let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); diff --git a/src/test/codegen/sanitizer-memory-track-orgins.rs b/src/test/codegen/sanitizer-memory-track-orgins.rs index fd8be0bced796..1fd496b35dfcc 100644 --- a/src/test/codegen/sanitizer-memory-track-orgins.rs +++ b/src/test/codegen/sanitizer-memory-track-orgins.rs @@ -4,17 +4,21 @@ // needs-sanitizer-support // only-linux // only-x86_64 -// revisions:MSAN-0 MSAN-1 MSAN-2 +// revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO // //[MSAN-0] compile-flags: -Zsanitizer=memory //[MSAN-1] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins=1 //[MSAN-2] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins +//[MSAN-1-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins=1 -C lto=fat +//[MSAN-2-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins -C lto=fat #![crate_type="lib"] // MSAN-0-NOT: @__msan_track_origins // MSAN-1: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 1 // MSAN-2: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 2 +// MSAN-1-LTO: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 1 +// MSAN-2-LTO: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 2 // // MSAN-0-LABEL: define void @copy( // MSAN-1-LABEL: define void @copy( From d8c661a88644ad710e309d3a8f0f27c5f74d705f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 21 Jan 2020 00:00:00 +0000 Subject: [PATCH 06/18] Mark __msan_keep_going as an exported symbol for LTO --- .../back/symbol_export.rs | 8 ++- src/test/codegen/sanitizer-recover.rs | 56 ++++++++++++------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index c5989748560ce..d680e14bbbd5b 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -208,8 +208,12 @@ fn exported_symbols_provider_local( if let Some(Sanitizer::Memory) = tcx.sess.opts.debugging_opts.sanitizer { // Similar to profiling, preserve weak msan symbol during LTO. - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("__msan_track_origins")); - symbols.push((exported_symbol, SymbolExportLevel::C)); + const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"]; + + symbols.extend(MSAN_WEAK_SYMBOLS.iter().map(|sym| { + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym)); + (exported_symbol, SymbolExportLevel::C) + })); } if tcx.sess.crate_types.borrow().contains(&config::CrateType::Dylib) { diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs index a292332667b54..9a583725b0bf0 100644 --- a/src/test/codegen/sanitizer-recover.rs +++ b/src/test/codegen/sanitizer-recover.rs @@ -4,31 +4,47 @@ // needs-sanitizer-support // only-linux // only-x86_64 -// revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER +// revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO +// no-prefer-dynamic // -//[ASAN] compile-flags: -Zsanitizer=address -//[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -//[MSAN] compile-flags: -Zsanitizer=memory -//[MSAN-RECOVER] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory - -#![crate_type="lib"] +//[ASAN] compile-flags: -Zsanitizer=address +//[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address +//[MSAN] compile-flags: -Zsanitizer=memory +//[MSAN-RECOVER] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory +//[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -C lto=fat +// +// MSAN-NOT: @__msan_keep_going +// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}} constant i32 1 +// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}} constant i32 1 -// ASAN-LABEL: define i32 @penguin( +// ASAN-LABEL: define i32 @penguin( +// ASAN: call void @__asan_report_load4(i64 %0) +// ASAN: unreachable +// ASAN: } +// // ASAN-RECOVER-LABEL: define i32 @penguin( -// MSAN-LABEL: define i32 @penguin( +// ASAN-RECOVER: call void @__asan_report_load4_noabort( +// ASAN-RECOVER-NOT: unreachable +// ASAN: } +// +// MSAN-LABEL: define i32 @penguin( +// MSAN: call void @__msan_warning_noreturn() +// MSAN: unreachable +// MSAN: } +// // MSAN-RECOVER-LABEL: define i32 @penguin( +// MSAN-RECOVER: call void @__msan_warning() +// MSAN-RECOVER-NOT: unreachable +// MSAN-RECOVER: } +// +// MSAN-RECOVER-LTO-LABEL: define i32 @penguin( +// MSAN-RECOVER-LTO: call void @__msan_warning() +// MSAN-RECOVER-LTO-NOT: unreachable +// MSAN-RECOVER-LTO: } +// #[no_mangle] pub fn penguin(p: &mut i32) -> i32 { - // ASAN: call void @__asan_report_load4(i64 %0) - // ASAN: unreachable - // - // ASAN-RECOVER: call void @__asan_report_load4_noabort( - // ASAN-RECOVER-NOT: unreachable - // - // MSAN: call void @__msan_warning_noreturn() - // MSAN: unreachable - // - // MSAN-RECOVER: call void @__msan_warning() - // MSAN-RECOVER-NOT: unreachable *p } + +fn main() {} From dd0507c054ea27ae836025761908d339a478e0ab Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Jan 2020 15:22:12 +0000 Subject: [PATCH 07/18] Make `TooGeneric` error in WF checking a proper error `TooGeneric` is encountered during WF checking when we cannot determine that a constant involving a generic parameter will always be evaluated successfully (rather than resulting in an error). In these cases, the burden of proof should be with the caller, so that we can avoid post-monomorphisation tim errors (which was the previous previous behaviour). This commit ensures that this situation produces a proper compiler error, rather than silently ignoring it or ICEing. --- src/librustc/traits/error_reporting/mod.rs | 34 +++++++++++++------ .../array-size-in-generic-struct-param.rs | 7 ++-- .../array-size-in-generic-struct-param.stderr | 20 ++++++++++- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index 646cb80bffd94..f3dc79f0ff6b2 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -914,17 +914,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { report_object_safety_error(self.tcx, span, did, violations) } - // already reported in the query - ConstEvalFailure(err) => { - if let ErrorHandled::TooGeneric = err { - // Silence this error, as it can be produced during intermediate steps - // when a constant is not yet able to be evaluated (but will be later). - return; - } - self.tcx.sess.delay_span_bug( - span, - &format!("constant in type had an ignored error: {:?}", err), - ); + ConstEvalFailure(ErrorHandled::TooGeneric) => { + // In this instance, we have a const expression containing an unevaluated + // generic parameter. We have no idea whether this expression is valid or + // not (e.g. it might result in an error), but we don't want to just assume + // that it's okay, because that might result in post-monomorphisation time + // errors. The onus is really on the caller to provide values that it can + // prove are well-formed. + let mut err = self + .tcx + .sess + .struct_span_err(span, "constant expression depends on a generic parameter"); + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + err.note("this may fail depending on what value the parameter takes"); + err + } + + // Already reported in the query. + ConstEvalFailure(ErrorHandled::Reported) => { + self.tcx + .sess + .delay_span_bug(span, &format!("constant in type had an ignored error")); return; } diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs index f3be7b56db589..d996bf56fcc10 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs @@ -1,10 +1,9 @@ -// run-pass - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash #[allow(dead_code)] -struct ArithArrayLen([u32; 0 + N]); // ok +struct ArithArrayLen([u32; 0 + N]); +//~^ ERROR constant expression depends on a generic parameter #[derive(PartialEq, Eq)] struct Config { @@ -12,7 +11,7 @@ struct Config { } struct B { - arr: [u8; CFG.arr_size], // ok + arr: [u8; CFG.arr_size], //~ ERROR constant expression depends on a generic parameter } const C: Config = Config { arr_size: 5 }; diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr index 274f97697029e..6ae70c493b1dd 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr @@ -1,8 +1,26 @@ warning: the feature `const_generics` is incomplete and may cause the compiler to crash - --> $DIR/array-size-in-generic-struct-param.rs:3:12 + --> $DIR/array-size-in-generic-struct-param.rs:1:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default +error: constant expression depends on a generic parameter + --> $DIR/array-size-in-generic-struct-param.rs:5:38 + | +LL | struct ArithArrayLen([u32; 0 + N]); + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/array-size-in-generic-struct-param.rs:14:5 + | +LL | arr: [u8; CFG.arr_size], + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + From 8abbd0beae79de5186158a759b08cb73d175b5ad Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 21 Jan 2020 17:18:37 +0100 Subject: [PATCH 08/18] for now, do not build rust-std for the armv7a-none-eabihf target it needs some upstream changes in the build script of the compiler-builtins crate --- src/ci/docker/dist-various-1/Dockerfile | 3 ++- src/tools/build-manifest/src/main.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 9da18d600ba2f..2a68a25be21b3 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -161,7 +161,6 @@ ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf ENV TARGETS=$TARGETS,armv7a-none-eabi -ENV TARGETS=$TARGETS,armv7a-none-eabihf # riscv targets currently do not need a C compiler, as compiler_builtins # doesn't currently have it enabled, and the riscv gcc compiler is not @@ -177,6 +176,8 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ \ CC_armv7a_none_eabi=arm-none-eabi-gcc \ CC_armv7a_none_eabihf=arm-none-eabi-gcc \ + CFLAGS_armv7a_none_eabi=-march=armv7-a \ + CFLAGS_armv7a_none_eabihf=-march=armv7-a+vfpv3 \ CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \ AR_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-ar \ CXX_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-g++ \ diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 8281d20e4c886..c8d6580f7a1a5 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -70,7 +70,6 @@ static TARGETS: &[&str] = &[ "armv7-unknown-linux-gnueabi", "armv7-unknown-linux-gnueabihf", "armv7a-none-eabi", - "armv7a-none-eabihf", "thumbv7neon-unknown-linux-gnueabihf", "armv7-unknown-linux-musleabi", "armv7-unknown-linux-musleabihf", From 5dee7dddf24a022184a743b714b5062e83516a87 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 21 Jan 2020 21:49:23 +0100 Subject: [PATCH 09/18] Handle methods in try diagnostic The diagnostic for diagnostic for methods and trait provided methods would only show the empty string: error[E0277]: the `?` operator can only be used in that returns `Result` or `Option` (or another type that implements `std::ops::Try`) Handle the missing cases so it reads ``a method'' / ``an async method'' / ``a trait method'' respectively. Signed-off-by: Philipp Gesang --- .../traits/error_reporting/on_unimplemented.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 9f3fc91548b21..8f55540cae38a 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -67,6 +67,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "a function" }) }) + } else if let hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), + .. + }) = &node + { + self.describe_generator(*body_id).or_else(|| Some("a trait method")) + } else if let hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Method(sig, body_id), + .. + }) = &node + { + self.describe_generator(*body_id).or_else(|| { + Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { + "an async method" + } else { + "a method" + }) + }) } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), .. From 02e66baac6882ef30e607d2bca98929f01758957 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 21 Jan 2020 21:51:13 +0100 Subject: [PATCH 10/18] Test try diagnostics for impl and trait methods Signed-off-by: Philipp Gesang --- src/test/ui/try-on-option-diagnostics.rs | 29 ++++++++++++++++++++ src/test/ui/try-on-option-diagnostics.stderr | 28 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-on-option-diagnostics.rs index 65d5e29ec2f13..63d17414c313b 100644 --- a/src/test/ui/try-on-option-diagnostics.rs +++ b/src/test/ui/try-on-option-diagnostics.rs @@ -16,3 +16,32 @@ fn a_closure() -> u32 { }; a_closure() } + +fn a_method() -> u32 { + struct S; + + impl S { + fn a_method() { + let x: Option = None; + x?; //~ ERROR the `?` operator + } + } + + S::a_method(); + 22 +} + +fn a_trait_method() -> u32 { + struct S; + trait T { + fn a_trait_method() { + let x: Option = None; + x?; //~ ERROR the `?` operator + } + } + + impl T for S { } + + S::a_trait_method(); + 22 +} diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-on-option-diagnostics.stderr index ce3aca39fb8fb..c9dc3f1b87969 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-on-option-diagnostics.stderr @@ -27,6 +27,32 @@ LL | | }; = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::from_error` -error: aborting due to 2 previous errors +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/try-on-option-diagnostics.rs:26:13 + | +LL | / fn a_method() { +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a method that returns `()` +LL | | } + | |_________- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/try-on-option-diagnostics.rs:39:13 + | +LL | / fn a_trait_method() { +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a trait method that returns `()` +LL | | } + | |_________- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. From db3b40c2a1fe6129a7bbc12df6260b7197731153 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 21 Jan 2020 21:46:38 +0100 Subject: [PATCH 11/18] Cleanup: rewrite conditional as match As suggested by @Centril. Signed-off-by: Philipp Gesang --- .../error_reporting/on_unimplemented.rs | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 8f55540cae38a..2ba12baaf6d6e 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -59,49 +59,45 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { let hir = &self.tcx.hir(); let node = hir.find(hir_id)?; - if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node { - self.describe_generator(*body_id).or_else(|| { - Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { - "an async function" - } else { - "a function" + match &node { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { + self.describe_generator(*body_id).or_else(|| { + Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { + "an async function" + } else { + "a function" + }) }) - }) - } else if let hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), - .. - }) = &node - { - self.describe_generator(*body_id).or_else(|| Some("a trait method")) - } else if let hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(sig, body_id), - .. - }) = &node - { - self.describe_generator(*body_id).or_else(|| { + } + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), + .. + }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")), + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Method(sig, body_id), + .. + }) => self.describe_generator(*body_id).or_else(|| { Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { "an async method" } else { "a method" }) - }) - } else if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), - .. - }) = &node - { - self.describe_generator(*body_id).or_else(|| { + }), + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), + .. + }) => self.describe_generator(*body_id).or_else(|| { Some(if gen_movability.is_some() { "an async closure" } else { "a closure" }) - }) - } else if let hir::Node::Expr(hir::Expr { .. }) = &node { - let parent_hid = hir.get_parent_node(hir_id); - if parent_hid != hir_id { - return self.describe_enclosure(parent_hid); - } else { - None + }), + hir::Node::Expr(hir::Expr { .. }) => { + let parent_hid = hir.get_parent_node(hir_id); + if parent_hid != hir_id { + return self.describe_enclosure(parent_hid); + } else { + None + } } - } else { - None + _ => None, } } From d1bb7e16e0d0ad4e568df14eceedc5b0dd484214 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 21 Jan 2020 09:50:22 -0500 Subject: [PATCH 12/18] Privatize private fields of OutputFilenames --- src/librustc_interface/util.rs | 33 ++++++++++++++------------------- src/librustc_session/config.rs | 14 ++++++++++++-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 21f9fa4816591..3e65da9c47b7e 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -550,13 +550,13 @@ pub fn build_output_filenames( .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string())) .unwrap_or_else(|| input.filestem().to_owned()); - OutputFilenames { - out_directory: dirpath, - out_filestem: stem, - single_output_file: None, - extra: sess.opts.cg.extra_filename.clone(), - outputs: sess.opts.output_types.clone(), - } + OutputFilenames::new( + dirpath, + stem, + None, + sess.opts.cg.extra_filename.clone(), + sess.opts.output_types.clone(), + ) } Some(ref out_file) => { @@ -578,18 +578,13 @@ pub fn build_output_filenames( sess.warn("ignoring --out-dir flag due to -o flag"); } - OutputFilenames { - out_directory: out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), - out_filestem: out_file - .file_stem() - .unwrap_or_default() - .to_str() - .unwrap() - .to_string(), - single_output_file: ofile, - extra: sess.opts.cg.extra_filename.clone(), - outputs: sess.opts.output_types.clone(), - } + OutputFilenames::new( + out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), + out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(), + ofile, + sess.opts.cg.extra_filename.clone(), + sess.opts.output_types.clone(), + ) } } } diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index b6b22e298ca62..08960cd44984b 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -447,9 +447,9 @@ impl Input { #[derive(Clone, Hash)] pub struct OutputFilenames { pub out_directory: PathBuf, - pub out_filestem: String, + out_filestem: String, pub single_output_file: Option, - pub extra: String, + extra: String, pub outputs: OutputTypes, } @@ -458,6 +458,16 @@ impl_stable_hash_via_hash!(OutputFilenames); pub const RUST_CGU_EXT: &str = "rcgu"; impl OutputFilenames { + pub fn new( + out_directory: PathBuf, + out_filestem: String, + single_output_file: Option, + extra: String, + outputs: OutputTypes, + ) -> Self { + OutputFilenames { out_directory, out_filestem, single_output_file, extra, outputs } + } + pub fn path(&self, flavor: OutputType) -> PathBuf { self.outputs .get(&flavor) From 8c6067c24e181aa388619ca0f39100e5c9a1f509 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 21 Jan 2020 09:54:58 -0500 Subject: [PATCH 13/18] Store filestem in a pre-formatted form --- src/librustc_session/config.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 08960cd44984b..81e8e47445859 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -447,9 +447,8 @@ impl Input { #[derive(Clone, Hash)] pub struct OutputFilenames { pub out_directory: PathBuf, - out_filestem: String, + filestem: String, pub single_output_file: Option, - extra: String, pub outputs: OutputTypes, } @@ -465,7 +464,12 @@ impl OutputFilenames { extra: String, outputs: OutputTypes, ) -> Self { - OutputFilenames { out_directory, out_filestem, single_output_file, extra, outputs } + OutputFilenames { + out_directory, + single_output_file, + outputs, + filestem: format!("{}{}", out_filestem, extra), + } } pub fn path(&self, flavor: OutputType) -> PathBuf { @@ -487,7 +491,7 @@ impl OutputFilenames { /// Like temp_path, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { - let base = self.out_directory.join(&self.filestem()); + let base = self.out_directory.join(&self.filestem); let mut extension = String::new(); @@ -505,16 +509,11 @@ impl OutputFilenames { extension.push_str(ext); } - let path = base.with_extension(&extension[..]); - path + base.with_extension(extension) } pub fn with_extension(&self, extension: &str) -> PathBuf { - self.out_directory.join(&self.filestem()).with_extension(extension) - } - - pub fn filestem(&self) -> String { - format!("{}{}", self.out_filestem, self.extra) + self.out_directory.join(&self.filestem).with_extension(extension) } } From dc97181a0966cd1686a70ce06849a19c196f72eb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 21 Jan 2020 09:57:50 -0500 Subject: [PATCH 14/18] Do not base path to append extension We already have ownership of the base path, so no need to clone it (within Path::with_extension). --- src/librustc_session/config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 81e8e47445859..c7fcd04c45a0a 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -491,8 +491,6 @@ impl OutputFilenames { /// Like temp_path, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { - let base = self.out_directory.join(&self.filestem); - let mut extension = String::new(); if let Some(codegen_unit_name) = codegen_unit_name { @@ -509,11 +507,13 @@ impl OutputFilenames { extension.push_str(ext); } - base.with_extension(extension) + self.with_extension(&extension) } pub fn with_extension(&self, extension: &str) -> PathBuf { - self.out_directory.join(&self.filestem).with_extension(extension) + let mut path = self.out_directory.join(&self.filestem); + path.set_extension(extension); + path } } From eb2da27af27c010bf5501bbe85341ccd457dc3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 22 Jan 2020 01:02:32 +0100 Subject: [PATCH 15/18] bootstrap: update clippy subcmd decription Clarify where the clippy used in `./x.py clippy` is coming from. It uses whatever clippy binary was installed via rustup, cargo-install or otherwise and does NOT use the binary generated by `./x.py build src/tools/clippy`. --- src/bootstrap/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 1fbdd50a51133..2101ef27f9d42 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -104,7 +104,7 @@ Usage: x.py [options] [...] Subcommands: build Compile either the compiler or libraries check Compile either the compiler or libraries, using cargo check - clippy Run clippy + clippy Run clippy (uses rustup/cargo-installed clippy binary) fix Run cargo fix fmt Run rustfmt test Build and run some test suites From 7962ccb216e993b52f67986f7944fba5fc38482c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 22 Jan 2020 01:38:05 +0100 Subject: [PATCH 16/18] pprust: use as_deref --- src/libsyntax/print/pprust.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index bc67980c454c0..6b21224b9b64c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1643,7 +1643,7 @@ impl<'a> State<'a> { self.print_expr_as_cond(i); self.s.space(); self.print_block(then); - self.print_else(e.as_ref().map(|e| &**e)) + self.print_else(e.as_deref()) } // Final `else` block. ast::ExprKind::Block(ref b, _) => { @@ -1947,7 +1947,7 @@ impl<'a> State<'a> { self.print_let(pat, scrutinee); } ast::ExprKind::If(ref test, ref blk, ref elseopt) => { - self.print_if(test, blk, elseopt.as_ref().map(|e| &**e)); + self.print_if(test, blk, elseopt.as_deref()) } ast::ExprKind::While(ref test, ref blk, opt_label) => { if let Some(label) = opt_label { From be86fb3516135944944318b873e6f3cfe0a599b0 Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Wed, 22 Jan 2020 21:36:39 +1100 Subject: [PATCH 17/18] Add some comments about CrateNum, CrateInfo and .rlink file format --- src/librustc_codegen_llvm/lib.rs | 1 + src/librustc_codegen_ssa/lib.rs | 6 ++++++ src/librustc_hir/def_id.rs | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 5af0e404183a9..70e3874035b60 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -301,6 +301,7 @@ impl CodegenBackend for LlvmCodegenBackend { } if sess.opts.debugging_opts.no_link { + // FIXME: use a binary format to encode the `.rlink` file let rlink_data = json::encode(&codegen_results).map_err(|err| { sess.fatal(&format!("failed to encode rlink: {}", err)); })?; diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 0ca9bbb74e5bb..474a15468d676 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -117,6 +117,12 @@ bitflags::bitflags! { } /// Misc info we load from metadata to persist beyond the tcx. +/// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` +/// is self-contained. `CrateNum` can be viewed as a unique identifier within a `CrateInfo`, where +/// `used_crate_source` contains all `CrateSource` of the dependents, and maintains a mapping from +/// identifiers (`CrateNum`) to `CrateSource`. The other fields map `CrateNum` to the crate's own +/// additional properties, so that effectively we can retrieve each dependent crate's `CrateSource` +/// and the corresponding properties without referencing information outside of a `CrateInfo`. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CrateInfo { pub panic_runtime: Option, diff --git a/src/librustc_hir/def_id.rs b/src/librustc_hir/def_id.rs index 80aa3ce6a4e14..7ee778ddd8ec7 100644 --- a/src/librustc_hir/def_id.rs +++ b/src/librustc_hir/def_id.rs @@ -87,6 +87,8 @@ impl fmt::Display for CrateNum { } } +/// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. +/// Therefore, make sure to include the context when encode a `CrateNum`. impl rustc_serialize::UseSpecializedEncodable for CrateNum { fn default_encode(&self, e: &mut E) -> Result<(), E::Error> { e.emit_u32(self.as_u32()) From 71370c87f74fa38a6976bec27ebe4f449058872c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 22 Jan 2020 17:19:26 +0100 Subject: [PATCH 18/18] librustc_mir: don't allocate vectors where slices will do. --- src/librustc_mir/transform/generator.rs | 4 ++-- src/librustc_mir/transform/instcombine.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 825ac4a28d869..8ac7772ea4818 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -117,7 +117,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { place, Place { local: self_arg(), - projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]), + projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]), }, self.tcx, ); @@ -153,7 +153,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { place, Place { local: self_arg(), - projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field( + projection: self.tcx().intern_place_elems(&[ProjectionElem::Field( Field::new(0), self.ref_gen_ty, )]), diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 69eedb1ae1876..afe42e6357128 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -51,7 +51,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { let new_place = match rvalue { Rvalue::Ref(_, _, place) => { if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { - place.projection = self.tcx().intern_place_elems(&vec![proj_r.clone()]); + place.projection = self.tcx().intern_place_elems(&[proj_r.clone()]); Place { // Replace with dummy