Auto merge of #132756 - workingjubilee:rollup-bed2akn, r=workingjubilee

Rollup of 10 pull requests

Successful merges:

 - #130586 (Set "symbol name" in raw-dylib import libraries to the decorated name)
 - #131913 (Add `{ignore,needs}-{rustc,std}-debug-assertions` directive support)
 - #132095 (Fix #131977 parens mangled in shared mut static lint suggestion)
 - #132131 ([StableMIR] API to retrieve definitions from crates)
 - #132639 (core: move intrinsics.rs into intrinsics folder)
 - #132696 (Compile `test_num_f128` conditionally on `reliable_f128_math` config)
 - #132737 (bootstrap: Print better message if lock pid isn't available)
 - #132739 (Fix `librustdoc/scrape_examples.rs` formatting)
 - #132740 (Update test for LLVM 20's new vector splat syntax)
 - #132741 (Update mips64 data layout to match LLVM 20 change)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-11-08 03:32:51 +00:00
commit 78bb5ee79e
54 changed files with 569 additions and 141 deletions

View File

@ -2,6 +2,7 @@
use rustc_codegen_ssa::back::archive::{ use rustc_codegen_ssa::back::archive::{
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
ImportLibraryItem,
}; };
use rustc_session::Session; use rustc_session::Session;
@ -16,7 +17,7 @@ fn create_dll_import_lib(
&self, &self,
_sess: &Session, _sess: &Session,
_lib_name: &str, _lib_name: &str,
_import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, _items: Vec<ImportLibraryItem>,
_output_path: &Path, _output_path: &Path,
) { ) {
unimplemented!("creating dll imports is not yet supported"); unimplemented!("creating dll imports is not yet supported");

View File

@ -44,6 +44,22 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
let llfn = if tcx.sess.target.arch == "x86" let llfn = if tcx.sess.target.arch == "x86"
&& let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym) && let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
{ {
// When calling functions in generated import libraries, MSVC needs
// the fully decorated name (as would have been in the declaring
// object file), but MinGW wants the name as exported (as would be
// in the def file) which may be missing decorations.
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&tcx.sess.target);
let llfn = cx.declare_fn(
&common::i686_decorated_name(
dllimport,
mingw_gnu_toolchain,
true,
!mingw_gnu_toolchain,
),
fn_abi,
Some(instance),
);
// Fix for https://github.com/rust-lang/rust/issues/104453 // Fix for https://github.com/rust-lang/rust/issues/104453
// On x86 Windows, LLVM uses 'L' as the prefix for any private // On x86 Windows, LLVM uses 'L' as the prefix for any private
// global symbols, so when we create an undecorated function symbol // global symbols, so when we create an undecorated function symbol
@ -55,15 +71,6 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the // LLVM will prefix the name with `__imp_`. Ideally, we'd like the
// existing logic below to set the Storage Class, but it has an // existing logic below to set the Storage Class, but it has an
// exemption for MinGW for backwards compatibility. // exemption for MinGW for backwards compatibility.
let llfn = cx.declare_fn(
&common::i686_decorated_name(
dllimport,
common::is_mingw_gnu_toolchain(&tcx.sess.target),
true,
),
fn_abi,
Some(instance),
);
unsafe { unsafe {
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
} }

View File

@ -194,16 +194,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
unsafe { llvm::LLVMSetInitializer(g2, g1) }; unsafe { llvm::LLVMSetInitializer(g2, g1) };
g2 g2
} else if cx.tcx.sess.target.arch == "x86" } else if cx.tcx.sess.target.arch == "x86"
&& common::is_mingw_gnu_toolchain(&cx.tcx.sess.target)
&& let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
{ {
cx.declare_global( cx.declare_global(&common::i686_decorated_name(dllimport, true, true, false), llty)
&common::i686_decorated_name(
dllimport,
common::is_mingw_gnu_toolchain(&cx.tcx.sess.target),
true,
),
llty,
)
} else { } else {
// Generate an external declaration. // Generate an external declaration.
// FIXME(nagisa): investigate whether it can be changed into define_global // FIXME(nagisa): investigate whether it can be changed into define_global

View File

@ -154,6 +154,11 @@ pub(crate) unsafe fn create_module<'ll>(
// See https://github.com/llvm/llvm-project/pull/106951 // See https://github.com/llvm/llvm-project/pull/106951
target_data_layout = target_data_layout.replace("-i128:128", ""); target_data_layout = target_data_layout.replace("-i128:128", "");
} }
if sess.target.arch.starts_with("mips64") {
// LLVM 20 updates the mips64 layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/112084
target_data_layout = target_data_layout.replace("-i128:128", "");
}
} }
// Ensure the data-layout values hardcoded remain the defaults. // Ensure the data-layout values hardcoded remain the defaults.

View File

