diff --git a/Cargo.lock b/Cargo.lock index 0a76aabc3a312..237b3dda670df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3428,6 +3428,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "serialize", "smallvec 1.0.0", "syntax", ] 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 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/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 546e73e33d7f3..2a68a25be21b3 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -160,6 +160,7 @@ 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 # 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 @@ -173,6 +174,10 @@ 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 \ + 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/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/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index d1c369d0abbf3..cdb50779e00cc 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -919,17 +919,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/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 9f3fc91548b21..2ba12baaf6d6e 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -59,31 +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(|| { + 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" + }) + }) + } + 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 function" + "an async method" } else { - "a function" + "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, } } 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..70e3874035b60 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,18 @@ impl CodegenBackend for LlvmCodegenBackend { return Ok(()); } + 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)); + })?; + 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 4679f6501336c..695f171dfb49c 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/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index bd44b4a38fd58..d680e14bbbd5b 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,16 @@ 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. + 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) { let symbol_name = metadata_symbol_name(tcx); let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index aba77231268e7..474a15468d676 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,13 @@ bitflags::bitflags! { } /// Misc info we load from metadata to persist beyond the tcx. -#[derive(Debug)] +/// 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, pub compiler_builtins: Option, @@ -135,6 +141,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..7ee778ddd8ec7 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,18 @@ impl fmt::Display for CrateNum { } } -impl rustc_serialize::UseSpecializedEncodable for CrateNum {} -impl rustc_serialize::UseSpecializedDecodable 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()) + } +} +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 +146,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_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_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 diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index b6b22e298ca62..aa492b566e59e 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, - pub out_filestem: String, + filestem: String, pub single_output_file: Option, - pub extra: String, pub outputs: OutputTypes, } @@ -458,6 +457,21 @@ 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, + single_output_file, + outputs, + filestem: format!("{}{}", out_filestem, extra), + } + } + pub fn path(&self, flavor: OutputType) -> PathBuf { self.outputs .get(&flavor) @@ -477,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 { @@ -495,16 +507,13 @@ impl OutputFilenames { extension.push_str(ext); } - let path = base.with_extension(&extension[..]); - path + self.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) + let mut path = self.out_directory.join(&self.filestem); + path.set_extension(extension); + path } } @@ -619,7 +628,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, 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/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 { 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/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3927e4f903011..f0ef33e2f622d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1645,7 +1645,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, _) => { @@ -1949,7 +1949,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 { 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( 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() {} 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 + 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`. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cff04e197e48a..98e9fe7a8b221 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -69,6 +69,7 @@ static TARGETS: &[&str] = &[ "thumbv7neon-linux-androideabi", "armv7-unknown-linux-gnueabi", "armv7-unknown-linux-gnueabihf", + "armv7a-none-eabi", "thumbv7neon-unknown-linux-gnueabihf", "armv7-unknown-linux-musleabi", "armv7-unknown-linux-musleabihf", 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 1f0b42d1786c1..1369fcf6f2361 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)) @@ -701,21 +727,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 } }