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:
commit
78bb5ee79e
@ -2,6 +2,7 @@
|
||||
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||
ImportLibraryItem,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
|
||||
@ -16,7 +17,7 @@ fn create_dll_import_lib(
|
||||
&self,
|
||||
_sess: &Session,
|
||||
_lib_name: &str,
|
||||
_import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
||||
_items: Vec<ImportLibraryItem>,
|
||||
_output_path: &Path,
|
||||
) {
|
||||
unimplemented!("creating dll imports is not yet supported");
|
||||
|
@ -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 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
|
||||
// On x86 Windows, LLVM uses 'L' as the prefix for any private
|
||||
// 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
|
||||
// existing logic below to set the Storage Class, but it has an
|
||||
// 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 {
|
||||
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
|
||||
}
|
||||
|
@ -194,16 +194,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
|
||||
unsafe { llvm::LLVMSetInitializer(g2, g1) };
|
||||
g2
|
||||
} 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)
|
||||
{
|
||||
cx.declare_global(
|
||||
&common::i686_decorated_name(
|
||||
dllimport,
|
||||
common::is_mingw_gnu_toolchain(&cx.tcx.sess.target),
|
||||
true,
|
||||
),
|
||||
llty,
|
||||
)
|
||||
cx.declare_global(&common::i686_decorated_name(dllimport, true, true, false), llty)
|
||||
} else {
|
||||
// Generate an external declaration.
|
||||
// FIXME(nagisa): investigate whether it can be changed into define_global
|
||||
|
@ -154,6 +154,11 @@ pub(crate) unsafe fn create_module<'ll>(
|
||||
// See https://github.com/llvm/llvm-project/pull/106951
|
||||
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.
|
||||
|
@ -26,6 +26,35 @@
|
||||
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 {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
||||
|
||||
@ -38,7 +67,7 @@ fn create_dll_import_lib(
|
||||
&self,
|
||||
sess: &Session,
|
||||
lib_name: &str,
|
||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
||||
items: Vec<ImportLibraryItem>,
|
||||
output_path: &Path,
|
||||
) {
|
||||
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
|
||||
// functions. Therefore, use binutils to create the import library instead,
|
||||
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
||||
create_mingw_dll_import_lib(
|
||||
sess,
|
||||
lib_name,
|
||||
import_name_and_ordinal_vector,
|
||||
output_path,
|
||||
);
|
||||
create_mingw_dll_import_lib(sess, lib_name, items, output_path);
|
||||
} else {
|
||||
trace!("creating import library");
|
||||
trace!(" dll_name {:#?}", lib_name);
|
||||
trace!(" output_path {}", output_path.display());
|
||||
trace!(
|
||||
" import names: {}",
|
||||
import_name_and_ordinal_vector
|
||||
items
|
||||
.iter()
|
||||
.map(|(name, _ordinal)| name.clone())
|
||||
.map(|ImportLibraryItem { name, .. }| name.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
);
|
||||
@ -79,20 +103,7 @@ fn create_dll_import_lib(
|
||||
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
|
||||
};
|
||||
|
||||
let exports = import_name_and_ordinal_vector
|
||||
.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 exports = items.into_iter().map(Into::into).collect::<Vec<_>>();
|
||||
let machine = match &*sess.target.arch {
|
||||
"x86_64" => MachineTypes::AMD64,
|
||||
"x86" => MachineTypes::I386,
|
||||
@ -160,16 +171,16 @@ fn extract_bundled_libs<'a>(
|
||||
fn create_mingw_dll_import_lib(
|
||||
sess: &Session,
|
||||
lib_name: &str,
|
||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
||||
items: Vec<ImportLibraryItem>,
|
||||
output_path: &Path,
|
||||
) {
|
||||
let def_file_path = output_path.with_extension("def");
|
||||
|
||||
let def_file_content = format!(
|
||||
"EXPORTS\n{}",
|
||||
import_name_and_ordinal_vector
|
||||
items
|
||||
.into_iter()
|
||||
.map(|(name, ordinal)| {
|
||||
.map(|ImportLibraryItem { name, ordinal, .. }| {
|
||||
match ordinal {
|
||||
Some(n) => format!("{name} @{n} NONAME"),
|
||||
None => name,
|
||||
|
@ -45,7 +45,7 @@
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
|
||||
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder, ImportLibraryItem};
|
||||
use super::command::Command;
|
||||
use super::linker::{self, Linker};
|
||||
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 import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports
|
||||
let items: Vec<ImportLibraryItem> = raw_dylib_imports
|
||||
.iter()
|
||||
.map(|import: &DllImport| {
|
||||
if sess.target.arch == "x86" {
|
||||
(
|
||||
common::i686_decorated_name(import, mingw_gnu_toolchain, false),
|
||||
import.ordinal(),
|
||||
)
|
||||
ImportLibraryItem {
|
||||
name: common::i686_decorated_name(
|
||||
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 {
|
||||
(import.name.to_string(), import.ordinal())
|
||||
ImportLibraryItem {
|
||||
name: import.name.to_string(),
|
||||
ordinal: import.ordinal(),
|
||||
symbol_name: None,
|
||||
is_data: !import.is_fn,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -512,7 +531,7 @@ fn create_dll_import_libs<'a>(
|
||||
archive_builder_builder.create_dll_import_lib(
|
||||
sess,
|
||||
&raw_dylib_name,
|
||||
import_name_and_ordinal_vector,
|
||||
items,
|
||||
&output_path,
|
||||
);
|
||||
|
||||
|
@ -187,12 +187,15 @@ pub fn i686_decorated_name(
|
||||
dll_import: &DllImport,
|
||||
mingw: bool,
|
||||
disable_name_mangling: bool,
|
||||
force_fully_decorated: bool,
|
||||
) -> String {
|
||||
let name = dll_import.name.as_str();
|
||||
|
||||
let (add_prefix, add_suffix) = match dll_import.import_name_type {
|
||||
Some(PeImportNameType::NoPrefix) => (false, true),
|
||||
Some(PeImportNameType::Undecorated) => (false, false),
|
||||
let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) {
|
||||
// No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will
|
||||
// ignore `force_fully_decorated` and always partially decorate it.
|
||||
(_, Some(PeImportNameType::NoPrefix)) => (false, true),
|
||||
(false, Some(PeImportNameType::Undecorated)) => (false, false),
|
||||
_ => (true, true),
|
||||
};
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
use rustc_middle::ty::{Mutability, TyKind};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::lints::{MutRefSugg, RefOfMutStatic};
|
||||
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)
|
||||
&& let Some(err_span) = path_is_static_mut(ex, err_span) =>
|
||||
{
|
||||
emit_static_mut_refs(
|
||||
cx,
|
||||
err_span,
|
||||
err_span.with_hi(ex.span.lo()),
|
||||
m,
|
||||
!expr.span.from_expansion(),
|
||||
);
|
||||
let source_map = cx.sess().source_map();
|
||||
let snippet = source_map.span_to_snippet(err_span);
|
||||
|
||||
let sugg_span = if let Ok(snippet) = snippet {
|
||||
// ( ( &IDENT ) )
|
||||
// ~~~~ 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, _, _)
|
||||
if let Some(err_span) = path_is_static_mut(e, expr.span)
|
||||
|
@ -384,6 +384,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
|
||||
crate_hash => { cdata.root.header.hash }
|
||||
crate_host_hash => { cdata.host_hash }
|
||||
crate_name => { cdata.root.header.name }
|
||||
num_extern_def_ids => { cdata.num_def_ids() }
|
||||
|
||||
extra_filename => { cdata.root.extra_filename.clone() }
|
||||
|
||||
|
@ -1844,6 +1844,16 @@
|
||||
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 {
|
||||
desc { "calculating the lib features defined in a crate" }
|
||||
separate_provide_extern
|
||||
|
@ -130,6 +130,11 @@ pub fn ordinal(&self) -> Option<u16> {
|
||||
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.
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
use crate::rustc_internal::RustcInternal;
|
||||
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> {
|
||||
fn target_info(&self) -> MachineInfo {
|
||||
@ -80,6 +80,20 @@ fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignMod
|
||||
.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(
|
||||
&self,
|
||||
mod_def: stable_mir::ty::ForeignModuleDef,
|
||||
|
@ -15,8 +15,8 @@
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::mir::mono::InstanceDef;
|
||||
use stable_mir::ty::{MirConstId, Span, TyConstId};
|
||||
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||
use stable_mir::ty::{FnDef, MirConstId, Span, TyConstId};
|
||||
use stable_mir::{CtorKind, ItemKind};
|
||||
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)
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
|
||||
std: None, // ?
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions {
|
||||
abi: "abi64".into(),
|
||||
|
@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions {
|
||||
abi: "abi64".into(),
|
||||
|
@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions {
|
||||
abi: "abi64".into(),
|
||||
|
@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions {
|
||||
abi: "abi64".into(),
|
||||
|
@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base },
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
|
||||
std: None, // ?
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions {
|
||||
abi: "abi64".into(),
|
||||
|
@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
|
||||
std: Some(true),
|
||||
},
|
||||
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(),
|
||||
options: TargetOptions {
|
||||
abi: "abi64".into(),
|
||||
|
@ -34,6 +34,12 @@ pub trait Context {
|
||||
/// Check whether the body of a function is available.
|
||||
fn has_body(&self, item: DefId) -> bool;
|
||||
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_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
|
||||
fn all_trait_decls(&self) -> TraitDecls;
|
||||
|
@ -25,8 +25,9 @@
|
||||
use crate::compiler_interface::with;
|
||||
pub use crate::crate_def::{CrateDef, CrateDefType, DefId};
|
||||
pub use crate::error::*;
|
||||
use crate::mir::mono::StaticDef;
|
||||
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;
|
||||
#[macro_use]
|
||||
@ -96,6 +97,16 @@ pub fn trait_decls(&self) -> TraitDecls {
|
||||
pub fn trait_impls(&self) -> ImplTraitDecls {
|
||||
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)]
|
||||
|
@ -2,7 +2,10 @@
|
||||
#![cfg(reliable_f128)]
|
||||
|
||||
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.
|
||||
|
||||
@ -53,7 +56,22 @@ macro_rules! assert_f128_biteq {
|
||||
|
||||
#[test]
|
||||
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]
|
||||
|
@ -33,7 +33,7 @@ fn main() {
|
||||
// Display PID of process holding the lock
|
||||
// PID will be stored in a lock file
|
||||
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()
|
||||
.write(true)
|
||||
@ -47,7 +47,11 @@ fn main() {
|
||||
}
|
||||
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());
|
||||
t!(lock.write(process::id().to_string().as_ref()));
|
||||
lock
|
||||
|
@ -1938,9 +1938,13 @@ fn run(self, builder: &Builder<'_>) {
|
||||
|
||||
cmd.arg("--json");
|
||||
|
||||
if builder.config.rust_debug_assertions_std {
|
||||
cmd.arg("--with-debug-assertions");
|
||||
};
|
||||
if builder.config.rustc_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 copts_passed = false;
|
||||
|
@ -833,9 +833,9 @@ fn cargo(
|
||||
cargo.env(
|
||||
profile_var("DEBUG_ASSERTIONS"),
|
||||
if mode == Mode::Std {
|
||||
self.config.rust_debug_assertions_std.to_string()
|
||||
self.config.std_debug_assertions.to_string()
|
||||
} else {
|
||||
self.config.rust_debug_assertions.to_string()
|
||||
self.config.rustc_debug_assertions.to_string()
|
||||
},
|
||||
);
|
||||
cargo.env(
|
||||
|
@ -263,8 +263,10 @@ pub struct Config {
|
||||
pub rust_optimize: RustOptimize,
|
||||
pub rust_codegen_units: 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_std: bool,
|
||||
pub rust_debug_logging: bool,
|
||||
@ -1115,9 +1117,9 @@ struct Rust {
|
||||
debug: Option<bool> = "debug",
|
||||
codegen_units: Option<u32> = "codegen-units",
|
||||
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",
|
||||
debug_assertions_std: Option<bool> = "debug-assertions-std",
|
||||
std_debug_assertions: Option<bool> = "debug-assertions-std",
|
||||
overflow_checks: Option<bool> = "overflow-checks",
|
||||
overflow_checks_std: Option<bool> = "overflow-checks-std",
|
||||
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_plugins = None;
|
||||
let mut debug = None;
|
||||
let mut debug_assertions = None;
|
||||
let mut debug_assertions_std = None;
|
||||
let mut rustc_debug_assertions = None;
|
||||
let mut std_debug_assertions = None;
|
||||
let mut overflow_checks = None;
|
||||
let mut overflow_checks_std = None;
|
||||
let mut debug_logging = None;
|
||||
@ -1675,8 +1677,8 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
|
||||
debug: debug_toml,
|
||||
codegen_units,
|
||||
codegen_units_std,
|
||||
debug_assertions: debug_assertions_toml,
|
||||
debug_assertions_std: debug_assertions_std_toml,
|
||||
rustc_debug_assertions: rustc_debug_assertions_toml,
|
||||
std_debug_assertions: std_debug_assertions_toml,
|
||||
overflow_checks: overflow_checks_toml,
|
||||
overflow_checks_std: overflow_checks_std_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);
|
||||
|
||||
debug = debug_toml;
|
||||
debug_assertions = debug_assertions_toml;
|
||||
debug_assertions_std = debug_assertions_std_toml;
|
||||
rustc_debug_assertions = rustc_debug_assertions_toml;
|
||||
std_debug_assertions = std_debug_assertions_toml;
|
||||
overflow_checks = overflow_checks_toml;
|
||||
overflow_checks_std = overflow_checks_std_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);
|
||||
|
||||
let default = debug == Some(true);
|
||||
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
|
||||
config.rust_debug_assertions_std =
|
||||
debug_assertions_std.unwrap_or(config.rust_debug_assertions);
|
||||
config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default);
|
||||
config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions);
|
||||
config.rust_overflow_checks = overflow_checks.unwrap_or(default);
|
||||
config.rust_overflow_checks_std =
|
||||
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<_>| {
|
||||
debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
|
||||
@ -3075,8 +3076,8 @@ macro_rules! warn {
|
||||
debug: _,
|
||||
codegen_units: _,
|
||||
codegen_units_std: _,
|
||||
debug_assertions: _,
|
||||
debug_assertions_std: _,
|
||||
rustc_debug_assertions: _,
|
||||
std_debug_assertions: _,
|
||||
overflow_checks: _,
|
||||
overflow_checks_std: _,
|
||||
debuginfo_level: _,
|
||||
|
@ -42,10 +42,16 @@ pub(crate) fn new(matches: &getopts::Matches, dcx: DiagCtxtHandle<'_>) -> Option
|
||||
scrape_tests,
|
||||
}),
|
||||
(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) => {
|
||||
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,
|
||||
}
|
||||
@ -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
|
||||
// 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() {
|
||||
trace!("Rejecting expr from macro: {call_span:?}");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the enclosing item has a span coming from a proc macro, then we also don't want to include
|
||||
// the example.
|
||||
// If the enclosing item has a span coming from a proc macro, then we also don't want to
|
||||
// include the example.
|
||||
let enclosing_item_span =
|
||||
tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id).into());
|
||||
if enclosing_item_span.from_expansion() {
|
||||
@ -178,11 +185,12 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the enclosing item doesn't actually enclose the call, this means we probably have a weird
|
||||
// macro issue even though the spans aren't tagged as being from an expansion.
|
||||
// If the enclosing item doesn't actually enclose the call, this means we probably have a
|
||||
// weird macro issue even though the spans aren't tagged as being from an expansion.
|
||||
if !enclosing_item_span.contains(call_span) {
|
||||
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;
|
||||
}
|
||||
@ -190,7 +198,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||
// Similarly for the call w/ the function ident.
|
||||
if !call_span.contains(ident_span) {
|
||||
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;
|
||||
}
|
||||
@ -224,7 +233,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
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;
|
||||
}
|
||||
@ -272,7 +282,8 @@ pub(crate) fn run(
|
||||
let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
|
||||
|
||||
// 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
|
||||
.crates(())
|
||||
.iter()
|
||||
|
@ -236,8 +236,11 @@ pub struct Config {
|
||||
/// Run ignored tests
|
||||
pub run_ignored: bool,
|
||||
|
||||
/// Whether to run tests with `ignore-debug` header
|
||||
pub with_debug_assertions: bool,
|
||||
/// Whether rustc was built with debug assertions.
|
||||
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
|
||||
pub filters: Vec<String>,
|
||||
|
@ -46,7 +46,6 @@
|
||||
"ignore-coverage-map",
|
||||
"ignore-coverage-run",
|
||||
"ignore-cross-compile",
|
||||
"ignore-debug",
|
||||
"ignore-eabi",
|
||||
"ignore-emscripten",
|
||||
"ignore-endian-big",
|
||||
@ -82,6 +81,7 @@
|
||||
"ignore-powerpc",
|
||||
"ignore-remote",
|
||||
"ignore-riscv64",
|
||||
"ignore-rustc-debug-assertions",
|
||||
"ignore-s390x",
|
||||
"ignore-sgx",
|
||||
"ignore-sparc64",
|
||||
@ -89,6 +89,7 @@
|
||||
"ignore-stable",
|
||||
"ignore-stage1",
|
||||
"ignore-stage2",
|
||||
"ignore-std-debug-assertions",
|
||||
"ignore-test",
|
||||
"ignore-thumb",
|
||||
"ignore-thumbv8m.base-none-eabi",
|
||||
@ -135,6 +136,7 @@
|
||||
"needs-relocation-model-pic",
|
||||
"needs-run-enabled",
|
||||
"needs-rust-lld",
|
||||
"needs-rustc-debug-assertions",
|
||||
"needs-sanitizer-address",
|
||||
"needs-sanitizer-cfi",
|
||||
"needs-sanitizer-dataflow",
|
||||
@ -147,6 +149,7 @@
|
||||
"needs-sanitizer-shadow-call-stack",
|
||||
"needs-sanitizer-support",
|
||||
"needs-sanitizer-thread",
|
||||
"needs-std-debug-assertions",
|
||||
"needs-symlink",
|
||||
"needs-threads",
|
||||
"needs-unwind",
|
||||
|
@ -202,9 +202,14 @@ macro_rules! condition {
|
||||
message: "when running tests remotely",
|
||||
}
|
||||
condition! {
|
||||
name: "debug",
|
||||
condition: config.with_debug_assertions,
|
||||
message: "when running tests with `ignore-debug` header",
|
||||
name: "rustc-debug-assertions",
|
||||
condition: config.with_rustc_debug_assertions,
|
||||
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! {
|
||||
name: config.debugger.as_ref().map(|d| d.to_str()),
|
||||
|
@ -159,6 +159,16 @@ pub(super) fn handle_needs(
|
||||
condition: cache.llvm_zstd,
|
||||
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([':', ' ']) {
|
||||
|
@ -74,6 +74,8 @@ struct ConfigBuilder {
|
||||
git_hash: bool,
|
||||
system_llvm: bool,
|
||||
profiler_runtime: bool,
|
||||
rustc_debug_assertions: bool,
|
||||
std_debug_assertions: bool,
|
||||
}
|
||||
|
||||
impl ConfigBuilder {
|
||||
@ -122,6 +124,16 @@ fn profiler_runtime(&mut self, is_available: bool) -> &mut 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 {
|
||||
let args = &[
|
||||
"compiletest",
|
||||
@ -170,6 +182,12 @@ fn build(&mut self) -> Config {
|
||||
if self.profiler_runtime {
|
||||
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());
|
||||
// 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"));
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn stage() {
|
||||
let config: Config = cfg().stage_id("stage1-x86_64-unknown-linux-gnu").build();
|
||||
|
@ -88,7 +88,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||
.optopt("", "run", "whether to execute run-* tests", "auto | always | never")
|
||||
.optflag("", "ignored", "run tests marked as ignored")
|
||||
.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(
|
||||
"",
|
||||
"skip",
|
||||
@ -235,7 +236,8 @@ fn make_absolute(path: PathBuf) -> PathBuf {
|
||||
|
||||
let src_base = opt_path(matches, "src-base");
|
||||
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 has_html_tidy = if mode == Mode::Rustdoc {
|
||||
Command::new("tidy")
|
||||
@ -293,7 +295,8 @@ fn make_absolute(path: PathBuf) -> PathBuf {
|
||||
suite: matches.opt_str("suite").unwrap(),
|
||||
debugger: None,
|
||||
run_ignored,
|
||||
with_debug_assertions,
|
||||
with_rustc_debug_assertions,
|
||||
with_std_debug_assertions,
|
||||
filters,
|
||||
skip: matches.opt_strs("skip"),
|
||||
filter_exact: matches.opt_present("exact"),
|
||||
|
@ -1,5 +1,5 @@
|
||||
//@ compile-flags: -O
|
||||
//@ ignore-debug
|
||||
//@ ignore-std-debug-assertions
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::collections::binary_heap::PeekMut;
|
||||
|
@ -4,7 +4,8 @@
|
||||
// known to be `1` after inlining).
|
||||
|
||||
//@ 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
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
@ -1,6 +1,7 @@
|
||||
//@ compile-flags: -O -C no-prepopulate-passes
|
||||
//@ 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"]
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
// CHECK-LABEL: @bitmask_int
|
||||
#[no_mangle]
|
||||
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: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
|
||||
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
|
||||
@ -41,7 +41,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 {
|
||||
// CHECK-LABEL: @bitmask_uint
|
||||
#[no_mangle]
|
||||
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: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
|
||||
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
|
||||
@ -51,7 +51,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
|
||||
// CHECK-LABEL: @bitmask_int16
|
||||
#[no_mangle]
|
||||
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: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
|
||||
// CHECK-NOT: zext
|
||||
|
@ -1,6 +1,6 @@
|
||||
//@ compile-flags: -O
|
||||
//@ only-x86_64
|
||||
//@ ignore-debug: debug assertions prevent generating shufflevector
|
||||
//@ ignore-std-debug-assertions (debug assertions prevent generating shufflevector)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
@ -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
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// LLVM 17 realizes double panic is not possible and doesn't generate calls
|
||||
// to panic_cannot_unwind.
|
||||
//@ compile-flags: -O
|
||||
//@ ignore-debug: plain old debug assertions
|
||||
//@ ignore-std-debug-assertions (plain old debug assertions)
|
||||
//@ needs-unwind
|
||||
#![crate_type = "lib"]
|
||||
#![feature(shrink_to)]
|
||||
|
@ -1,5 +1,5 @@
|
||||
//@ compile-flags: -O
|
||||
//@ ignore-debug
|
||||
//@ ignore-std-debug-assertions
|
||||
// (with debug assertions turned on, `assert_unchecked` generates a real assertion)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
//@ compile-flags: -O
|
||||
//@ 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"]
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic.
|
||||
|
||||
//@ compile-flags: -O
|
||||
//@ ignore-debug: plain old debug assertions
|
||||
//@ ignore-std-debug-assertions (plain old debug assertions)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// skip-filecheck
|
||||
//@ 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
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
// skip-filecheck
|
||||
//@ 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
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
@ -1,7 +1,7 @@
|
||||
// skip-filecheck
|
||||
//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
|
||||
//@ 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
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
149
tests/ui-fulldeps/stable-mir/check_crate_defs.rs
Normal file
149
tests/ui-fulldeps/stable-mir/check_crate_defs.rs
Normal 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(())
|
||||
}
|
@ -11,12 +11,12 @@ LL | *ptr = 0;
|
||||
| ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required
|
||||
|
||||
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: 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`
|
||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
note: inside `MISALIGNED_COPY`
|
||||
|
@ -27,7 +27,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
= help: the trait `FnOnce()` is not implemented for `{integer}`
|
||||
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
|
||||
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}`
|
||||
--> $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}`
|
||||
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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) -> _`
|
||||
found function signature `fn(i32) -> _`
|
||||
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
|
||||
|
|
||||
LL | const_eval_select((true,), |arg0: bool| foo(/* i32 */), baz);
|
||||
|
@ -9,7 +9,7 @@
|
||||
//! padding and overall computed sizes can be quite different.
|
||||
//!
|
||||
//@ 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
|
||||
//@ ignore-pass
|
||||
// ^-- needed because `--pass check` does not emit the output needed.
|
||||
|
13
tests/ui/statics/static-mut-shared-parens.rs
Normal file
13
tests/ui/statics/static-mut-shared-parens.rs
Normal 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
|
||||
}
|
29
tests/ui/statics/static-mut-shared-parens.stderr
Normal file
29
tests/ui/statics/static-mut-shared-parens.stderr
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user