@ -26,6 +26,35 @@
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
}; };
/// An item to be included in an import library.
/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`.
pub struct ImportLibraryItem {
/// The name to be exported.
pub name: String,
/// The ordinal to be exported, if any.
pub ordinal: Option<u16>,
/// The original, decorated name if `name` is not decorated.
pub symbol_name: Option<String>,
/// True if this is a data export, false if it is a function export.
pub is_data: bool,
}
impl From<ImportLibraryItem> for COFFShortExport {
fn from(item: ImportLibraryItem) -> Self {
COFFShortExport {
name: item.name,
ext_name: None,
symbol_name: item.symbol_name,
alias_target: None,
ordinal: item.ordinal.unwrap_or(0),
noname: item.ordinal.is_some(),
data: item.is_data,
private: false,
constant: false,
}
}
}
pub trait ArchiveBuilderBuilder { pub trait ArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>; fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
@ -38,7 +67,7 @@ fn create_dll_import_lib(
&self, &self,
sess: &Session, sess: &Session,
lib_name: &str, lib_name: &str,
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, items: Vec<ImportLibraryItem>,
output_path: &Path, output_path: &Path,
) { ) {
if common::is_mingw_gnu_toolchain(&sess.target) { if common::is_mingw_gnu_toolchain(&sess.target) {
@ -47,21 +76,16 @@ fn create_dll_import_lib(
// that loaded but crashed with an AV upon calling one of the imported // that loaded but crashed with an AV upon calling one of the imported
// functions. Therefore, use binutils to create the import library instead, // functions. Therefore, use binutils to create the import library instead,
// by writing a .DEF file to the temp dir and calling binutils's dlltool. // by writing a .DEF file to the temp dir and calling binutils's dlltool.
create_mingw_dll_import_lib( create_mingw_dll_import_lib(sess, lib_name, items, output_path);
sess,
lib_name,
import_name_and_ordinal_vector,
output_path,
);
} else { } else {
trace!("creating import library"); trace!("creating import library");
trace!(" dll_name {:#?}", lib_name); trace!(" dll_name {:#?}", lib_name);
trace!(" output_path {}", output_path.display()); trace!(" output_path {}", output_path.display());
trace!( trace!(
" import names: {}", " import names: {}",
import_name_and_ordinal_vector items
.iter() .iter()
.map(|(name, _ordinal)| name.clone()) .map(|ImportLibraryItem { name, .. }| name.clone())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "), .join(", "),
); );
@ -79,20 +103,7 @@ fn create_dll_import_lib(
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }), .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
}; };
let exports = import_name_and_ordinal_vector let exports = items.into_iter().map(Into::into).collect::<Vec<_>>();
.iter()
.map(|(name, ordinal)| COFFShortExport {
name: name.to_string(),
ext_name: None,
symbol_name: None,
alias_target: None,
ordinal: ordinal.unwrap_or(0),
noname: ordinal.is_some(),
data: false,
private: false,
constant: false,
})
.collect::<Vec<_>>();
let machine = match &*sess.target.arch { let machine = match &*sess.target.arch {
"x86_64" => MachineTypes::AMD64, "x86_64" => MachineTypes::AMD64,
"x86" => MachineTypes::I386, "x86" => MachineTypes::I386,
@ -160,16 +171,16 @@ fn extract_bundled_libs<'a>(
fn create_mingw_dll_import_lib( fn create_mingw_dll_import_lib(
sess: &Session, sess: &Session,
lib_name: &str, lib_name: &str,
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, items: Vec<ImportLibraryItem>,
output_path: &Path, output_path: &Path,
) { ) {
let def_file_path = output_path.with_extension("def"); let def_file_path = output_path.with_extension("def");
let def_file_content = format!( let def_file_content = format!(
"EXPORTS\n{}", "EXPORTS\n{}",
import_name_and_ordinal_vector items
.into_iter() .into_iter()
.map(|(name, ordinal)| { .map(|ImportLibraryItem { name, ordinal, .. }| {
match ordinal { match ordinal {
Some(n) => format!("{name} @{n} NONAME"), Some(n) => format!("{name} @{n} NONAME"),
None => name, None => name,

View File

@ -45,7 +45,7 @@
use tempfile::Builder as TempFileBuilder; use tempfile::Builder as TempFileBuilder;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder, ImportLibraryItem};
use super::command::Command; use super::command::Command;
use super::linker::{self, Linker}; use super::linker::{self, Linker};
use super::metadata::{MetadataPosition, create_wrapper_file}; use super::metadata::{MetadataPosition, create_wrapper_file};
@ -495,16 +495,35 @@ fn create_dll_import_libs<'a>(
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target);
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports let items: Vec<ImportLibraryItem> = raw_dylib_imports
.iter() .iter()
.map(|import: &DllImport| { .map(|import: &DllImport| {
if sess.target.arch == "x86" { if sess.target.arch == "x86" {
( ImportLibraryItem {
common::i686_decorated_name(import, mingw_gnu_toolchain, false), name: common::i686_decorated_name(
import.ordinal(), import,
) mingw_gnu_toolchain,
false,
false,
),
ordinal: import.ordinal(),
symbol_name: import.is_missing_decorations().then(|| {
common::i686_decorated_name(
import,
mingw_gnu_toolchain,
false,
true,
)
}),
is_data: !import.is_fn,
}
} else { } else {
(import.name.to_string(), import.ordinal()) ImportLibraryItem {
name: import.name.to_string(),
ordinal: import.ordinal(),
symbol_name: None,
is_data: !import.is_fn,
}
} }
}) })
.collect(); .collect();
@ -512,7 +531,7 @@ fn create_dll_import_libs<'a>(
archive_builder_builder.create_dll_import_lib( archive_builder_builder.create_dll_import_lib(
sess, sess,
&raw_dylib_name, &raw_dylib_name,
import_name_and_ordinal_vector, items,
&output_path, &output_path,
); );

View File

@ -187,12 +187,15 @@ pub fn i686_decorated_name(
dll_import: &DllImport, dll_import: &DllImport,
mingw: bool, mingw: bool,
disable_name_mangling: bool, disable_name_mangling: bool,
force_fully_decorated: bool,
) -> String { ) -> String {
let name = dll_import.name.as_str(); let name = dll_import.name.as_str();
let (add_prefix, add_suffix) = match dll_import.import_name_type { let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) {
Some(PeImportNameType::NoPrefix) => (false, true), // No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will
Some(PeImportNameType::Undecorated) => (false, false), // ignore `force_fully_decorated` and always partially decorate it.
(_, Some(PeImportNameType::NoPrefix)) => (false, true),
(false, Some(PeImportNameType::Undecorated)) => (false, false),
_ => (true, true), _ => (true, true),
}; };

View File

@ -3,8 +3,8 @@
use rustc_middle::ty::{Mutability, TyKind}; use rustc_middle::ty::{Mutability, TyKind};
use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::{declare_lint, declare_lint_pass}; use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::Span;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::{BytePos, Span};
use crate::lints::{MutRefSugg, RefOfMutStatic}; use crate::lints::{MutRefSugg, RefOfMutStatic};
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
@ -71,13 +71,24 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if matches!(borrow_kind, hir::BorrowKind::Ref) if matches!(borrow_kind, hir::BorrowKind::Ref)
&& let Some(err_span) = path_is_static_mut(ex, err_span) => && let Some(err_span) = path_is_static_mut(ex, err_span) =>
{ {
emit_static_mut_refs( let source_map = cx.sess().source_map();
cx, let snippet = source_map.span_to_snippet(err_span);
err_span,
err_span.with_hi(ex.span.lo()), let sugg_span = if let Ok(snippet) = snippet {
m, // ( ( &IDENT ) )
!expr.span.from_expansion(), // ~~~~ exclude these from the suggestion span to avoid unmatching parens
); let exclude_n_bytes: u32 = snippet
.chars()
.take_while(|ch| ch.is_whitespace() || *ch == '(')
.map(|ch| ch.len_utf8() as u32)
.sum();
err_span.with_lo(err_span.lo() + BytePos(exclude_n_bytes)).with_hi(ex.span.lo())
} else {
err_span.with_hi(ex.span.lo())
};
emit_static_mut_refs(cx, err_span, sugg_span, m, !expr.span.from_expansion());
} }
hir::ExprKind::MethodCall(_, e, _, _) hir::ExprKind::MethodCall(_, e, _, _)
if let Some(err_span) = path_is_static_mut(e, expr.span) if let Some(err_span) = path_is_static_mut(e, expr.span)

View File

@ -384,6 +384,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
crate_hash => { cdata.root.header.hash } crate_hash => { cdata.root.header.hash }
crate_host_hash => { cdata.host_hash } crate_host_hash => { cdata.host_hash }
crate_name => { cdata.root.header.name } crate_name => { cdata.root.header.name }
num_extern_def_ids => { cdata.num_def_ids() }
extra_filename => { cdata.root.extra_filename.clone() } extra_filename => { cdata.root.extra_filename.clone() }

View File

@ -1844,6 +1844,16 @@
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) } desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) }
} }
/// Gets the number of definitions in a foreign crate.
///
/// This allows external tools to iterate over all definitions in a foreign crate.
///
/// This should never be used for the local crate, instead use `iter_local_def_id`.
query num_extern_def_ids(_: CrateNum) -> usize {
desc { "fetching the number of definitions in a crate" }
separate_provide_extern
}
query lib_features(_: CrateNum) -> &'tcx LibFeatures { query lib_features(_: CrateNum) -> &'tcx LibFeatures {
desc { "calculating the lib features defined in a crate" } desc { "calculating the lib features defined in a crate" }
separate_provide_extern separate_provide_extern

View File

@ -130,6 +130,11 @@ pub fn ordinal(&self) -> Option<u16> {
None None
} }
} }
pub fn is_missing_decorations(&self) -> bool {
self.import_name_type == Some(PeImportNameType::Undecorated)
|| self.import_name_type == Some(PeImportNameType::NoPrefix)
}
} }
/// Calling convention for a function defined in an external library. /// Calling convention for a function defined in an external library.

View File

@ -34,7 +34,7 @@
use crate::rustc_internal::RustcInternal; use crate::rustc_internal::RustcInternal;
use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::builder::BodyBuilder;
use crate::rustc_smir::{Stable, Tables, alloc, new_item_kind, smir_crate}; use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate};
impl<'tcx> Context for TablesWrapper<'tcx> { impl<'tcx> Context for TablesWrapper<'tcx> {
fn target_info(&self) -> MachineInfo { fn target_info(&self) -> MachineInfo {
@ -80,6 +80,20 @@ fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignMod
.collect() .collect()
} }
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let krate = crate_num.internal(&mut *tables, tcx);
filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id))
}
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let krate = crate_num.internal(&mut *tables, tcx);
filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id))
}
fn foreign_module( fn foreign_module(
&self, &self,
mod_def: stable_mir::ty::ForeignModuleDef, mod_def: stable_mir::ty::ForeignModuleDef,

View File

@ -15,8 +15,8 @@
use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
use stable_mir::abi::Layout; use stable_mir::abi::Layout;
use stable_mir::mir::mono::InstanceDef; use stable_mir::mir::mono::{InstanceDef, StaticDef};
use stable_mir::ty::{MirConstId, Span, TyConstId}; use stable_mir::ty::{FnDef, MirConstId, Span, TyConstId};
use stable_mir::{CtorKind, ItemKind}; use stable_mir::{CtorKind, ItemKind};
use tracing::debug; use tracing::debug;
@ -79,6 +79,36 @@ pub(crate) fn item_has_body(&self, def_id: DefId) -> bool {
}; };
!must_override && self.tcx.is_mir_available(def_id) !must_override && self.tcx.is_mir_available(def_id)
} }
fn to_fn_def(&mut self, def_id: DefId) -> Option<FnDef> {
if matches!(self.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
Some(self.fn_def(def_id))
} else {
None
}
}
fn to_static(&mut self, def_id: DefId) -> Option<StaticDef> {
matches!(self.tcx.def_kind(def_id), DefKind::Static { .. }).then(|| self.static_def(def_id))
}
}
/// Iterate over the definitions of the given crate.
pub(crate) fn filter_def_ids<F, T>(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec<T>
where
F: FnMut(DefId) -> Option<T>,
{
if krate == LOCAL_CRATE {
tcx.iter_local_def_id().filter_map(|did| func(did.to_def_id())).collect()
} else {
let num_definitions = tcx.num_extern_def_ids(krate);
(0..num_definitions)
.filter_map(move |i| {
let def_id = DefId { krate, index: rustc_span::def_id::DefIndex::from_usize(i) };
func(def_id)
})
.collect()
}
} }
/// Build a stable mir crate from a given crate number. /// Build a stable mir crate from a given crate number.

View File

@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
std: None, // ? std: None, // ?
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(), arch: "mips64".into(),
options: TargetOptions { options: TargetOptions {
abi: "abi64".into(), abi: "abi64".into(),

View File

@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
std: Some(true), std: Some(true),
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(), arch: "mips64".into(),
options: TargetOptions { options: TargetOptions {
abi: "abi64".into(), abi: "abi64".into(),

View File

@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
std: Some(true), std: Some(true),
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(), arch: "mips64".into(),
options: TargetOptions { options: TargetOptions {
abi: "abi64".into(), abi: "abi64".into(),

View File

@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
std: Some(true), std: Some(true),
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(), arch: "mips64".into(),
options: TargetOptions { options: TargetOptions {
abi: "abi64".into(), abi: "abi64".into(),

View File

@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
std: Some(true), std: Some(true),
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(), arch: "mips64".into(),
options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base }, options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base },
} }

View File

@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
std: None, // ? std: None, // ?
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64r6".into(), arch: "mips64r6".into(),
options: TargetOptions { options: TargetOptions {
abi: "abi64".into(), abi: "abi64".into(),

View File

@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
std: Some(true), std: Some(true),
}, },
pointer_width: 64, pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64r6".into(), arch: "mips64r6".into(),
options: TargetOptions { options: TargetOptions {
abi: "abi64".into(), abi: "abi64".into(),

View File

@ -34,6 +34,12 @@ pub trait Context {
/// Check whether the body of a function is available. /// Check whether the body of a function is available.
fn has_body(&self, item: DefId) -> bool; fn has_body(&self, item: DefId) -> bool;
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>; fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>;
/// Retrieve all functions defined in this crate.
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>;
/// Retrieve all static items defined in this crate.
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>;
fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule;
fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>; fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
fn all_trait_decls(&self) -> TraitDecls; fn all_trait_decls(&self) -> TraitDecls;

View File

@ -25,8 +25,9 @@
use crate::compiler_interface::with; use crate::compiler_interface::with;
pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; pub use crate::crate_def::{CrateDef, CrateDefType, DefId};
pub use crate::error::*; pub use crate::error::*;
use crate::mir::mono::StaticDef;
use crate::mir::{Body, Mutability}; use crate::mir::{Body, Mutability};
use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; use crate::ty::{FnDef, ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
pub mod abi; pub mod abi;
#[macro_use] #[macro_use]
@ -96,6 +97,16 @@ pub fn trait_decls(&self) -> TraitDecls {
pub fn trait_impls(&self) -> ImplTraitDecls { pub fn trait_impls(&self) -> ImplTraitDecls {
with(|cx| cx.trait_impls(self.id)) with(|cx| cx.trait_impls(self.id))
} }
/// Return a list of function definitions from this crate independent on their visibility.
pub fn fn_defs(&self) -> Vec<FnDef> {
with(|cx| cx.crate_functions(self.id))
}
/// Return a list of static items defined in this crate independent on their visibility.
pub fn statics(&self) -> Vec<StaticDef> {
with(|cx| cx.crate_statics(self.id))
}
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]

View File

@ -2,7 +2,10 @@
#![cfg(reliable_f128)] #![cfg(reliable_f128)]
use crate::f128::consts; use crate::f128::consts;
use crate::num::{FpCategory as Fp, *}; use crate::num::FpCategory as Fp;
#[cfg(reliable_f128_math)]
use crate::ops::Rem;
use crate::ops::{Add, Div, Mul, Sub};
// Note these tolerances make sense around zero, but not for more extreme exponents. // Note these tolerances make sense around zero, but not for more extreme exponents.
@ -53,7 +56,22 @@ macro_rules! assert_f128_biteq {
#[test] #[test]
fn test_num_f128() { fn test_num_f128() {
test_num(10f128, 2f128); // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128`
// function is available on all platforms.
let ten = 10f128;
let two = 2f128;
assert_eq!(ten.add(two), ten + two);
assert_eq!(ten.sub(two), ten - two);
assert_eq!(ten.mul(two), ten * two);
assert_eq!(ten.div(two), ten / two);
}
#[test]
#[cfg(reliable_f128_math)]
fn test_num_f128_rem() {
let ten = 10f128;
let two = 2f128;
assert_eq!(ten.rem(two), ten % two);
} }
#[test] #[test]

