mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #139354 - matthiaskrgr:rollup-04lgx23, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #138949 (Rename `is_like_osx` to `is_like_darwin`) - #139295 (Remove creation of duplicate `AnonPipe`) - #139313 (Deduplicate some `rustc_middle` function bodies by calling the `rustc_type_ir` equivalent) - #139317 (compiletest: Encapsulate all of the code that touches libtest) - #139322 (Add helper function for checking LLD usage to `run-make-support`) - #139335 (Pass correct param-env to `error_implies`) - #139342 (Add a mailmap entry for myself) - #139349 (adt_destructor: sanity-check returned item) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a4166dabaa
2
.mailmap
2
.mailmap
@ -408,6 +408,8 @@ Luqman Aden <me@luqman.ca> <laden@mozilla.com>
|
||||
Luqman Aden <me@luqman.ca> <rust@luqman.ca>
|
||||
Lzu Tao <taolzu@gmail.com>
|
||||
Maik Klein <maikklein@googlemail.com>
|
||||
Maja Kądziołka <maya@compilercrim.es> <github@compilercrim.es>
|
||||
Maja Kądziołka <maya@compilercrim.es> <kuba@kadziolka.net>
|
||||
Malo Jaffré <jaffre.malo@gmail.com>
|
||||
Manish Goregaokar <manishsmail@gmail.com>
|
||||
Mara Bos <m-ou.se@m-ou.se>
|
||||
|
@ -641,7 +641,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||
.flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()),
|
||||
);
|
||||
|
||||
if fx.tcx.sess.target.is_like_osx && fx.tcx.sess.target.arch == "aarch64" {
|
||||
if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == "aarch64" {
|
||||
// Add any padding arguments needed for Apple AArch64.
|
||||
// There's no need to pad the argument list unless variadic arguments are actually being
|
||||
// passed.
|
||||
|
@ -391,7 +391,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
||||
data.set_align(alloc.align.bytes());
|
||||
|
||||
if let Some(section_name) = section_name {
|
||||
let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
|
||||
let (segment_name, section_name) = if tcx.sess.target.is_like_darwin {
|
||||
// See https://github.com/llvm/llvm-project/blob/main/llvm/lib/MC/MCSectionMachO.cpp
|
||||
let mut parts = section_name.as_str().split(',');
|
||||
let Some(segment_name) = parts.next() else {
|
||||
|
@ -58,7 +58,7 @@ impl DebugContext {
|
||||
// FIXME this should be configurable
|
||||
// macOS doesn't seem to support DWARF > 3
|
||||
// 5 version is required for md5 file hash
|
||||
version: if tcx.sess.target.is_like_osx {
|
||||
version: if tcx.sess.target.is_like_darwin {
|
||||
3
|
||||
} else {
|
||||
// FIXME change to version 5 once the gdb and lldb shipping with the latest debian
|
||||
|
@ -131,7 +131,7 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
// will use load-unaligned instructions instead, and thus avoiding the crash.
|
||||
//
|
||||
// We could remove this hack whenever we decide to drop macOS 10.10 support.
|
||||
if self.tcx.sess.target.options.is_like_osx {
|
||||
if self.tcx.sess.target.options.is_like_darwin {
|
||||
// The `inspect` method is okay here because we checked for provenance, and
|
||||
// because we are doing this access to inspect the final interpreter state
|
||||
// (not as part of the interpreter execution).
|
||||
|
@ -1024,7 +1024,7 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data:
|
||||
}
|
||||
|
||||
pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static CStr {
|
||||
if cgcx.target_is_like_osx {
|
||||
if cgcx.target_is_like_darwin {
|
||||
c"__LLVM,__bitcode"
|
||||
} else if cgcx.target_is_like_aix {
|
||||
c".ipa"
|
||||
@ -1077,7 +1077,7 @@ unsafe fn embed_bitcode(
|
||||
// and COFF we emit the sections using module level inline assembly for that
|
||||
// reason (see issue #90326 for historical background).
|
||||
unsafe {
|
||||
if cgcx.target_is_like_osx
|
||||
if cgcx.target_is_like_darwin
|
||||
|| cgcx.target_is_like_aix
|
||||
|| cgcx.target_arch == "wasm32"
|
||||
|| cgcx.target_arch == "wasm64"
|
||||
@ -1096,7 +1096,7 @@ unsafe fn embed_bitcode(
|
||||
let llglobal =
|
||||
llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline");
|
||||
llvm::set_initializer(llglobal, llconst);
|
||||
let section = if cgcx.target_is_like_osx {
|
||||
let section = if cgcx.target_is_like_darwin {
|
||||
c"__LLVM,__cmdline"
|
||||
} else if cgcx.target_is_like_aix {
|
||||
c".info"
|
||||
|
@ -120,7 +120,7 @@ impl CodegenCx<'_, '_> {
|
||||
}
|
||||
|
||||
// Match clang by only supporting COFF and ELF for now.
|
||||
if self.tcx.sess.target.is_like_osx {
|
||||
if self.tcx.sess.target.is_like_darwin {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -399,7 +399,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
|
||||
emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), false)
|
||||
}
|
||||
// macOS / iOS AArch64
|
||||
"aarch64" if target.is_like_osx => {
|
||||
"aarch64" if target.is_like_darwin => {
|
||||
emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
|
||||
}
|
||||
"aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
|
||||
|
@ -1012,7 +1012,7 @@ fn link_natively(
|
||||
// On macOS the external `dsymutil` tool is used to create the packed
|
||||
// debug information. Note that this will read debug information from
|
||||
// the objects on the filesystem which we'll clean up later.
|
||||
SplitDebuginfo::Packed if sess.target.is_like_osx => {
|
||||
SplitDebuginfo::Packed if sess.target.is_like_darwin => {
|
||||
let prog = Command::new("dsymutil").arg(out_filename).output();
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
@ -1043,7 +1043,7 @@ fn link_natively(
|
||||
|
||||
let strip = sess.opts.cg.strip;
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
if sess.target.is_like_darwin {
|
||||
let stripcmd = "rust-objcopy";
|
||||
match (strip, crate_type) {
|
||||
(Strip::Debuginfo, _) => {
|
||||
@ -1241,7 +1241,7 @@ fn add_sanitizer_libraries(
|
||||
// Everywhere else the runtimes are currently distributed as static
|
||||
// libraries which should be linked to executables only.
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
|
||||
&& !(sess.target.is_like_osx || sess.target.is_like_msvc)
|
||||
&& !(sess.target.is_like_darwin || sess.target.is_like_msvc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1294,7 +1294,7 @@ fn link_sanitizer_runtime(
|
||||
let channel =
|
||||
option_env!("CFG_RELEASE_CHANNEL").map(|channel| format!("-{channel}")).unwrap_or_default();
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
if sess.target.is_like_darwin {
|
||||
// On Apple platforms, the sanitizer is always built as a dylib, and
|
||||
// LLVM will link to `@rpath/*.dylib`, so we need to specify an
|
||||
// rpath to the library as well (the rpath should be absolute, see
|
||||
@ -2182,7 +2182,7 @@ fn add_rpath_args(
|
||||
let rpath_config = RPathConfig {
|
||||
libs: &*libs,
|
||||
out_filename: out_filename.to_path_buf(),
|
||||
is_like_osx: sess.target.is_like_osx,
|
||||
is_like_darwin: sess.target.is_like_darwin,
|
||||
linker_is_gnu: sess.target.linker_flavor.is_gnu(),
|
||||
};
|
||||
cmd.link_args(&rpath::get_rpath_linker_args(&rpath_config));
|
||||
@ -3044,7 +3044,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool
|
||||
/// - The deployment target.
|
||||
/// - The SDK version.
|
||||
fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
|
||||
if !sess.target.is_like_osx {
|
||||
if !sess.target.is_like_darwin {
|
||||
return;
|
||||
}
|
||||
let LinkerFlavor::Darwin(cc, _) = flavor else {
|
||||
|
@ -373,7 +373,7 @@ impl<'a> GccLinker<'a> {
|
||||
// * On OSX they have their own linker, not binutils'
|
||||
// * For WebAssembly the only functional linker is LLD, which doesn't
|
||||
// support hint flags
|
||||
!self.sess.target.is_like_osx && !self.sess.target.is_like_wasm
|
||||
!self.sess.target.is_like_darwin && !self.sess.target.is_like_wasm
|
||||
}
|
||||
|
||||
// Some platforms take hints about whether a library is static or dynamic.
|
||||
@ -425,7 +425,7 @@ impl<'a> GccLinker<'a> {
|
||||
|
||||
fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
if self.is_cc() {
|
||||
// `-dynamiclib` makes `cc` pass `-dylib` to the linker.
|
||||
self.cc_arg("-dynamiclib");
|
||||
@ -471,7 +471,7 @@ impl<'a> GccLinker<'a> {
|
||||
|
||||
fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
|
||||
if !as_needed {
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
// FIXME(81490): ld64 doesn't support these flags but macOS 11
|
||||
// has -needed-l{} / -needed_library {}
|
||||
// but we have no way to detect that here.
|
||||
@ -486,7 +486,7 @@ impl<'a> GccLinker<'a> {
|
||||
f(self);
|
||||
|
||||
if !as_needed {
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
// See above FIXME comment
|
||||
} else if self.is_gnu && !self.sess.target.is_like_windows {
|
||||
self.link_arg("--as-needed");
|
||||
@ -619,7 +619,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
let colon = if verbatim && self.is_gnu { ":" } else { "" };
|
||||
if !whole_archive {
|
||||
self.link_or_cc_arg(format!("-l{colon}{name}"));
|
||||
} else if self.sess.target.is_like_osx {
|
||||
} else if self.sess.target.is_like_darwin {
|
||||
// -force_load is the macOS equivalent of --whole-archive, but it
|
||||
// involves passing the full path to the library to link.
|
||||
self.link_arg("-force_load");
|
||||
@ -635,7 +635,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
self.hint_static();
|
||||
if !whole_archive {
|
||||
self.link_or_cc_arg(path);
|
||||
} else if self.sess.target.is_like_osx {
|
||||
} else if self.sess.target.is_like_darwin {
|
||||
self.link_arg("-force_load").link_arg(path);
|
||||
} else {
|
||||
self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
|
||||
@ -670,7 +670,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
// -dead_strip can't be part of the pre_link_args because it's also used
|
||||
// for partial linking when using multiple codegen units (-r). So we
|
||||
// insert it here.
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
self.link_arg("-dead_strip");
|
||||
|
||||
// If we're building a dylib, we don't use --gc-sections because LLVM
|
||||
@ -728,7 +728,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
|
||||
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
|
||||
// MacOS linker doesn't support stripping symbols directly anymore.
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -795,7 +795,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
|
||||
debug!("EXPORTED SYMBOLS:");
|
||||
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
// Write a plain, newline-separated list of symbols
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
@ -841,7 +841,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.sess.target.is_like_osx {
|
||||
if self.sess.target.is_like_darwin {
|
||||
self.link_arg("-exported_symbols_list").link_arg(path);
|
||||
} else if self.sess.target.is_like_solaris {
|
||||
self.link_arg("-M").link_arg(path);
|
||||
|
@ -214,7 +214,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
|
||||
let mut file = write::Object::new(binary_format, architecture, endianness);
|
||||
file.set_sub_architecture(sub_architecture);
|
||||
if sess.target.is_like_osx {
|
||||
if sess.target.is_like_darwin {
|
||||
if macho_is_arm64e(&sess.target) {
|
||||
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub mod write;
|
||||
///
|
||||
/// Certain optimizations also depend on the deployment target.
|
||||
pub fn versioned_llvm_target(sess: &Session) -> Cow<'_, str> {
|
||||
if sess.target.is_like_osx {
|
||||
if sess.target.is_like_darwin {
|
||||
apple::add_version_to_llvm_target(&sess.target.llvm_target, apple::deployment_target(sess))
|
||||
.into()
|
||||
} else {
|
||||
|
@ -9,7 +9,7 @@ use tracing::debug;
|
||||
pub(super) struct RPathConfig<'a> {
|
||||
pub libs: &'a [&'a Path],
|
||||
pub out_filename: PathBuf,
|
||||
pub is_like_osx: bool,
|
||||
pub is_like_darwin: bool,
|
||||
pub linker_is_gnu: bool,
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ fn get_rpaths_relative_to_output(config: &RPathConfig<'_>) -> Vec<OsString> {
|
||||
|
||||
fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsString {
|
||||
// Mac doesn't appear to support $ORIGIN
|
||||
let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
|
||||
let prefix = if config.is_like_darwin { "@loader_path" } else { "$ORIGIN" };
|
||||
|
||||
// Strip filenames
|
||||
let lib = lib.parent().unwrap();
|
||||
|
@ -28,7 +28,7 @@ fn test_rpath_relative() {
|
||||
if cfg!(target_os = "macos") {
|
||||
let config = &mut RPathConfig {
|
||||
libs: &[],
|
||||
is_like_osx: true,
|
||||
is_like_darwin: true,
|
||||
linker_is_gnu: false,
|
||||
out_filename: PathBuf::from("bin/rustc"),
|
||||
};
|
||||
@ -38,7 +38,7 @@ fn test_rpath_relative() {
|
||||
let config = &mut RPathConfig {
|
||||
libs: &[],
|
||||
out_filename: PathBuf::from("bin/rustc"),
|
||||
is_like_osx: false,
|
||||
is_like_darwin: false,
|
||||
linker_is_gnu: true,
|
||||
};
|
||||
let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so"));
|
||||
@ -51,7 +51,7 @@ fn test_rpath_relative_issue_119571() {
|
||||
let config = &mut RPathConfig {
|
||||
libs: &[],
|
||||
out_filename: PathBuf::from("rustc"),
|
||||
is_like_osx: false,
|
||||
is_like_darwin: false,
|
||||
linker_is_gnu: true,
|
||||
};
|
||||
// Should not panic when out_filename only contains filename.
|
||||
|
@ -352,7 +352,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
||||
pub is_pe_coff: bool,
|
||||
pub target_can_use_split_dwarf: bool,
|
||||
pub target_arch: String,
|
||||
pub target_is_like_osx: bool,
|
||||
pub target_is_like_darwin: bool,
|
||||
pub target_is_like_aix: bool,
|
||||
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
|
||||
pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
|
||||
@ -1216,7 +1216,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||
is_pe_coff: tcx.sess.target.is_like_windows,
|
||||
target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(),
|
||||
target_arch: tcx.sess.target.arch.to_string(),
|
||||
target_is_like_osx: tcx.sess.target.is_like_osx,
|
||||
target_is_like_darwin: tcx.sess.target.is_like_darwin,
|
||||
target_is_like_aix: tcx.sess.target.is_like_aix,
|
||||
split_debuginfo: tcx.sess.split_debuginfo(),
|
||||
split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind,
|
||||
|
@ -213,7 +213,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
// somewhat, and is subject to change in the future (which
|
||||
// is a good thing, because this would ideally be a bit
|
||||
// more firmed up).
|
||||
let is_like_elf = !(tcx.sess.target.is_like_osx
|
||||
let is_like_elf = !(tcx.sess.target.is_like_darwin
|
||||
|| tcx.sess.target.is_like_windows
|
||||
|| tcx.sess.target.is_like_wasm);
|
||||
codegen_fn_attrs.flags |= if is_like_elf {
|
||||
|
@ -807,7 +807,7 @@ fn print_crate_info(
|
||||
}
|
||||
}
|
||||
DeploymentTarget => {
|
||||
if sess.target.is_like_osx {
|
||||
if sess.target.is_like_darwin {
|
||||
println_info!(
|
||||
"{}={}",
|
||||
apple::deployment_target_env_var(&sess.target.os),
|
||||
|
@ -27,6 +27,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::select;
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{
|
||||
self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
|
||||
@ -268,7 +269,7 @@ pub struct InferCtxt<'tcx> {
|
||||
/// The set of predicates on which errors have been reported, to
|
||||
/// avoid reporting the same error twice.
|
||||
pub reported_trait_errors:
|
||||
RefCell<FxIndexMap<Span, (Vec<ty::Predicate<'tcx>>, ErrorGuaranteed)>>,
|
||||
RefCell<FxIndexMap<Span, (Vec<Goal<'tcx, ty::Predicate<'tcx>>>, ErrorGuaranteed)>>,
|
||||
|
||||
pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
|
||||
|
||||
|
@ -73,7 +73,7 @@ pub fn walk_native_lib_search_dirs<R>(
|
||||
|| sess.target.os == "linux"
|
||||
|| sess.target.os == "fuchsia"
|
||||
|| sess.target.is_like_aix
|
||||
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
|
||||
|| sess.target.is_like_darwin && !sess.opts.unstable_opts.sanitizer.is_empty()
|
||||
{
|
||||
f(&sess.target_tlib_path.dir, false)?;
|
||||
}
|
||||
@ -257,7 +257,7 @@ impl<'tcx> Collector<'tcx> {
|
||||
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
|
||||
"dylib" => NativeLibKind::Dylib { as_needed: None },
|
||||
"framework" => {
|
||||
if !sess.target.is_like_osx {
|
||||
if !sess.target.is_like_darwin {
|
||||
sess.dcx().emit_err(errors::LinkFrameworkApple { span });
|
||||
}
|
||||
NativeLibKind::Framework { as_needed: None }
|
||||
@ -531,7 +531,7 @@ impl<'tcx> Collector<'tcx> {
|
||||
let mut renames = FxHashSet::default();
|
||||
for lib in &self.tcx.sess.opts.libs {
|
||||
if let NativeLibKind::Framework { .. } = lib.kind
|
||||
&& !self.tcx.sess.target.is_like_osx
|
||||
&& !self.tcx.sess.target.is_like_darwin
|
||||
{
|
||||
// Cannot check this when parsing options because the target is not yet available.
|
||||
self.tcx.dcx().emit_err(errors::LibFrameworkApple);
|
||||
|
@ -8,7 +8,7 @@ use std::iter;
|
||||
use std::ops::{ControlFlow, Range};
|
||||
|
||||
use hir::def::{CtorKind, DefKind};
|
||||
use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx};
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
|
||||
use rustc_errors::{ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::LangItem;
|
||||
@ -1441,23 +1441,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(tcx))]
|
||||
pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
|
||||
match self.kind() {
|
||||
FnDef(def_id, args) => tcx.fn_sig(*def_id).instantiate(tcx, args),
|
||||
FnPtr(sig_tys, hdr) => sig_tys.with(*hdr),
|
||||
Error(_) => {
|
||||
// ignore errors (#54954)
|
||||
Binder::dummy(ty::FnSig {
|
||||
inputs_and_output: ty::List::empty(),
|
||||
c_variadic: false,
|
||||
safety: hir::Safety::Safe,
|
||||
abi: ExternAbi::Rust,
|
||||
})
|
||||
}
|
||||
Closure(..) => bug!(
|
||||
"to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
|
||||
),
|
||||
_ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self),
|
||||
}
|
||||
self.kind().fn_sig(tcx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -2043,32 +2027,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
/// nested types may be further simplified, the outermost [`TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
pub fn is_known_rigid(self) -> bool {
|
||||
match self.kind() {
|
||||
Bool
|
||||
| Char
|
||||
| Int(_)
|
||||
| Uint(_)
|
||||
| Float(_)
|
||||
| Adt(_, _)
|
||||
| Foreign(_)
|
||||
| Str
|
||||
| Array(_, _)
|
||||
| Pat(_, _)
|
||||
| Slice(_)
|
||||
| RawPtr(_, _)
|
||||
| Ref(_, _, _)
|
||||
| FnDef(_, _)
|
||||
| FnPtr(..)
|
||||
| Dynamic(_, _, _)
|
||||
| Closure(_, _)
|
||||
| CoroutineClosure(_, _)
|
||||
| Coroutine(_, _)
|
||||
| CoroutineWitness(..)
|
||||
| Never
|
||||
| Tuple(_)
|
||||
| UnsafeBinder(_) => true,
|
||||
Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false,
|
||||
}
|
||||
self.kind().is_known_rigid()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,6 +414,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
continue;
|
||||
};
|
||||
|
||||
if self.def_kind(item_id) != DefKind::AssocFn {
|
||||
self.dcx().span_delayed_bug(self.def_span(item_id), "drop is not a function");
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(old_item_id) = dtor_candidate {
|
||||
self.dcx()
|
||||
.struct_span_err(self.def_span(item_id), "multiple drop impls found")
|
||||
|
@ -78,7 +78,7 @@ pub(crate) fn target_reserves_x18(target: &Target, target_features: &FxIndexSet<
|
||||
target.os == "android"
|
||||
|| target.os == "fuchsia"
|
||||
|| target.env == "ohos"
|
||||
|| target.is_like_osx
|
||||
|| target.is_like_darwin
|
||||
|| target.is_like_windows
|
||||
|| target_features.contains(&sym::reserve_x18)
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ impl ArmInlineAsmRegClass {
|
||||
|
||||
// This uses the same logic as useR7AsFramePointer in LLVM
|
||||
fn frame_pointer_is_r7(target_features: &FxIndexSet<Symbol>, target: &Target) -> bool {
|
||||
target.is_like_osx || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
|
||||
target.is_like_darwin || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
|
||||
}
|
||||
|
||||
fn frame_pointer_r11(
|
||||
|
@ -670,7 +670,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
}
|
||||
},
|
||||
"aarch64" | "arm64ec" => {
|
||||
let kind = if cx.target_spec().is_like_osx {
|
||||
let kind = if cx.target_spec().is_like_darwin {
|
||||
aarch64::AbiKind::DarwinPCS
|
||||
} else if cx.target_spec().is_like_windows {
|
||||
aarch64::AbiKind::Win64
|
||||
|
@ -104,7 +104,7 @@ where
|
||||
let byval_align = if arg.layout.align.abi < align_4 {
|
||||
// (1.)
|
||||
align_4
|
||||
} else if t.is_like_osx && contains_vector(cx, arg.layout) {
|
||||
} else if t.is_like_darwin && contains_vector(cx, arg.layout) {
|
||||
// (3.)
|
||||
align_16
|
||||
} else {
|
||||
|
@ -115,7 +115,7 @@ pub(crate) fn base(
|
||||
function_sections: false,
|
||||
dynamic_linking: true,
|
||||
families: cvs!["unix"],
|
||||
is_like_osx: true,
|
||||
is_like_darwin: true,
|
||||
binary_format: BinaryFormat::MachO,
|
||||
// LLVM notes that macOS 10.11+ and iOS 9+ default
|
||||
// to v4, so we do the same.
|
||||
|
@ -598,7 +598,7 @@ impl Target {
|
||||
key!(families, target_families);
|
||||
key!(abi_return_struct_as_int, bool);
|
||||
key!(is_like_aix, bool);
|
||||
key!(is_like_osx, bool);
|
||||
key!(is_like_darwin, bool);
|
||||
key!(is_like_solaris, bool);
|
||||
key!(is_like_windows, bool);
|
||||
key!(is_like_msvc, bool);
|
||||
@ -777,7 +777,7 @@ impl ToJson for Target {
|
||||
target_option_val!(families, "target-family");
|
||||
target_option_val!(abi_return_struct_as_int);
|
||||
target_option_val!(is_like_aix);
|
||||
target_option_val!(is_like_osx);
|
||||
target_option_val!(is_like_darwin);
|
||||
target_option_val!(is_like_solaris);
|
||||
target_option_val!(is_like_windows);
|
||||
target_option_val!(is_like_msvc);
|
||||
|
@ -81,7 +81,7 @@ pub enum Lld {
|
||||
/// of classes that we call "linker flavors".
|
||||
///
|
||||
/// Technically, it's not even necessary, we can nearly always infer the flavor from linker name
|
||||
/// and target properties like `is_like_windows`/`is_like_osx`/etc. However, the PRs originally
|
||||
/// and target properties like `is_like_windows`/`is_like_darwin`/etc. However, the PRs originally
|
||||
/// introducing `-Clinker-flavor` (#40018 and friends) were aiming to reduce this kind of inference
|
||||
/// and provide something certain and explicitly specified instead, and that design goal is still
|
||||
/// relevant now.
|
||||
@ -2406,7 +2406,7 @@ pub struct TargetOptions {
|
||||
/// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
|
||||
/// Also indicates whether to use Apple-specific ABI changes, such as extending function
|
||||
/// parameters to 32-bits.
|
||||
pub is_like_osx: bool,
|
||||
pub is_like_darwin: bool,
|
||||
/// Whether the target toolchain is like Solaris's.
|
||||
/// Only useful for compiling against Illumos/Solaris,
|
||||
/// as they have a different set of linker flags. Defaults to false.
|
||||
@ -2700,7 +2700,7 @@ fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'stati
|
||||
impl TargetOptions {
|
||||
pub fn supports_comdat(&self) -> bool {
|
||||
// XCOFF and MachO don't support COMDAT.
|
||||
!self.is_like_aix && !self.is_like_osx
|
||||
!self.is_like_aix && !self.is_like_darwin
|
||||
}
|
||||
}
|
||||
|
||||
@ -2804,7 +2804,7 @@ impl Default for TargetOptions {
|
||||
families: cvs![],
|
||||
abi_return_struct_as_int: false,
|
||||
is_like_aix: false,
|
||||
is_like_osx: false,
|
||||
is_like_darwin: false,
|
||||
is_like_solaris: false,
|
||||
is_like_windows: false,
|
||||
is_like_msvc: false,
|
||||
@ -3070,9 +3070,9 @@ impl Target {
|
||||
}
|
||||
|
||||
check_eq!(
|
||||
self.is_like_osx,
|
||||
self.is_like_darwin,
|
||||
self.vendor == "apple",
|
||||
"`is_like_osx` must be set if and only if `vendor` is `apple`"
|
||||
"`is_like_darwin` must be set if and only if `vendor` is `apple`"
|
||||
);
|
||||
check_eq!(
|
||||
self.is_like_solaris,
|
||||
@ -3098,9 +3098,9 @@ impl Target {
|
||||
|
||||
// Check that default linker flavor is compatible with some other key properties.
|
||||
check_eq!(
|
||||
self.is_like_osx,
|
||||
self.is_like_darwin,
|
||||
matches!(self.linker_flavor, LinkerFlavor::Darwin(..)),
|
||||
"`linker_flavor` must be `darwin` if and only if `is_like_osx` is set"
|
||||
"`linker_flavor` must be `darwin` if and only if `is_like_darwin` is set"
|
||||
);
|
||||
check_eq!(
|
||||
self.is_like_msvc,
|
||||
|
@ -14,6 +14,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{self as hir, LangItem, Node};
|
||||
use rustc_infer::infer::{InferOk, TypeTrace};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_middle::traits::SignatureMismatchData;
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
@ -930,7 +931,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
)) = arg.kind
|
||||
&& let Node::Pat(pat) = self.tcx.hir_node(*hir_id)
|
||||
&& let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span)
|
||||
&& preds.contains(&obligation.predicate)
|
||||
&& preds.contains(&obligation.as_goal())
|
||||
{
|
||||
return Err(*guar);
|
||||
}
|
||||
@ -1292,6 +1293,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
fn can_match_trait(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
goal: ty::TraitPredicate<'tcx>,
|
||||
assumption: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
@ -1306,11 +1308,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
assumption,
|
||||
);
|
||||
|
||||
self.can_eq(ty::ParamEnv::empty(), goal.trait_ref, trait_assumption.trait_ref)
|
||||
self.can_eq(param_env, goal.trait_ref, trait_assumption.trait_ref)
|
||||
}
|
||||
|
||||
fn can_match_projection(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
goal: ty::ProjectionPredicate<'tcx>,
|
||||
assumption: ty::PolyProjectionPredicate<'tcx>,
|
||||
) -> bool {
|
||||
@ -1320,7 +1323,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
assumption,
|
||||
);
|
||||
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
self.can_eq(param_env, goal.projection_term, assumption.projection_term)
|
||||
&& self.can_eq(param_env, goal.term, assumption.term)
|
||||
}
|
||||
@ -1330,24 +1332,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(super) fn error_implies(
|
||||
&self,
|
||||
cond: ty::Predicate<'tcx>,
|
||||
error: ty::Predicate<'tcx>,
|
||||
cond: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
error: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) -> bool {
|
||||
if cond == error {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(error) = error.as_trait_clause() {
|
||||
// FIXME: We could be smarter about this, i.e. if cond's param-env is a
|
||||
// subset of error's param-env. This only matters when binders will carry
|
||||
// predicates though, and obviously only matters for error reporting.
|
||||
if cond.param_env != error.param_env {
|
||||
return false;
|
||||
}
|
||||
let param_env = error.param_env;
|
||||
|
||||
if let Some(error) = error.predicate.as_trait_clause() {
|
||||
self.enter_forall(error, |error| {
|
||||
elaborate(self.tcx, std::iter::once(cond))
|
||||
elaborate(self.tcx, std::iter::once(cond.predicate))
|
||||
.filter_map(|implied| implied.as_trait_clause())
|
||||
.any(|implied| self.can_match_trait(error, implied))
|
||||
.any(|implied| self.can_match_trait(param_env, error, implied))
|
||||
})
|
||||
} else if let Some(error) = error.as_projection_clause() {
|
||||
} else if let Some(error) = error.predicate.as_projection_clause() {
|
||||
self.enter_forall(error, |error| {
|
||||
elaborate(self.tcx, std::iter::once(cond))
|
||||
elaborate(self.tcx, std::iter::once(cond.predicate))
|
||||
.filter_map(|implied| implied.as_projection_clause())
|
||||
.any(|implied| self.can_match_projection(error, implied))
|
||||
.any(|implied| self.can_match_projection(param_env, error, implied))
|
||||
})
|
||||
} else {
|
||||
false
|
||||
|
@ -12,6 +12,7 @@ use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_cod
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{self as hir, AmbigArg, LangItem};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::{
|
||||
DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
|
||||
PredicateObligation, SelectionError,
|
||||
@ -144,7 +145,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ErrorDescriptor<'tcx> {
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
index: Option<usize>, // None if this is an old error
|
||||
}
|
||||
|
||||
@ -152,15 +153,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
.reported_trait_errors
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(&span, predicates)| {
|
||||
(
|
||||
span,
|
||||
predicates
|
||||
.0
|
||||
.iter()
|
||||
.map(|&predicate| ErrorDescriptor { predicate, index: None })
|
||||
.collect(),
|
||||
)
|
||||
.map(|(&span, goals)| {
|
||||
(span, goals.0.iter().map(|&goal| ErrorDescriptor { goal, index: None }).collect())
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -186,10 +180,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
span = expn_data.call_site;
|
||||
}
|
||||
|
||||
error_map.entry(span).or_default().push(ErrorDescriptor {
|
||||
predicate: error.obligation.predicate,
|
||||
index: Some(index),
|
||||
});
|
||||
error_map
|
||||
.entry(span)
|
||||
.or_default()
|
||||
.push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
|
||||
}
|
||||
|
||||
// We do this in 2 passes because we want to display errors in order, though
|
||||
@ -210,9 +204,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.error_implies(error2.predicate, error.predicate)
|
||||
if self.error_implies(error2.goal, error.goal)
|
||||
&& !(error2.index >= error.index
|
||||
&& self.error_implies(error.predicate, error2.predicate))
|
||||
&& self.error_implies(error.goal, error2.goal))
|
||||
{
|
||||
info!("skipping {:?} (implied by {:?})", error, error2);
|
||||
is_suppressed[index] = true;
|
||||
@ -243,7 +237,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
.entry(span)
|
||||
.or_insert_with(|| (vec![], guar))
|
||||
.0
|
||||
.push(error.obligation.predicate);
|
||||
.push(error.obligation.as_goal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,67 +146,14 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
fn has_unsafe_fields(self) -> bool;
|
||||
|
||||
fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
|
||||
match self.kind() {
|
||||
ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
|
||||
ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, args),
|
||||
ty::Error(_) => {
|
||||
// ignore errors (#54954)
|
||||
ty::Binder::dummy(ty::FnSig {
|
||||
inputs_and_output: Default::default(),
|
||||
c_variadic: false,
|
||||
safety: I::Safety::safe(),
|
||||
abi: I::Abi::rust(),
|
||||
})
|
||||
}
|
||||
ty::Closure(..) => panic!(
|
||||
"to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
|
||||
),
|
||||
_ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self),
|
||||
}
|
||||
self.kind().fn_sig(interner)
|
||||
}
|
||||
|
||||
fn discriminant_ty(self, interner: I) -> I::Ty;
|
||||
|
||||
fn async_destructor_ty(self, interner: I) -> I::Ty;
|
||||
|
||||
/// Returns `true` when the outermost type cannot be further normalized,
|
||||
/// resolved, or instantiated. This includes all primitive types, but also
|
||||
/// things like ADTs and trait objects, since even if their arguments or
|
||||
/// nested types may be further simplified, the outermost [`ty::TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
fn is_known_rigid(self) -> bool {
|
||||
match self.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(..)
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_) => true,
|
||||
|
||||
ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_) => false,
|
||||
}
|
||||
self.kind().is_known_rigid()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,6 +273,68 @@ pub enum TyKind<I: Interner> {
|
||||
Error(I::ErrorGuaranteed),
|
||||
}
|
||||
|
||||
impl<I: Interner> TyKind<I> {
|
||||
pub fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
|
||||
match self {
|
||||
ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
|
||||
ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, args),
|
||||
ty::Error(_) => {
|
||||
// ignore errors (#54954)
|
||||
ty::Binder::dummy(ty::FnSig {
|
||||
inputs_and_output: Default::default(),
|
||||
c_variadic: false,
|
||||
safety: I::Safety::safe(),
|
||||
abi: I::Abi::rust(),
|
||||
})
|
||||
}
|
||||
ty::Closure(..) => panic!(
|
||||
"to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
|
||||
),
|
||||
_ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` when the outermost type cannot be further normalized,
|
||||
/// resolved, or instantiated. This includes all primitive types, but also
|
||||
/// things like ADTs and trait objects, since even if their arguments or
|
||||
/// nested types may be further simplified, the outermost [`ty::TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
pub fn is_known_rigid(self) -> bool {
|
||||
match self {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(..)
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_) => true,
|
||||
|
||||
ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is manually implemented because a derive would require `I: Debug`
|
||||
impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -143,7 +143,6 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
|
||||
};
|
||||
opts.security_attributes(&mut sa);
|
||||
let theirs = File::open(Path::new(&name), &opts)?;
|
||||
let theirs = AnonPipe { inner: theirs.into_inner() };
|
||||
|
||||
Ok(Pipes {
|
||||
ours: AnonPipe { inner: ours },
|
||||
|
@ -9,9 +9,9 @@ use std::{fmt, iter};
|
||||
use build_helper::git::GitConfig;
|
||||
use semver::Version;
|
||||
use serde::de::{Deserialize, Deserializer, Error as _};
|
||||
use test::{ColorConfig, OutputFormat};
|
||||
|
||||
pub use self::Mode::*;
|
||||
use crate::executor::{ColorConfig, OutputFormat};
|
||||
use crate::util::{PathBufExt, add_dylib_path};
|
||||
|
||||
macro_rules! string_enum {
|
||||
@ -178,6 +178,10 @@ pub struct Config {
|
||||
/// `true` to overwrite stderr/stdout files instead of complaining about changes in output.
|
||||
pub bless: bool,
|
||||
|
||||
/// Stop as soon as possible after any test fails.
|
||||
/// May run a few more tests before stopping, due to threading.
|
||||
pub fail_fast: bool,
|
||||
|
||||
/// The library paths required for running the compiler.
|
||||
pub compile_lib_path: PathBuf,
|
||||
|
||||
|
156
src/tools/compiletest/src/executor.rs
Normal file
156
src/tools/compiletest/src/executor.rs
Normal file
@ -0,0 +1,156 @@
|
||||
//! This module encapsulates all of the code that interacts directly with
|
||||
//! libtest, to execute the collected tests.
|
||||
//!
|
||||
//! This will hopefully make it easier to migrate away from libtest someday.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::common::{Config, TestPaths};
|
||||
|
||||
/// Delegates to libtest to run the list of collected tests.
|
||||
///
|
||||
/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed.
|
||||
pub(crate) fn execute_tests(config: &Config, tests: Vec<CollectedTest>) -> io::Result<bool> {
|
||||
let opts = test_opts(config);
|
||||
let tests = tests.into_iter().map(|t| t.into_libtest()).collect::<Vec<_>>();
|
||||
|
||||
test::run_tests_console(&opts, tests)
|
||||
}
|
||||
|
||||
/// Information needed to create a `test::TestDescAndFn`.
|
||||
pub(crate) struct CollectedTest {
|
||||
pub(crate) desc: CollectedTestDesc,
|
||||
pub(crate) config: Arc<Config>,
|
||||
pub(crate) testpaths: TestPaths,
|
||||
pub(crate) revision: Option<String>,
|
||||
}
|
||||
|
||||
/// Information needed to create a `test::TestDesc`.
|
||||
pub(crate) struct CollectedTestDesc {
|
||||
pub(crate) name: String,
|
||||
pub(crate) ignore: bool,
|
||||
pub(crate) ignore_message: Option<Cow<'static, str>>,
|
||||
pub(crate) should_panic: ShouldPanic,
|
||||
}
|
||||
|
||||
impl CollectedTest {
|
||||
fn into_libtest(self) -> test::TestDescAndFn {
|
||||
let Self { desc, config, testpaths, revision } = self;
|
||||
let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc;
|
||||
|
||||
// Libtest requires the ignore message to be a &'static str, so we might
|
||||
// have to leak memory to create it. This is fine, as we only do so once
|
||||
// per test, so the leak won't grow indefinitely.
|
||||
let ignore_message = ignore_message.map(|msg| match msg {
|
||||
Cow::Borrowed(s) => s,
|
||||
Cow::Owned(s) => &*String::leak(s),
|
||||
});
|
||||
|
||||
let desc = test::TestDesc {
|
||||
name: test::DynTestName(name),
|
||||
ignore,
|
||||
ignore_message,
|
||||
source_file: "",
|
||||
start_line: 0,
|
||||
start_col: 0,
|
||||
end_line: 0,
|
||||
end_col: 0,
|
||||
should_panic: should_panic.to_libtest(),
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
test_type: test::TestType::Unknown,
|
||||
};
|
||||
|
||||
// This closure is invoked when libtest returns control to compiletest
|
||||
// to execute the test.
|
||||
let testfn = test::DynTestFn(Box::new(move || {
|
||||
crate::runtest::run(config, &testpaths, revision.as_deref());
|
||||
Ok(())
|
||||
}));
|
||||
|
||||
test::TestDescAndFn { desc, testfn }
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether console output should be colored or not.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub enum ColorConfig {
|
||||
#[default]
|
||||
AutoColor,
|
||||
AlwaysColor,
|
||||
NeverColor,
|
||||
}
|
||||
|
||||
impl ColorConfig {
|
||||
fn to_libtest(self) -> test::ColorConfig {
|
||||
match self {
|
||||
Self::AutoColor => test::ColorConfig::AutoColor,
|
||||
Self::AlwaysColor => test::ColorConfig::AlwaysColor,
|
||||
Self::NeverColor => test::ColorConfig::NeverColor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format of the test results output.
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub enum OutputFormat {
|
||||
/// Verbose output
|
||||
Pretty,
|
||||
/// Quiet output
|
||||
#[default]
|
||||
Terse,
|
||||
/// JSON output
|
||||
Json,
|
||||
}
|
||||
|
||||
impl OutputFormat {
|
||||
fn to_libtest(self) -> test::OutputFormat {
|
||||
match self {
|
||||
Self::Pretty => test::OutputFormat::Pretty,
|
||||
Self::Terse => test::OutputFormat::Terse,
|
||||
Self::Json => test::OutputFormat::Json,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether test is expected to panic or not.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum ShouldPanic {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl ShouldPanic {
|
||||
fn to_libtest(self) -> test::ShouldPanic {
|
||||
match self {
|
||||
Self::No => test::ShouldPanic::No,
|
||||
Self::Yes => test::ShouldPanic::Yes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_opts(config: &Config) -> test::TestOpts {
|
||||
test::TestOpts {
|
||||
exclude_should_panic: false,
|
||||
filters: config.filters.clone(),
|
||||
filter_exact: config.filter_exact,
|
||||
run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
|
||||
format: config.format.to_libtest(),
|
||||
logfile: config.logfile.clone(),
|
||||
run_tests: true,
|
||||
bench_benchmarks: true,
|
||||
nocapture: config.nocapture,
|
||||
color: config.color.to_libtest(),
|
||||
shuffle: false,
|
||||
shuffle_seed: None,
|
||||
test_threads: None,
|
||||
skip: config.skip.clone(),
|
||||
list: false,
|
||||
options: test::Options::new(),
|
||||
time_options: None,
|
||||
force_run_in_process: false,
|
||||
fail_fast: config.fail_fast,
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ use tracing::*;
|
||||
|
||||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::header::needs::CachedNeedsConditions;
|
||||
use crate::util::static_regex;
|
||||
@ -1355,15 +1356,15 @@ where
|
||||
Some((min, max))
|
||||
}
|
||||
|
||||
pub fn make_test_description<R: Read>(
|
||||
pub(crate) fn make_test_description<R: Read>(
|
||||
config: &Config,
|
||||
cache: &HeadersCache,
|
||||
name: test::TestName,
|
||||
name: String,
|
||||
path: &Path,
|
||||
src: R,
|
||||
test_revision: Option<&str>,
|
||||
poisoned: &mut bool,
|
||||
) -> test::TestDesc {
|
||||
) -> CollectedTestDesc {
|
||||
let mut ignore = false;
|
||||
let mut ignore_message = None;
|
||||
let mut should_fail = false;
|
||||
@ -1387,10 +1388,7 @@ pub fn make_test_description<R: Read>(
|
||||
match $e {
|
||||
IgnoreDecision::Ignore { reason } => {
|
||||
ignore = true;
|
||||
// The ignore reason must be a &'static str, so we have to leak memory to
|
||||
// create it. This is fine, as the header is parsed only at the start of
|
||||
// compiletest so it won't grow indefinitely.
|
||||
ignore_message = Some(&*Box::leak(Box::<str>::from(reason)));
|
||||
ignore_message = Some(reason.into());
|
||||
}
|
||||
IgnoreDecision::Error { message } => {
|
||||
eprintln!("error: {}:{line_number}: {message}", path.display());
|
||||
@ -1431,25 +1429,12 @@ pub fn make_test_description<R: Read>(
|
||||
// since we run the pretty printer across all tests by default.
|
||||
// If desired, we could add a `should-fail-pretty` annotation.
|
||||
let should_panic = match config.mode {
|
||||
crate::common::Pretty => test::ShouldPanic::No,
|
||||
_ if should_fail => test::ShouldPanic::Yes,
|
||||
_ => test::ShouldPanic::No,
|
||||
crate::common::Pretty => ShouldPanic::No,
|
||||
_ if should_fail => ShouldPanic::Yes,
|
||||
_ => ShouldPanic::No,
|
||||
};
|
||||
|
||||
test::TestDesc {
|
||||
name,
|
||||
ignore,
|
||||
ignore_message,
|
||||
source_file: "",
|
||||
start_line: 0,
|
||||
start_col: 0,
|
||||
end_line: 0,
|
||||
end_col: 0,
|
||||
should_panic,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
test_type: test::TestType::Unknown,
|
||||
}
|
||||
CollectedTestDesc { name, ignore, ignore_message, should_panic }
|
||||
}
|
||||
|
||||
fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
|
||||
|
@ -8,14 +8,15 @@ use super::{
|
||||
parse_normalize_rule,
|
||||
};
|
||||
use crate::common::{Config, Debugger, Mode};
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
|
||||
fn make_test_description<R: Read>(
|
||||
config: &Config,
|
||||
name: test::TestName,
|
||||
name: String,
|
||||
path: &Path,
|
||||
src: R,
|
||||
revision: Option<&str>,
|
||||
) -> test::TestDesc {
|
||||
) -> CollectedTestDesc {
|
||||
let cache = HeadersCache::load(config);
|
||||
let mut poisoned = false;
|
||||
let test = crate::header::make_test_description(
|
||||
@ -233,7 +234,7 @@ fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
|
||||
}
|
||||
|
||||
fn check_ignore(config: &Config, contents: &str) -> bool {
|
||||
let tn = test::DynTestName(String::new());
|
||||
let tn = String::new();
|
||||
let p = Path::new("a.rs");
|
||||
let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None);
|
||||
d.ignore
|
||||
@ -242,13 +243,13 @@ fn check_ignore(config: &Config, contents: &str) -> bool {
|
||||
#[test]
|
||||
fn should_fail() {
|
||||
let config: Config = cfg().build();
|
||||
let tn = test::DynTestName(String::new());
|
||||
let tn = String::new();
|
||||
let p = Path::new("a.rs");
|
||||
|
||||
let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None);
|
||||
assert_eq!(d.should_panic, test::ShouldPanic::No);
|
||||
assert_eq!(d.should_panic, ShouldPanic::No);
|
||||
let d = make_test_description(&config, tn, p, std::io::Cursor::new("//@ should-fail"), None);
|
||||
assert_eq!(d.should_panic, test::ShouldPanic::Yes);
|
||||
assert_eq!(d.should_panic, ShouldPanic::Yes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -12,6 +12,7 @@ pub mod common;
|
||||
pub mod compute_diff;
|
||||
mod debuggers;
|
||||
pub mod errors;
|
||||
mod executor;
|
||||
pub mod header;
|
||||
mod json;
|
||||
mod raise_fd_limit;
|
||||
@ -32,7 +33,6 @@ use std::{env, fs, vec};
|
||||
|
||||
use build_helper::git::{get_git_modified_files, get_git_untracked_files};
|
||||
use getopts::Options;
|
||||
use test::ColorConfig;
|
||||
use tracing::*;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
@ -41,6 +41,7 @@ use crate::common::{
|
||||
CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
|
||||
output_base_dir, output_relative_path,
|
||||
};
|
||||
use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
|
||||
use crate::header::HeadersCache;
|
||||
use crate::util::logv;
|
||||
|
||||
@ -50,6 +51,12 @@ use crate::util::logv;
|
||||
/// some code here that inspects environment variables or even runs executables
|
||||
/// (e.g. when discovering debugger versions).
|
||||
pub fn parse_config(args: Vec<String>) -> Config {
|
||||
if env::var("RUST_TEST_NOCAPTURE").is_ok() {
|
||||
eprintln!(
|
||||
"WARNING: RUST_TEST_NOCAPTURE is not supported. Use the `--no-capture` flag instead."
|
||||
);
|
||||
}
|
||||
|
||||
let mut opts = Options::new();
|
||||
opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH")
|
||||
.reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
|
||||
@ -128,6 +135,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||
"bless",
|
||||
"overwrite stderr/stdout files instead of complaining about a mismatch",
|
||||
)
|
||||
.optflag("", "fail-fast", "stop as soon as possible after any test fails")
|
||||
.optflag("", "quiet", "print one character per test instead of one line")
|
||||
.optopt("", "color", "coloring: auto, always, never", "WHEN")
|
||||
.optflag("", "json", "emit json output instead of plaintext output")
|
||||
@ -319,6 +327,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||
|
||||
Config {
|
||||
bless: matches.opt_present("bless"),
|
||||
fail_fast: matches.opt_present("fail-fast")
|
||||
|| env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
|
||||
|
||||
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
|
||||
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
|
||||
rustc_path: opt_path(matches, "rustc-path"),
|
||||
@ -392,9 +403,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||
verbose: matches.opt_present("verbose"),
|
||||
format: match (matches.opt_present("quiet"), matches.opt_present("json")) {
|
||||
(true, true) => panic!("--quiet and --json are incompatible"),
|
||||
(true, false) => test::OutputFormat::Terse,
|
||||
(false, true) => test::OutputFormat::Json,
|
||||
(false, false) => test::OutputFormat::Pretty,
|
||||
(true, false) => OutputFormat::Terse,
|
||||
(false, true) => OutputFormat::Json,
|
||||
(false, false) => OutputFormat::Pretty,
|
||||
},
|
||||
only_modified: matches.opt_present("only-modified"),
|
||||
color,
|
||||
@ -525,8 +536,6 @@ pub fn run_tests(config: Arc<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
|
||||
@ -553,12 +562,12 @@ pub fn run_tests(config: Arc<Config>) {
|
||||
tests.extend(collect_and_make_tests(c));
|
||||
}
|
||||
|
||||
tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
|
||||
tests.sort_by(|a, b| Ord::cmp(&a.desc.name, &b.desc.name));
|
||||
|
||||
// Delegate to libtest to filter and run the big list of structures created
|
||||
// during test discovery. When libtest decides to run a test, it will invoke
|
||||
// the corresponding closure created by `make_test_closure`.
|
||||
let res = test::run_tests_console(&opts, tests);
|
||||
// during test discovery. When libtest decides to run a test, it will
|
||||
// return control to compiletest by invoking a closure.
|
||||
let res = crate::executor::execute_tests(&config, tests);
|
||||
|
||||
// Check the outcome reported by libtest.
|
||||
match res {
|
||||
@ -602,37 +611,6 @@ pub fn run_tests(config: Arc<Config>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||
if env::var("RUST_TEST_NOCAPTURE").is_ok() {
|
||||
eprintln!(
|
||||
"WARNING: RUST_TEST_NOCAPTURE is no longer used. \
|
||||
Use the `--nocapture` flag instead."
|
||||
);
|
||||
}
|
||||
|
||||
test::TestOpts {
|
||||
exclude_should_panic: false,
|
||||
filters: config.filters.clone(),
|
||||
filter_exact: config.filter_exact,
|
||||
run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
|
||||
format: config.format,
|
||||
logfile: config.logfile.clone(),
|
||||
run_tests: true,
|
||||
bench_benchmarks: true,
|
||||
nocapture: config.nocapture,
|
||||
color: config.color,
|
||||
shuffle: false,
|
||||
shuffle_seed: None,
|
||||
test_threads: None,
|
||||
skip: config.skip.clone(),
|
||||
list: false,
|
||||
options: test::Options::new(),
|
||||
time_options: None,
|
||||
force_run_in_process: false,
|
||||
fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read-only context data used during test collection.
|
||||
struct TestCollectorCx {
|
||||
config: Arc<Config>,
|
||||
@ -643,17 +621,17 @@ struct TestCollectorCx {
|
||||
|
||||
/// Mutable state used during test collection.
|
||||
struct TestCollector {
|
||||
tests: Vec<test::TestDescAndFn>,
|
||||
tests: Vec<CollectedTest>,
|
||||
found_path_stems: HashSet<PathBuf>,
|
||||
poisoned: bool,
|
||||
}
|
||||
|
||||
/// Creates libtest structures for every test/revision in the test suite directory.
|
||||
/// Creates test structures for every test/revision in the test suite directory.
|
||||
///
|
||||
/// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
|
||||
/// regardless of whether any filters/tests were specified on the command-line,
|
||||
/// because filtering is handled later by libtest.
|
||||
pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
|
||||
pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest> {
|
||||
debug!("making tests from {}", config.src_test_suite_root.display());
|
||||
let common_inputs_stamp = common_inputs_stamp(&config);
|
||||
let modified_tests =
|
||||
@ -882,7 +860,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
|
||||
};
|
||||
|
||||
// For each revision (or the sole dummy revision), create and append a
|
||||
// `test::TestDescAndFn` that can be handed over to libtest.
|
||||
// `CollectedTest` that can be handed over to the test executor.
|
||||
collector.tests.extend(revisions.into_iter().map(|revision| {
|
||||
// Create a test name and description to hand over to libtest.
|
||||
let src_file = fs::File::open(&test_path).expect("open test file to parse ignores");
|
||||
@ -905,13 +883,14 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
|
||||
if !cx.config.force_rerun && is_up_to_date(cx, testpaths, &early_props, revision) {
|
||||
desc.ignore = true;
|
||||
// Keep this in sync with the "up-to-date" message detected by bootstrap.
|
||||
desc.ignore_message = Some("up-to-date");
|
||||
desc.ignore_message = Some("up-to-date".into());
|
||||
}
|
||||
|
||||
// Create the callback that will run this test/revision when libtest calls it.
|
||||
let testfn = make_test_closure(Arc::clone(&cx.config), testpaths, revision);
|
||||
let config = Arc::clone(&cx.config);
|
||||
let testpaths = testpaths.clone();
|
||||
let revision = revision.map(str::to_owned);
|
||||
|
||||
test::TestDescAndFn { desc, testfn }
|
||||
CollectedTest { desc, config, testpaths, revision }
|
||||
}));
|
||||
}
|
||||
|
||||
@ -1043,11 +1022,7 @@ impl Stamp {
|
||||
}
|
||||
|
||||
/// Creates a name for this test/revision that can be handed over to libtest.
|
||||
fn make_test_name(
|
||||
config: &Config,
|
||||
testpaths: &TestPaths,
|
||||
revision: Option<&str>,
|
||||
) -> test::TestName {
|
||||
fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> String {
|
||||
// Print the name of the file, relative to the sources root.
|
||||
let path = testpaths.file.strip_prefix(&config.src_root).unwrap();
|
||||
let debugger = match config.debugger {
|
||||
@ -1059,32 +1034,14 @@ fn make_test_name(
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
test::DynTestName(format!(
|
||||
format!(
|
||||
"[{}{}{}] {}{}",
|
||||
config.mode,
|
||||
debugger,
|
||||
mode_suffix,
|
||||
path.display(),
|
||||
revision.map_or("".to_string(), |rev| format!("#{}", rev))
|
||||
))
|
||||
}
|
||||
|
||||
/// Creates a callback for this test/revision that libtest will call when it
|
||||
/// decides to actually run the underlying test.
|
||||
fn make_test_closure(
|
||||
config: Arc<Config>,
|
||||
testpaths: &TestPaths,
|
||||
revision: Option<&str>,
|
||||
) -> test::TestFn {
|
||||
let testpaths = testpaths.clone();
|
||||
let revision = revision.map(str::to_owned);
|
||||
|
||||
// This callback is the link between compiletest's test discovery code,
|
||||
// and the parts of compiletest that know how to run an individual test.
|
||||
test::DynTestFn(Box::new(move || {
|
||||
runtest::run(config, &testpaths, revision.as_deref());
|
||||
Ok(())
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks that test discovery didn't find any tests whose name stem is a prefix
|
||||
|
@ -17,6 +17,7 @@ pub mod assertion_helpers;
|
||||
pub mod diff;
|
||||
pub mod env;
|
||||
pub mod external_deps;
|
||||
pub mod linker;
|
||||
pub mod path_helpers;
|
||||
pub mod run;
|
||||
pub mod scoped_run;
|
||||
|
36
src/tools/run-make-support/src/linker.rs
Normal file
36
src/tools/run-make-support/src/linker.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{Rustc, is_msvc};
|
||||
|
||||
/// Asserts that `rustc` uses LLD for linking when executed.
|
||||
pub fn assert_rustc_uses_lld(rustc: &mut Rustc) {
|
||||
let stderr = get_stderr_with_linker_messages(rustc);
|
||||
assert!(
|
||||
has_lld_version_in_logs(&stderr),
|
||||
"LLD version should be present in rustc stderr:\n{stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Asserts that `rustc` doesn't use LLD for linking when executed.
|
||||
pub fn assert_rustc_doesnt_use_lld(rustc: &mut Rustc) {
|
||||
let stderr = get_stderr_with_linker_messages(rustc);
|
||||
assert!(
|
||||
!has_lld_version_in_logs(&stderr),
|
||||
"LLD version should NOT be present in rustc stderr:\n{stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
fn get_stderr_with_linker_messages(rustc: &mut Rustc) -> String {
|
||||
// lld-link is used if msvc, otherwise a gnu-compatible lld is used.
|
||||
let linker_version_flag = if is_msvc() { "--version" } else { "-Wl,-v" };
|
||||
|
||||
let output = rustc.arg("-Wlinker-messages").link_arg(linker_version_flag).run();
|
||||
output.stderr_utf8()
|
||||
}
|
||||
|
||||
fn has_lld_version_in_logs(stderr: &str) -> bool {
|
||||
// Strip the `-Wlinker-messages` wrappers prefixing the linker output.
|
||||
let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, "");
|
||||
let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
|
||||
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
|
||||
}
|
@ -4,24 +4,11 @@
|
||||
//@ ignore-nightly
|
||||
//@ only-x86_64-unknown-linux-gnu
|
||||
|
||||
use std::process::Output;
|
||||
|
||||
use run_make_support::regex::Regex;
|
||||
use run_make_support::linker::assert_rustc_doesnt_use_lld;
|
||||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
// A regular compilation should not use rust-lld by default. We'll check that by asking the
|
||||
// linker to display its version number with a link-arg.
|
||||
let output = rustc().arg("-Wlinker-messages").link_arg("-Wl,-v").input("main.rs").run();
|
||||
assert!(
|
||||
!find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should not be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
);
|
||||
}
|
||||
|
||||
fn find_lld_version_in_logs(stderr: String) -> bool {
|
||||
let lld_version_re =
|
||||
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
|
||||
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
|
||||
assert_rustc_doesnt_use_lld(rustc().input("main.rs"));
|
||||
}
|
||||
|
@ -6,35 +6,14 @@
|
||||
//@ ignore-stable
|
||||
//@ only-x86_64-unknown-linux-gnu
|
||||
|
||||
use run_make_support::regex::Regex;
|
||||
use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
|
||||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
// A regular compilation should use rust-lld by default. We'll check that by asking the linker
|
||||
// to display its version number with a link-arg.
|
||||
let output = rustc().arg("-Wlinker-messages").link_arg("-Wl,-v").input("main.rs").run();
|
||||
assert!(
|
||||
find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
);
|
||||
assert_rustc_uses_lld(rustc().input("main.rs"));
|
||||
|
||||
// But it can still be disabled by turning the linker feature off.
|
||||
let output = rustc()
|
||||
.arg("-Wlinker-messages")
|
||||
.link_arg("-Wl,-v")
|
||||
.arg("-Zlinker-features=-lld")
|
||||
.input("main.rs")
|
||||
.run();
|
||||
assert!(
|
||||
!find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should not be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
);
|
||||
}
|
||||
|
||||
fn find_lld_version_in_logs(stderr: String) -> bool {
|
||||
let lld_version_re =
|
||||
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
|
||||
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
|
||||
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));
|
||||
}
|
||||
|
@ -8,43 +8,22 @@
|
||||
//@ needs-rust-lld
|
||||
//@ only-x86_64-unknown-linux-gnu
|
||||
|
||||
use run_make_support::regex::Regex;
|
||||
use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
|
||||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
// Compile to a custom target spec with rust-lld enabled by default. We'll check that by asking
|
||||
// the linker to display its version number with a link-arg.
|
||||
let output = rustc()
|
||||
.crate_type("cdylib")
|
||||
.arg("-Wlinker-messages")
|
||||
.target("custom-target.json")
|
||||
.link_arg("-Wl,-v")
|
||||
.input("lib.rs")
|
||||
.run();
|
||||
assert!(
|
||||
find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
assert_rustc_uses_lld(
|
||||
rustc().crate_type("cdylib").target("custom-target.json").input("lib.rs"),
|
||||
);
|
||||
|
||||
// But it can also be disabled via linker features.
|
||||
let output = rustc()
|
||||
.crate_type("cdylib")
|
||||
.arg("-Wlinker-messages")
|
||||
.target("custom-target.json")
|
||||
.arg("-Zlinker-features=-lld")
|
||||
.link_arg("-Wl,-v")
|
||||
.input("lib.rs")
|
||||
.run();
|
||||
assert!(
|
||||
!find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should not be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
assert_rustc_doesnt_use_lld(
|
||||
rustc()
|
||||
.crate_type("cdylib")
|
||||
.target("custom-target.json")
|
||||
.arg("-Zlinker-features=-lld")
|
||||
.input("lib.rs"),
|
||||
);
|
||||
}
|
||||
|
||||
fn find_lld_version_in_logs(stderr: String) -> bool {
|
||||
let lld_version_re =
|
||||
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
|
||||
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
|
||||
}
|
||||
|
@ -4,64 +4,32 @@
|
||||
//@ needs-rust-lld
|
||||
//@ ignore-s390x lld does not yet support s390x as target
|
||||
|
||||
use run_make_support::regex::Regex;
|
||||
use run_make_support::{is_msvc, rustc};
|
||||
use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
|
||||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
// lld-link is used if msvc, otherwise a gnu-compatible lld is used.
|
||||
let linker_version_flag = if is_msvc() { "--version" } else { "-Wl,-v" };
|
||||
|
||||
// Opt-in to lld and the self-contained linker, to link with rust-lld. We'll check that by
|
||||
// asking the linker to display its version number with a link-arg.
|
||||
let output = rustc()
|
||||
.arg("-Zlinker-features=+lld")
|
||||
.arg("-Clink-self-contained=+linker")
|
||||
.arg("-Zunstable-options")
|
||||
.arg("-Wlinker-messages")
|
||||
.link_arg(linker_version_flag)
|
||||
.input("main.rs")
|
||||
.run();
|
||||
assert!(
|
||||
find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
assert_rustc_uses_lld(
|
||||
rustc()
|
||||
.arg("-Zlinker-features=+lld")
|
||||
.arg("-Clink-self-contained=+linker")
|
||||
.arg("-Zunstable-options")
|
||||
.input("main.rs"),
|
||||
);
|
||||
|
||||
// It should not be used when we explicitly opt-out of lld.
|
||||
let output = rustc()
|
||||
.link_arg(linker_version_flag)
|
||||
.arg("-Zlinker-features=-lld")
|
||||
.arg("-Wlinker-messages")
|
||||
.input("main.rs")
|
||||
.run();
|
||||
assert!(
|
||||
!find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should not be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
);
|
||||
// It should not be used when we explicitly opt out of lld.
|
||||
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));
|
||||
|
||||
// While we're here, also check that the last linker feature flag "wins" when passed multiple
|
||||
// times to rustc.
|
||||
let output = rustc()
|
||||
.link_arg(linker_version_flag)
|
||||
.arg("-Clink-self-contained=+linker")
|
||||
.arg("-Zunstable-options")
|
||||
.arg("-Zlinker-features=-lld")
|
||||
.arg("-Zlinker-features=+lld")
|
||||
.arg("-Zlinker-features=-lld,+lld")
|
||||
.arg("-Wlinker-messages")
|
||||
.input("main.rs")
|
||||
.run();
|
||||
assert!(
|
||||
find_lld_version_in_logs(output.stderr_utf8()),
|
||||
"the LLD version string should be present in the output logs:\n{}",
|
||||
output.stderr_utf8()
|
||||
assert_rustc_uses_lld(
|
||||
rustc()
|
||||
.arg("-Clink-self-contained=+linker")
|
||||
.arg("-Zunstable-options")
|
||||
.arg("-Zlinker-features=-lld")
|
||||
.arg("-Zlinker-features=+lld")
|
||||
.arg("-Zlinker-features=-lld,+lld")
|
||||
.input("main.rs"),
|
||||
);
|
||||
}
|
||||
|
||||
fn find_lld_version_in_logs(stderr: String) -> bool {
|
||||
// Strip the `-Wlinker-messages` wrappers prefixing the linker output.
|
||||
let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, "");
|
||||
let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
|
||||
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
// compile-flags: -Znext-solver
|
||||
|
||||
// Test for a weird diagnostics corner case. In the error reporting code, when reporting
|
||||
// fulfillment errors for goals A and B, we try to see if elaborating A will result in
|
||||
// another goal that can equate with B. That would signal that B is "implied by" A,
|
||||
// allowing us to skip reporting it, which is beneficial for cutting down on the number
|
||||
// of diagnostics we report. In the new trait solver especially, but even in the old trait
|
||||
// solver through things like defining opaque type usages, this `can_equate` call was not
|
||||
// properly taking the param-env of the goals, resulting in nested obligations that had
|
||||
// empty param-envs. If one of these nested obligations was a `ConstParamHasTy` goal, then
|
||||
// we would ICE, since those goals are particularly strict about the param-env they're
|
||||
// evaluated in.
|
||||
|
||||
// This is morally a fix for <https://github.com/rust-lang/rust/issues/139314>, but that
|
||||
// repro uses details about how defining usages in the `check_opaque_well_formed` code
|
||||
// can spring out of type equality, and will likely stop failing soon coincidentally once
|
||||
// we start using `PostBorrowck` mode in that check.
|
||||
|
||||
trait Foo: Baz<()> {}
|
||||
trait Baz<T> {}
|
||||
|
||||
trait IdentityWithConstArgGoal<const N: usize> {
|
||||
type Assoc;
|
||||
}
|
||||
impl<T, const N: usize> IdentityWithConstArgGoal<N> for T {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
fn unsatisfied<T, const N: usize>()
|
||||
where
|
||||
T: Foo,
|
||||
T: Baz<<T as IdentityWithConstArgGoal<N>>::Assoc>,
|
||||
{
|
||||
}
|
||||
|
||||
fn test<const N: usize>() {
|
||||
unsatisfied::<(), N>();
|
||||
//~^ ERROR the trait bound `(): Foo` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,23 @@
|
||||
error[E0277]: the trait bound `(): Foo` is not satisfied
|
||||
--> $DIR/const-param-has-ty-goal-in-error-implies.rs:37:19
|
||||
|
|
||||
LL | unsatisfied::<(), N>();
|
||||
| ^^ the trait `Foo` is not implemented for `()`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/const-param-has-ty-goal-in-error-implies.rs:19:1
|
||||
|
|
||||
LL | trait Foo: Baz<()> {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `unsatisfied`
|
||||
--> $DIR/const-param-has-ty-goal-in-error-implies.rs:31:8
|
||||
|
|
||||
LL | fn unsatisfied<T, const N: usize>()
|
||||
| ----------- required by a bound in this function
|
||||
LL | where
|
||||
LL | T: Foo,
|
||||
| ^^^ required by this bound in `unsatisfied`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
10
tests/ui/drop/nonsense-drop-impl-issue-139278.rs
Normal file
10
tests/ui/drop/nonsense-drop-impl-issue-139278.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ check-fail
|
||||
struct Foo;
|
||||
|
||||
impl Drop for Foo { //~ ERROR: not all trait items implemented
|
||||
const SPLOK: u32 = 0; //~ ERROR: not a member of trait
|
||||
}
|
||||
|
||||
const X: Foo = Foo;
|
||||
|
||||
fn main() {}
|
18
tests/ui/drop/nonsense-drop-impl-issue-139278.stderr
Normal file
18
tests/ui/drop/nonsense-drop-impl-issue-139278.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0438]: const `SPLOK` is not a member of trait `Drop`
|
||||
--> $DIR/nonsense-drop-impl-issue-139278.rs:5:5
|
||||
|
|
||||
LL | const SPLOK: u32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ not a member of trait `Drop`
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `drop`
|
||||
--> $DIR/nonsense-drop-impl-issue-139278.rs:4:1
|
||||
|
|
||||
LL | impl Drop for Foo {
|
||||
| ^^^^^^^^^^^^^^^^^ missing `drop` in implementation
|
||||
|
|
||||
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0046, E0438.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
Loading…
Reference in New Issue
Block a user