View File

@ -33,7 +33,7 @@ fn main() {
// Display PID of process holding the lock // Display PID of process holding the lock
// PID will be stored in a lock file // PID will be stored in a lock file
let lock_path = config.out.join("lock"); let lock_path = config.out.join("lock");
let pid = fs::read_to_string(&lock_path).unwrap_or_default(); let pid = fs::read_to_string(&lock_path);
build_lock = fd_lock::RwLock::new(t!(fs::OpenOptions::new() build_lock = fd_lock::RwLock::new(t!(fs::OpenOptions::new()
.write(true) .write(true)
@ -47,7 +47,11 @@ fn main() {
} }
err => { err => {
drop(err); drop(err);
println!("WARNING: build directory locked by process {pid}, waiting for lock"); if let Ok(pid) = pid {
println!("WARNING: build directory locked by process {pid}, waiting for lock");
} else {
println!("WARNING: build directory locked, waiting for lock");
}
let mut lock = t!(build_lock.write()); let mut lock = t!(build_lock.write());
t!(lock.write(process::id().to_string().as_ref())); t!(lock.write(process::id().to_string().as_ref()));
lock lock

View File

@ -1938,9 +1938,13 @@ fn run(self, builder: &Builder<'_>) {
cmd.arg("--json"); cmd.arg("--json");
if builder.config.rust_debug_assertions_std { if builder.config.rustc_debug_assertions {
cmd.arg("--with-debug-assertions"); cmd.arg("--with-rustc-debug-assertions");
}; }
if builder.config.std_debug_assertions {
cmd.arg("--with-std-debug-assertions");
}
let mut llvm_components_passed = false; let mut llvm_components_passed = false;
let mut copts_passed = false; let mut copts_passed = false;

View File

@ -833,9 +833,9 @@ fn cargo(
cargo.env( cargo.env(
profile_var("DEBUG_ASSERTIONS"), profile_var("DEBUG_ASSERTIONS"),
if mode == Mode::Std { if mode == Mode::Std {
self.config.rust_debug_assertions_std.to_string() self.config.std_debug_assertions.to_string()
} else { } else {
self.config.rust_debug_assertions.to_string() self.config.rustc_debug_assertions.to_string()
}, },
); );
cargo.env( cargo.env(

View File

@ -263,8 +263,10 @@ pub struct Config {
pub rust_optimize: RustOptimize, pub rust_optimize: RustOptimize,
pub rust_codegen_units: Option<u32>, pub rust_codegen_units: Option<u32>,
pub rust_codegen_units_std: Option<u32>, pub rust_codegen_units_std: Option<u32>,
pub rust_debug_assertions: bool,
pub rust_debug_assertions_std: bool, pub rustc_debug_assertions: bool,
pub std_debug_assertions: bool,
pub rust_overflow_checks: bool, pub rust_overflow_checks: bool,
pub rust_overflow_checks_std: bool, pub rust_overflow_checks_std: bool,
pub rust_debug_logging: bool, pub rust_debug_logging: bool,
@ -1115,9 +1117,9 @@ struct Rust {
debug: Option<bool> = "debug", debug: Option<bool> = "debug",
codegen_units: Option<u32> = "codegen-units", codegen_units: Option<u32> = "codegen-units",
codegen_units_std: Option<u32> = "codegen-units-std", codegen_units_std: Option<u32> = "codegen-units-std",
debug_assertions: Option<bool> = "debug-assertions", rustc_debug_assertions: Option<bool> = "debug-assertions",
randomize_layout: Option<bool> = "randomize-layout", randomize_layout: Option<bool> = "randomize-layout",
debug_assertions_std: Option<bool> = "debug-assertions-std", std_debug_assertions: Option<bool> = "debug-assertions-std",
overflow_checks: Option<bool> = "overflow-checks", overflow_checks: Option<bool> = "overflow-checks",
overflow_checks_std: Option<bool> = "overflow-checks-std", overflow_checks_std: Option<bool> = "overflow-checks-std",
debug_logging: Option<bool> = "debug-logging", debug_logging: Option<bool> = "debug-logging",
@ -1652,8 +1654,8 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
let mut llvm_offload = None; let mut llvm_offload = None;
let mut llvm_plugins = None; let mut llvm_plugins = None;
let mut debug = None; let mut debug = None;
let mut debug_assertions = None; let mut rustc_debug_assertions = None;
let mut debug_assertions_std = None; let mut std_debug_assertions = None;
let mut overflow_checks = None; let mut overflow_checks = None;
let mut overflow_checks_std = None; let mut overflow_checks_std = None;
let mut debug_logging = None; let mut debug_logging = None;
@ -1675,8 +1677,8 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
debug: debug_toml, debug: debug_toml,
codegen_units, codegen_units,
codegen_units_std, codegen_units_std,
debug_assertions: debug_assertions_toml, rustc_debug_assertions: rustc_debug_assertions_toml,
debug_assertions_std: debug_assertions_std_toml, std_debug_assertions: std_debug_assertions_toml,
overflow_checks: overflow_checks_toml, overflow_checks: overflow_checks_toml,
overflow_checks_std: overflow_checks_std_toml, overflow_checks_std: overflow_checks_std_toml,
debug_logging: debug_logging_toml, debug_logging: debug_logging_toml,
@ -1734,8 +1736,8 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
config.download_ci_rustc_commit(download_rustc, config.llvm_assertions); config.download_ci_rustc_commit(download_rustc, config.llvm_assertions);
debug = debug_toml; debug = debug_toml;
debug_assertions = debug_assertions_toml; rustc_debug_assertions = rustc_debug_assertions_toml;
debug_assertions_std = debug_assertions_std_toml; std_debug_assertions = std_debug_assertions_toml;
overflow_checks = overflow_checks_toml; overflow_checks = overflow_checks_toml;
overflow_checks_std = overflow_checks_std_toml; overflow_checks_std = overflow_checks_std_toml;
debug_logging = debug_logging_toml; debug_logging = debug_logging_toml;
@ -2148,14 +2150,13 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
config.rust_std_features = std_features.unwrap_or(default_std_features); config.rust_std_features = std_features.unwrap_or(default_std_features);
let default = debug == Some(true); let default = debug == Some(true);
config.rust_debug_assertions = debug_assertions.unwrap_or(default); config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default);
config.rust_debug_assertions_std = config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions);
debug_assertions_std.unwrap_or(config.rust_debug_assertions);
config.rust_overflow_checks = overflow_checks.unwrap_or(default); config.rust_overflow_checks = overflow_checks.unwrap_or(default);
config.rust_overflow_checks_std = config.rust_overflow_checks_std =
overflow_checks_std.unwrap_or(config.rust_overflow_checks); overflow_checks_std.unwrap_or(config.rust_overflow_checks);
config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); config.rust_debug_logging = debug_logging.unwrap_or(config.rustc_debug_assertions);
let with_defaults = |debuginfo_level_specific: Option<_>| { let with_defaults = |debuginfo_level_specific: Option<_>| {
debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
@ -3075,8 +3076,8 @@ macro_rules! warn {
debug: _, debug: _,
codegen_units: _, codegen_units: _,
codegen_units_std: _, codegen_units_std: _,
debug_assertions: _, rustc_debug_assertions: _,
debug_assertions_std: _, std_debug_assertions: _,
overflow_checks: _, overflow_checks: _,
overflow_checks_std: _, overflow_checks_std: _,
debuginfo_level: _, debuginfo_level: _,

View File

@ -42,10 +42,16 @@ pub(crate) fn new(matches: &getopts::Matches, dcx: DiagCtxtHandle<'_>) -> Option
scrape_tests, scrape_tests,
}), }),
(Some(_), false, _) | (None, true, _) => { (Some(_), false, _) | (None, true, _) => {
dcx.fatal("must use --scrape-examples-output-path and --scrape-examples-target-crate together"); dcx.fatal(
"must use --scrape-examples-output-path and --scrape-examples-target-crate \
together",
);
} }
(None, false, true) => { (None, false, true) => {
dcx.fatal("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests"); dcx.fatal(
"must use --scrape-examples-output-path and \
--scrape-examples-target-crate with --scrape-tests",
);
} }
(None, false, false) => None, (None, false, false) => None,
} }
@ -163,14 +169,15 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
}; };
// If this span comes from a macro expansion, then the source code may not actually show // If this span comes from a macro expansion, then the source code may not actually show
// a use of the given item, so it would be a poor example. Hence, we skip all uses in macros. // a use of the given item, so it would be a poor example. Hence, we skip all uses in
// macros.
if call_span.from_expansion() { if call_span.from_expansion() {
trace!("Rejecting expr from macro: {call_span:?}"); trace!("Rejecting expr from macro: {call_span:?}");
return; return;
} }
// If the enclosing item has a span coming from a proc macro, then we also don't want to include // If the enclosing item has a span coming from a proc macro, then we also don't want to
// the example. // include the example.
let enclosing_item_span = let enclosing_item_span =
tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id).into()); tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id).into());
if enclosing_item_span.from_expansion() { if enclosing_item_span.from_expansion() {
@ -178,11 +185,12 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
return; return;
} }
// If the enclosing item doesn't actually enclose the call, this means we probably have a weird // If the enclosing item doesn't actually enclose the call, this means we probably have a
// macro issue even though the spans aren't tagged as being from an expansion. // weird macro issue even though the spans aren't tagged as being from an expansion.
if !enclosing_item_span.contains(call_span) { if !enclosing_item_span.contains(call_span) {
warn!( warn!(
"Attempted to scrape call at [{call_span:?}] whose enclosing item [{enclosing_item_span:?}] doesn't contain the span of the call." "Attempted to scrape call at [{call_span:?}] whose enclosing item \
[{enclosing_item_span:?}] doesn't contain the span of the call."
); );
return; return;
} }
@ -190,7 +198,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
// Similarly for the call w/ the function ident. // Similarly for the call w/ the function ident.
if !call_span.contains(ident_span) { if !call_span.contains(ident_span) {
warn!( warn!(
"Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was not contained in the span of the call." "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was \
not contained in the span of the call."
); );
return; return;
} }
@ -224,7 +233,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
Some(url) => url, Some(url) => url,
None => { None => {
trace!( trace!(
"Rejecting expr ({call_span:?}) whose clean span ({clean_span:?}) cannot be turned into a link" "Rejecting expr ({call_span:?}) whose clean span ({clean_span:?}) \
cannot be turned into a link"
); );
return; return;
} }
@ -272,7 +282,8 @@ pub(crate) fn run(
let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?; let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
// Collect CrateIds corresponding to provided target crates // Collect CrateIds corresponding to provided target crates
// If two different versions of the crate in the dependency tree, then examples will be collected from both. // If two different versions of the crate in the dependency tree, then examples will be
// collected from both.
let all_crates = tcx let all_crates = tcx
.crates(()) .crates(())
.iter() .iter()

View File

@ -236,8 +236,11 @@ pub struct Config {
/// Run ignored tests /// Run ignored tests
pub run_ignored: bool, pub run_ignored: bool,
/// Whether to run tests with `ignore-debug` header /// Whether rustc was built with debug assertions.
pub with_debug_assertions: bool, pub with_rustc_debug_assertions: bool,
/// Whether std was built with debug assertions.
pub with_std_debug_assertions: bool,
/// Only run tests that match these filters /// Only run tests that match these filters
pub filters: Vec<String>, pub filters: Vec<String>,

View File

@ -46,7 +46,6 @@
"ignore-coverage-map", "ignore-coverage-map",
"ignore-coverage-run", "ignore-coverage-run",
"ignore-cross-compile", "ignore-cross-compile",
"ignore-debug",
"ignore-eabi", "ignore-eabi",
"ignore-emscripten", "ignore-emscripten",
"ignore-endian-big", "ignore-endian-big",
@ -82,6 +81,7 @@
"ignore-powerpc", "ignore-powerpc",
"ignore-remote", "ignore-remote",
"ignore-riscv64", "ignore-riscv64",
"ignore-rustc-debug-assertions",
"ignore-s390x", "ignore-s390x",
"ignore-sgx", "ignore-sgx",
"ignore-sparc64", "ignore-sparc64",
@ -89,6 +89,7 @@
"ignore-stable", "ignore-stable",
"ignore-stage1", "ignore-stage1",
"ignore-stage2", "ignore-stage2",
"ignore-std-debug-assertions",
"ignore-test", "ignore-test",
"ignore-thumb", "ignore-thumb",
"ignore-thumbv8m.base-none-eabi", "ignore-thumbv8m.base-none-eabi",
@ -135,6 +136,7 @@
"needs-relocation-model-pic", "needs-relocation-model-pic",
"needs-run-enabled", "needs-run-enabled",
"needs-rust-lld", "needs-rust-lld",
"needs-rustc-debug-assertions",
"needs-sanitizer-address", "needs-sanitizer-address",
"needs-sanitizer-cfi", "needs-sanitizer-cfi",
"needs-sanitizer-dataflow", "needs-sanitizer-dataflow",
@ -147,6 +149,7 @@
"needs-sanitizer-shadow-call-stack", "needs-sanitizer-shadow-call-stack",
"needs-sanitizer-support", "needs-sanitizer-support",
"needs-sanitizer-thread", "needs-sanitizer-thread",
"needs-std-debug-assertions",
"needs-symlink", "needs-symlink",
"needs-threads", "needs-threads",
"needs-unwind", "needs-unwind",

View File

@ -202,9 +202,14 @@ macro_rules! condition {
message: "when running tests remotely", message: "when running tests remotely",
} }
condition! { condition! {
name: "debug", name: "rustc-debug-assertions",
condition: config.with_debug_assertions, condition: config.with_rustc_debug_assertions,
message: "when running tests with `ignore-debug` header", message: "when rustc is built with debug assertions",
}
condition! {
name: "std-debug-assertions",
condition: config.with_std_debug_assertions,
message: "when std is built with debug assertions",
} }
condition! { condition! {
name: config.debugger.as_ref().map(|d| d.to_str()), name: config.debugger.as_ref().map(|d| d.to_str()),

View File

@ -159,6 +159,16 @@ pub(super) fn handle_needs(
condition: cache.llvm_zstd, condition: cache.llvm_zstd,
ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression", ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression",
}, },
Need {
name: "needs-rustc-debug-assertions",
condition: config.with_rustc_debug_assertions,
ignore_reason: "ignored if rustc wasn't built with debug assertions",
},
Need {
name: "needs-std-debug-assertions",
condition: config.with_std_debug_assertions,
ignore_reason: "ignored if std wasn't built with debug assertions",
},
]; ];
let (name, comment) = match ln.split_once([':', ' ']) { let (name, comment) = match ln.split_once([':', ' ']) {

View File

@ -74,6 +74,8 @@ struct ConfigBuilder {
git_hash: bool, git_hash: bool,
system_llvm: bool, system_llvm: bool,
profiler_runtime: bool, profiler_runtime: bool,
rustc_debug_assertions: bool,
std_debug_assertions: bool,
} }
impl ConfigBuilder { impl ConfigBuilder {
@ -122,6 +124,16 @@ fn profiler_runtime(&mut self, is_available: bool) -> &mut Self {
self self
} }
fn rustc_debug_assertions(&mut self, is_enabled: bool) -> &mut Self {
self.rustc_debug_assertions = is_enabled;
self
}
fn std_debug_assertions(&mut self, is_enabled: bool) -> &mut Self {
self.std_debug_assertions = is_enabled;
self
}
fn build(&mut self) -> Config { fn build(&mut self) -> Config {
let args = &[ let args = &[
"compiletest", "compiletest",
@ -170,6 +182,12 @@ fn build(&mut self) -> Config {
if self.profiler_runtime { if self.profiler_runtime {
args.push("--profiler-runtime".to_owned()); args.push("--profiler-runtime".to_owned());
} }
if self.rustc_debug_assertions {
args.push("--with-rustc-debug-assertions".to_owned());
}
if self.std_debug_assertions {
args.push("--with-std-debug-assertions".to_owned());
}
args.push("--rustc-path".to_string()); args.push("--rustc-path".to_string());
// This is a subtle/fragile thing. On rust-lang CI, there is no global // This is a subtle/fragile thing. On rust-lang CI, there is no global
@ -314,6 +332,32 @@ fn only_target() {
assert!(!check_ignore(&config, "//@ only-64bit")); assert!(!check_ignore(&config, "//@ only-64bit"));
} }
#[test]
fn rustc_debug_assertions() {
let config: Config = cfg().rustc_debug_assertions(false).build();
assert!(check_ignore(&config, "//@ needs-rustc-debug-assertions"));
assert!(!check_ignore(&config, "//@ ignore-rustc-debug-assertions"));
let config: Config = cfg().rustc_debug_assertions(true).build();
assert!(!check_ignore(&config, "//@ needs-rustc-debug-assertions"));
assert!(check_ignore(&config, "//@ ignore-rustc-debug-assertions"));
}
#[test]
fn std_debug_assertions() {
let config: Config = cfg().std_debug_assertions(false).build();
assert!(check_ignore(&config, "//@ needs-std-debug-assertions"));
assert!(!check_ignore(&config, "//@ ignore-std-debug-assertions"));
let config: Config = cfg().std_debug_assertions(true).build();
assert!(!check_ignore(&config, "//@ needs-std-debug-assertions"));
assert!(check_ignore(&config, "//@ ignore-std-debug-assertions"));
}
#[test] #[test]
fn stage() { fn stage() {
let config: Config = cfg().stage_id("stage1-x86_64-unknown-linux-gnu").build(); let config: Config = cfg().stage_id("stage1-x86_64-unknown-linux-gnu").build();

View File

@ -88,7 +88,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
.optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
.optflag("", "ignored", "run tests marked as ignored") .optflag("", "ignored", "run tests marked as ignored")
.optflag("", "has-enzyme", "run tests that require enzyme") .optflag("", "has-enzyme", "run tests that require enzyme")
.optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header") .optflag("", "with-rustc-debug-assertions", "whether rustc was built with debug assertions")
.optflag("", "with-std-debug-assertions", "whether std was built with debug assertions")
.optmulti( .optmulti(
"", "",
"skip", "skip",
@ -235,7 +236,8 @@ fn make_absolute(path: PathBuf) -> PathBuf {
let src_base = opt_path(matches, "src-base"); let src_base = opt_path(matches, "src-base");
let run_ignored = matches.opt_present("ignored"); let run_ignored = matches.opt_present("ignored");
let with_debug_assertions = matches.opt_present("with-debug-assertions"); let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions");
let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode");
let has_html_tidy = if mode == Mode::Rustdoc { let has_html_tidy = if mode == Mode::Rustdoc {
Command::new("tidy") Command::new("tidy")
@ -293,7 +295,8 @@ fn make_absolute(path: PathBuf) -> PathBuf {
suite: matches.opt_str("suite").unwrap(), suite: matches.opt_str("suite").unwrap(),
debugger: None, debugger: None,
run_ignored, run_ignored,
with_debug_assertions, with_rustc_debug_assertions,
with_std_debug_assertions,
filters, filters,
skip: matches.opt_strs("skip"), skip: matches.opt_strs("skip"),
filter_exact: matches.opt_present("exact"), filter_exact: matches.opt_present("exact"),

View File

@ -1,5 +1,5 @@
//@ compile-flags: -O //@ compile-flags: -O
//@ ignore-debug //@ ignore-std-debug-assertions
#![crate_type = "lib"] #![crate_type = "lib"]
use std::collections::binary_heap::PeekMut; use std::collections::binary_heap::PeekMut;

View File

@ -4,7 +4,8 @@
// known to be `1` after inlining). // known to be `1` after inlining).
//@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no //@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no
//@ ignore-debug: precondition checks in ptr::read make them a bad candidate for MIR inlining //@ ignore-std-debug-assertions
// Reason: precondition checks in ptr::read make them a bad candidate for MIR inlining
//@ needs-deterministic-layouts //@ needs-deterministic-layouts
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,6 +1,7 @@
//@ compile-flags: -O -C no-prepopulate-passes //@ compile-flags: -O -C no-prepopulate-passes
//@ only-x86_64 (to not worry about usize differing) //@ only-x86_64 (to not worry about usize differing)
//@ ignore-debug: precondition checks make mem::replace not a candidate for MIR inlining //@ ignore-std-debug-assertions
// Reason: precondition checks make mem::replace not a candidate for MIR inlining
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -31,7 +31,7 @@
// CHECK-LABEL: @bitmask_int // CHECK-LABEL: @bitmask_int
#[no_mangle] #[no_mangle]
pub unsafe fn bitmask_int(x: i32x2) -> u8 { pub unsafe fn bitmask_int(x: i32x2) -> u8 {
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31> // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
// CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@ -41,7 +41,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 {
// CHECK-LABEL: @bitmask_uint // CHECK-LABEL: @bitmask_uint
#[no_mangle] #[no_mangle]
pub unsafe fn bitmask_uint(x: u32x2) -> u8 { pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31> // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
// CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@ -51,7 +51,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
// CHECK-LABEL: @bitmask_int16 // CHECK-LABEL: @bitmask_int16
#[no_mangle] #[no_mangle]
pub unsafe fn bitmask_int16(x: i8x16) -> u16 { pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
// CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7> // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
// CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
// CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16 // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
// CHECK-NOT: zext // CHECK-NOT: zext

View File

@ -1,6 +1,6 @@
//@ compile-flags: -O //@ compile-flags: -O
//@ only-x86_64 //@ only-x86_64
//@ ignore-debug: debug assertions prevent generating shufflevector //@ ignore-std-debug-assertions (debug assertions prevent generating shufflevector)
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,4 +1,4 @@
//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata //@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata)
//@ compile-flags: -O -Z merge-functions=disabled //@ compile-flags: -O -Z merge-functions=disabled
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,7 +1,7 @@
// LLVM 17 realizes double panic is not possible and doesn't generate calls // LLVM 17 realizes double panic is not possible and doesn't generate calls
// to panic_cannot_unwind. // to panic_cannot_unwind.
//@ compile-flags: -O //@ compile-flags: -O
//@ ignore-debug: plain old debug assertions //@ ignore-std-debug-assertions (plain old debug assertions)
//@ needs-unwind //@ needs-unwind
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(shrink_to)] #![feature(shrink_to)]

View File

@ -1,5 +1,5 @@
//@ compile-flags: -O //@ compile-flags: -O
//@ ignore-debug //@ ignore-std-debug-assertions
// (with debug assertions turned on, `assert_unchecked` generates a real assertion) // (with debug assertions turned on, `assert_unchecked` generates a real assertion)
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -2,7 +2,7 @@
//@ compile-flags: -O //@ compile-flags: -O
//@ needs-deterministic-layouts //@ needs-deterministic-layouts
//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata //@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata)
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,7 +1,7 @@
// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic. // This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic.
//@ compile-flags: -O //@ compile-flags: -O
//@ ignore-debug: plain old debug assertions //@ ignore-std-debug-assertions (plain old debug assertions)
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,6 +1,7 @@
// skip-filecheck // skip-filecheck
//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir
//@ ignore-debug: precondition checks on ptr::read/write are under cfg(debug_assertions) //@ ignore-std-debug-assertions
// Reason: precondition checks on ptr::read/write are under cfg(debug_assertions)
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,6 +1,6 @@
// skip-filecheck // skip-filecheck
//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir
//@ ignore-debug: precondition checks are under cfg(debug_assertions) //@ ignore-std-debug-assertions (precondition checks are under cfg(debug_assertions))
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -1,7 +1,7 @@
// skip-filecheck // skip-filecheck
//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
//@ only-64bit (constants for `None::<&T>` show in the output) //@ only-64bit (constants for `None::<&T>` show in the output)
//@ ignore-debug: precondition checks on ptr::add are under cfg(debug_assertions) //@ ignore-std-debug-assertions (precondition checks on ptr::add are under cfg(debug_assertions))
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![crate_type = "lib"] #![crate_type = "lib"]

View File

@ -0,0 +1,149 @@
//@ run-pass
//! Test information about crate definitions (local and external).
//@ ignore-stage1
//@ ignore-cross-compile
//@ ignore-remote
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
#![feature(rustc_private)]
#![feature(assert_matches)]
extern crate rustc_hir;
#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;
use rustc_smir::rustc_internal;
use stable_mir::CrateDef;
use std::collections::HashSet;
use std::io::Write;
use std::ops::ControlFlow;
const CRATE_NAME: &str = "crate_defs";
/// This function uses the Stable MIR APIs to get information about the test crate.
fn test_stable_mir() -> ControlFlow<()> {
// Find items in the local crate.
let local = stable_mir::local_crate();
check_items(&local.statics(), &["PRIVATE_STATIC", "dummy::PUBLIC_STATIC"]);
check_items(
&local.fn_defs(),
&[
"top_level",
"dummy::public_fn",
"dummy::private_fn",
"dummy::PrivateStruct::new",
"<dummy::PrivateStruct as std::ops::Drop>::drop",
"DummyTrait::method",
"<T as DummyTrait>::method",
],
);
// Find items inside core crate.
// FIXME: We are currently missing primitive type methods and trait implementations for external
// crates.
let core = stable_mir::find_crates("core").pop().expect("Cannot find `core` crate");
contains(
&core.fn_defs(),
&[
"std::fmt::Debug::fmt",
"std::option::Option::<T>::is_some",
"std::ptr::swap",
"<std::slice::Iter<'a, T> as std::iter::Iterator>::next",
"core::num::<impl u8>::abs_diff",
],
);
// Ensure nothing crashes. There is no public static in core that we can test here.
let _ = core.statics();
ControlFlow::Continue(())
}
/// Check if the list of definitions matches the expected list.
/// Note that order doesn't matter.
fn check_items<T: CrateDef>(items: &[T], expected: &[&str]) {
let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect();
let item_names: HashSet<_> = items.iter().map(|item| item.name()).collect();
assert_eq!(item_names, expected);
}
/// Check that the list contains the expected items.
fn contains<T: CrateDef + std::fmt::Debug>(items: &[T], expected: &[&str]) {
let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect();
let item_names = items.iter().map(|item| item.name()).collect();
let not_found: Vec<_> = expected.difference(&item_names).collect();
assert!(not_found.is_empty(), "Missing items: {:?}", not_found);
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then
/// it will run the compiler.
fn main() {
let path = "crate_definitions.rs";
generate_input(&path).unwrap();
let args = vec![
"rustc".to_string(),
"--crate-type=lib".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
];
run!(args, test_stable_mir).unwrap();
}
fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
#![allow(dead_code, unused_variables)]
static PRIVATE_STATIC: u8 = 0;
fn top_level() -> &'static str {{
"hello"
}}
pub trait DummyTrait {{
fn method(&self) -> Self;
}}
impl<T: Copy> DummyTrait for T {{
fn method(&self) -> T {{
*self
}}
}}
pub mod dummy {{
pub static mut PUBLIC_STATIC: Option<char> = None;
pub fn public_fn(input: bool) -> bool {{
private_fn(!input)
}}
fn private_fn(input: bool) -> bool {{
todo!()
}}
struct PrivateStruct {{
field: u32,
}}
impl PrivateStruct {{
fn new() -> Self {{
Self {{ field: 42 }}
}}
}}
impl Drop for PrivateStruct {{
fn drop(&mut self) {{
println!("Dropping PrivateStruct");
}}
}}
}}
"#
)?;
Ok(())
}

View File

@ -11,12 +11,12 @@ LL | *ptr = 0;
| ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
| |
= note: accessing memory with alignment 1, but alignment 4 is required = note: accessing memory with alignment 1, but alignment 4 is required
| |
note: inside `copy_nonoverlapping::<u32>` note: inside `copy_nonoverlapping::<u32>`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping` note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `MISALIGNED_COPY` note: inside `MISALIGNED_COPY`

View File

@ -27,7 +27,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
= help: the trait `FnOnce()` is not implemented for `{integer}` = help: the trait `FnOnce()` is not implemented for `{integer}`
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `const_eval_select` note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
error[E0277]: expected a `FnOnce()` closure, found `{integer}` error[E0277]: expected a `FnOnce()` closure, found `{integer}`
--> $DIR/const-eval-select-bad.rs:10:31 --> $DIR/const-eval-select-bad.rs:10:31
@ -40,7 +40,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
= help: the trait `FnOnce()` is not implemented for `{integer}` = help: the trait `FnOnce()` is not implemented for `{integer}`
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `const_eval_select` note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
error: this argument must be a function item error: this argument must be a function item
--> $DIR/const-eval-select-bad.rs:10:27 --> $DIR/const-eval-select-bad.rs:10:27
@ -69,7 +69,7 @@ LL | const_eval_select((1,), foo, bar);
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `const_eval_select` note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
error[E0631]: type mismatch in function arguments error[E0631]: type mismatch in function arguments
--> $DIR/const-eval-select-bad.rs:37:32 --> $DIR/const-eval-select-bad.rs:37:32
@ -85,7 +85,7 @@ LL | const_eval_select((true,), foo, baz);
= note: expected function signature `fn(bool) -> _` = note: expected function signature `fn(bool) -> _`
found function signature `fn(i32) -> _` found function signature `fn(i32) -> _`
note: required by a bound in `const_eval_select` note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
help: consider wrapping the function in a closure help: consider wrapping the function in a closure
| |
LL | const_eval_select((true,), |arg0: bool| foo(/* i32 */), baz); LL | const_eval_select((true,), |arg0: bool| foo(/* i32 */), baz);

View File

@ -9,7 +9,7 @@
//! padding and overall computed sizes can be quite different. //! padding and overall computed sizes can be quite different.
//! //!
//@ compile-flags: -Z print-type-sizes --crate-type lib //@ compile-flags: -Z print-type-sizes --crate-type lib
//@ ignore-debug: debug assertions will print more types //@ ignore-std-debug-assertions (debug assertions will print more types)
//@ build-pass //@ build-pass
//@ ignore-pass //@ ignore-pass
// ^-- needed because `--pass check` does not emit the output needed. // ^-- needed because `--pass check` does not emit the output needed.

View File

@ -0,0 +1,13 @@
//Missing paren in diagnostic msg: https://github.com/rust-lang/rust/issues/131977
//@check-pass
static mut TEST: usize = 0;
fn main() {
let _ = unsafe { (&TEST) as *const usize };
//~^WARN creating a shared reference to mutable static is discouraged
let _ = unsafe { ((&mut TEST)) as *const usize };
//~^WARN creating a mutable reference to mutable static is discouraged
}

View File

@ -0,0 +1,29 @@
warning: creating a shared reference to mutable static is discouraged
--> $DIR/static-mut-shared-parens.rs:8:22
|
LL | let _ = unsafe { (&TEST) as *const usize };
| ^^^^^^^ shared reference to mutable static
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
= note: `#[warn(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
|
LL | let _ = unsafe { (&raw const TEST) as *const usize };
| ~~~~~~~~~~
warning: creating a mutable reference to mutable static is discouraged
--> $DIR/static-mut-shared-parens.rs:11:22
|
LL | let _ = unsafe { ((&mut TEST)) as *const usize };
| ^^^^^^^^^^^^^ mutable reference to mutable static
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
= note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
help: use `&raw mut` instead to create a raw pointer
|
LL | let _ = unsafe { ((&raw mut TEST)) as *const usize };
| ~~~~~~~~
warning: 2 warnings emitted