From b2fd8a0192f6a69a4fb969ab3d005b577a524371 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 19 Sep 2024 15:00:30 -0700 Subject: [PATCH 01/10] Test fixing raw-dylib --- compiler/rustc_codegen_gcc/src/archive.rs | 3 +- compiler/rustc_codegen_llvm/src/callee.rs | 25 +++++--- compiler/rustc_codegen_llvm/src/consts.rs | 10 +-- .../rustc_codegen_ssa/src/back/archive.rs | 63 +++++++++++-------- compiler/rustc_codegen_ssa/src/back/link.rs | 35 ++++++++--- compiler/rustc_codegen_ssa/src/common.rs | 9 ++- compiler/rustc_session/src/cstore.rs | 5 ++ 7 files changed, 95 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 0cee05f1cea38..82e98370b376b 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -2,6 +2,7 @@ use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, + ImportLibraryItem, }; use rustc_session::Session; @@ -16,7 +17,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { &self, _sess: &Session, _lib_name: &str, - _import_name_and_ordinal_vector: Vec<(String, Option)>, + _items: Vec, _output_path: &Path, ) { unimplemented!("creating dll imports is not yet supported"); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 949fd1bc124f5..db4e1bae94229 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -49,6 +49,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 @@ -60,15 +76,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); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c3b1676f77e75..dc86ef22e37da 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -196,16 +196,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( 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 diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index a665f5c93060d..eb714853a4a0a 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -26,6 +26,35 @@ use crate::errors::{ 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, + /// The original, decorated name if `name` is not decorated. + pub symbol_name: Option, + /// True if this is a data export, false if it is a function export. + pub is_data: bool, +} + +impl From 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; @@ -38,7 +67,7 @@ pub trait ArchiveBuilderBuilder { &self, sess: &Session, lib_name: &str, - import_name_and_ordinal_vector: Vec<(String, Option)>, + items: Vec, output_path: &Path, ) { if common::is_mingw_gnu_toolchain(&sess.target) { @@ -47,21 +76,16 @@ pub trait ArchiveBuilderBuilder { // 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::>() .join(", "), ); @@ -79,20 +103,7 @@ pub trait ArchiveBuilderBuilder { .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::>(); + let exports = items.into_iter().map(Into::into).collect::>(); let machine = match &*sess.target.arch { "x86_64" => MachineTypes::AMD64, "x86" => MachineTypes::I386, @@ -160,16 +171,16 @@ pub trait ArchiveBuilderBuilder { fn create_mingw_dll_import_lib( sess: &Session, lib_name: &str, - import_name_and_ordinal_vector: Vec<(String, Option)>, + items: Vec, 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, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8b855bd0dd568..5fd6a2553ee45 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -45,7 +45,7 @@ use rustc_target::spec::{ 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::{create_wrapper_file, MetadataPosition}; @@ -498,16 +498,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)> = raw_dylib_imports + let items: Vec = 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(); @@ -515,7 +534,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, ); diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 582a2a87e4867..965bd34ac147b 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -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), }; diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index da7a82fee94d0..16432095acc2f 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -130,6 +130,11 @@ impl DllImport { 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. From 0ed6c46961fa28d611c63a9ab32c833ae0d7fa5d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 22 Oct 2024 17:59:26 +0000 Subject: [PATCH 02/10] Robustify and genericize RTN resolution in RBV --- .../src/collect/resolve_bound_vars.rs | 118 +++++++++++++----- compiler/rustc_hir_analysis/src/lib.rs | 2 + .../all-generics-lookup.rs | 31 +++++ 3 files changed, 119 insertions(+), 32 deletions(-) create mode 100644 tests/ui/associated-type-bounds/all-generics-lookup.rs diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index cb7f0901c7e4a..7e1fc020b4572 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1891,45 +1891,30 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; match path.res { Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => { - // Get the generics of this type's hir owner. This is *different* - // from the generics of the parameter's definition, since we want - // to be able to resolve an RTN path on a nested body (e.g. method - // inside an impl) using the where clauses on the method. - // FIXME(return_type_notation): Think of some better way of doing this. - let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics() - else { - return; - }; - - // Look for the first bound that contains an associated type that - // matches the segment that we're looking for. We ignore any subsequent - // bounds since we'll be emitting a hard error in HIR lowering, so this - // is purely speculative. - let one_bound = generics.predicates.iter().find_map(|predicate| { - let hir::WherePredicate::BoundPredicate(predicate) = predicate else { - return None; - }; - let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = - predicate.bounded_ty.kind - else { - return None; - }; - if bounded_path.res != path.res { - return None; - } - predicate.bounds.iter().find_map(|bound| { - let hir::GenericBound::Trait(trait_) = bound else { - return None; - }; + let mut bounds = + self.for_each_in_scope_predicate(path.res).filter_map(|trait_| { BoundVarContext::supertrait_hrtb_vars( self.tcx, trait_.trait_ref.trait_def_id()?, item_segment.ident, ty::AssocKind::Fn, ) - }) - }); + }); + + let one_bound = bounds.next(); + let second_bound = bounds.next(); + + if second_bound.is_some() { + self.tcx + .dcx() + .span_delayed_bug(path.span, "ambiguous resolution for RTN path"); + return; + } + let Some((bound_vars, assoc_item)) = one_bound else { + self.tcx + .dcx() + .span_delayed_bug(path.span, "no resolution for RTN path"); return; }; (bound_vars, assoc_item.def_id, item_segment) @@ -2001,6 +1986,75 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { existing_bound_vars.extend(bound_vars); self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); } + + /// Walk the generics of the item for a trait-ref whose self type + /// corresponds to the expected res. + fn for_each_in_scope_predicate( + &self, + expected_res: Res, + ) -> impl Iterator> + use<'tcx, '_> { + std::iter::from_coroutine( + #[coroutine] + move || { + let mut next_scope = Some(self.scope); + while let Some(current_scope) = next_scope { + next_scope = None; + let hir_id = match *current_scope { + Scope::Binder { s, hir_id, .. } => { + next_scope = Some(s); + hir_id + } + Scope::Body { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s } + | Scope::LateBoundary { s, .. } => { + next_scope = Some(s); + continue; + } + Scope::Root { opt_parent_item } => { + if let Some(parent_id) = opt_parent_item { + self.tcx.local_def_id_to_hir_id(parent_id) + } else { + continue; + } + } + }; + let node = self.tcx.hir_node(hir_id); + if let Some(generics) = node.generics() { + for pred in generics.predicates { + let hir::WherePredicate::BoundPredicate(pred) = pred else { + continue; + }; + let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = + pred.bounded_ty.kind + else { + continue; + }; + // Match the expected res. + if bounded_path.res != expected_res { + continue; + } + yield pred.bounds; + } + } + // Also consider supertraits for `Self` res... + if let Res::SelfTyParam { trait_: _ } = expected_res + && let hir::Node::Item(item) = node + && let hir::ItemKind::Trait(_, _, _, supertraits, _) = item.kind + { + yield supertraits; + } + } + }, + ) + .flatten() + .filter_map(|pred| match pred { + hir::GenericBound::Trait(poly_trait_ref) => Some(poly_trait_ref), + hir::GenericBound::Outlives(_) | hir::GenericBound::Use(_, _) => None, + }) + .fuse() + } } /// Detects late-bound lifetimes and inserts them into diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 71ee77f8f6172..3d73e45f53436 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -62,7 +62,9 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] +#![feature(coroutines)] #![feature(if_let_guard)] +#![feature(iter_from_coroutine)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] diff --git a/tests/ui/associated-type-bounds/all-generics-lookup.rs b/tests/ui/associated-type-bounds/all-generics-lookup.rs new file mode 100644 index 0000000000000..c5940c14f440c --- /dev/null +++ b/tests/ui/associated-type-bounds/all-generics-lookup.rs @@ -0,0 +1,31 @@ +//@ check-pass + +#![feature(return_type_notation)] + +trait Trait { + fn method(&self) -> impl Sized; +} + +impl Trait for () { + fn method(&self) -> impl Sized {} +} + +struct Struct(T); + +// This test used to fail a debug assertion since we weren't resolving the item +// for `T::method(..)` correctly, leading to two bound vars being given the +// index 0. The solution is to look at both generics of `test` and its parent impl. + +impl Struct +where + T: Trait, +{ + fn test() + where + T::method(..): Send + {} +} + +fn main() { + Struct::<()>::test(); +} From cc0ec046b1f7a1b708454cf8d6e33fceee44420d Mon Sep 17 00:00:00 2001 From: Greg Echelberger Date: Thu, 24 Oct 2024 03:32:23 +0000 Subject: [PATCH 03/10] Fix #131977 parens mangled in shared mut static lint suggestion --- compiler/rustc_lint/src/static_mut_refs.rs | 27 ++++++++++++----- tests/ui/statics/static-mut-shared-parens.rs | 13 +++++++++ .../statics/static-mut-shared-parens.stderr | 29 +++++++++++++++++++ 3 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 tests/ui/statics/static-mut-shared-parens.rs create mode 100644 tests/ui/statics/static-mut-shared-parens.stderr diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 5d78b41944fef..fed5c29284b3f 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -3,8 +3,8 @@ use rustc_hir::{Expr, Stmt}; 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 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { 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) diff --git a/tests/ui/statics/static-mut-shared-parens.rs b/tests/ui/statics/static-mut-shared-parens.rs new file mode 100644 index 0000000000000..8e58152e27acd --- /dev/null +++ b/tests/ui/statics/static-mut-shared-parens.rs @@ -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 +} diff --git a/tests/ui/statics/static-mut-shared-parens.stderr b/tests/ui/statics/static-mut-shared-parens.stderr new file mode 100644 index 0000000000000..aa7a760ded875 --- /dev/null +++ b/tests/ui/statics/static-mut-shared-parens.stderr @@ -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 + = 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 + = 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 + From 65b986b94dbeb179338716203f85d811aae6ece1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:13:13 +0800 Subject: [PATCH 04/10] compiletest: add `{ignore,needs}-{rustc,std}-debug-assertions` directive support And retire the old `only-debug` directive which was ambiguous and only for std debug assertions. --- src/tools/compiletest/src/common.rs | 7 +++- src/tools/compiletest/src/directive-list.rs | 5 ++- src/tools/compiletest/src/header/cfg.rs | 11 ++++-- src/tools/compiletest/src/header/needs.rs | 10 +++++ src/tools/compiletest/src/header/tests.rs | 44 +++++++++++++++++++++ src/tools/compiletest/src/lib.rs | 9 +++-- 6 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index e82b88eef7985..070a014afa888 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -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, diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 4d57907f26f92..b7a171e02b5bc 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -45,7 +45,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-coverage-map", "ignore-coverage-run", "ignore-cross-compile", - "ignore-debug", "ignore-eabi", "ignore-emscripten", "ignore-endian-big", @@ -81,6 +80,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-powerpc", "ignore-remote", "ignore-riscv64", + "ignore-rustc-debug-assertions", "ignore-s390x", "ignore-sgx", "ignore-sparc64", @@ -88,6 +88,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-stable", "ignore-stage1", "ignore-stage2", + "ignore-std-debug-assertions", "ignore-test", "ignore-thumb", "ignore-thumbv8m.base-none-eabi", @@ -134,6 +135,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-relocation-model-pic", "needs-run-enabled", "needs-rust-lld", + "needs-rustc-debug-assertions", "needs-sanitizer-address", "needs-sanitizer-cfi", "needs-sanitizer-dataflow", @@ -146,6 +148,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-shadow-call-stack", "needs-sanitizer-support", "needs-sanitizer-thread", + "needs-std-debug-assertions", "needs-symlink", "needs-threads", "needs-unwind", diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index b9314f0abbbc8..3ab552903dc6b 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -202,9 +202,14 @@ pub(super) fn parse_cfg_name_directive<'a>( 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()), diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index a744fb61b9cfc..77570c58db5cf 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -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([':', ' ']) { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 2e6effcab9868..4b35bbee08b9f 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -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 @@ impl ConfigBuilder { 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", @@ -169,6 +181,12 @@ impl ConfigBuilder { 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 @@ -313,6 +331,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(); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index ccf8057bf5c57..d171bf67a445f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -88,7 +88,8 @@ pub fn parse_config(args: Vec) -> 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", @@ -234,7 +235,8 @@ pub fn parse_config(args: Vec) -> Config { 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") @@ -292,7 +294,8 @@ pub fn parse_config(args: Vec) -> Config { 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"), From 3870022986d62233ee83928dcba6040a7a1c9a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:53:52 +0800 Subject: [PATCH 05/10] bootstrap: pass `--with-{rustc,std}-debug-assertions` to compiletest And rename local variables and field names in bootstrap from `debug_assertions{,_std}` -> `{rustc,std}-debug-assertions` to avoid confusion where applicable. --- src/bootstrap/src/core/build_steps/test.rs | 10 +++++-- src/bootstrap/src/core/builder/cargo.rs | 4 +-- src/bootstrap/src/core/config/config.rs | 33 +++++++++++----------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 2ad1b39a87c83..4aced4f1e3211 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1933,9 +1933,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the 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; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index c3d0994f16410..134da5db96d06 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -833,9 +833,9 @@ impl Builder<'_> { 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( diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 8115aea033d93..f977c285a74c1 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -263,8 +263,10 @@ pub struct Config { pub rust_optimize: RustOptimize, pub rust_codegen_units: Option, pub rust_codegen_units_std: Option, - 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 @@ define_config! { debug: Option = "debug", codegen_units: Option = "codegen-units", codegen_units_std: Option = "codegen-units-std", - debug_assertions: Option = "debug-assertions", + rustc_debug_assertions: Option = "debug-assertions", randomize_layout: Option = "randomize-layout", - debug_assertions_std: Option = "debug-assertions-std", + std_debug_assertions: Option = "debug-assertions-std", overflow_checks: Option = "overflow-checks", overflow_checks_std: Option = "overflow-checks-std", debug_logging: Option = "debug-logging", @@ -1652,8 +1654,8 @@ impl Config { 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 @@ impl Config { 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 @@ impl Config { 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 @@ impl Config { 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 @@ fn check_incompatible_options_for_ci_rustc( debug: _, codegen_units: _, codegen_units_std: _, - debug_assertions: _, - debug_assertions_std: _, + rustc_debug_assertions: _, + std_debug_assertions: _, overflow_checks: _, overflow_checks_std: _, debuginfo_level: _, From 0d5cc8ee96c0bf7fa041727891839da4ac57c042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:20:40 +0800 Subject: [PATCH 06/10] tests: `ignore-debug` -> `ignore-std-debug-assertions` --- tests/codegen/binary-heap-peek-mut-pop-no-panic.rs | 2 +- tests/codegen/mem-replace-big-type.rs | 3 ++- tests/codegen/mem-replace-simple-type.rs | 3 ++- tests/codegen/slice-reverse.rs | 2 +- tests/codegen/vec-in-place.rs | 2 +- tests/codegen/vec-shrink-panik.rs | 2 +- tests/codegen/vec-with-capacity.rs | 2 +- tests/codegen/vecdeque-drain.rs | 2 +- tests/codegen/vecdeque_no_panic.rs | 2 +- tests/mir-opt/pre-codegen/mem_replace.rs | 3 ++- tests/mir-opt/pre-codegen/ptr_offset.rs | 2 +- tests/mir-opt/pre-codegen/slice_iter.rs | 2 +- tests/ui/print_type_sizes/niche-filling.rs | 2 +- 13 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs index 9cf4f210e527a..e3bc9a4761cfd 100644 --- a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs +++ b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs @@ -1,5 +1,5 @@ //@ compile-flags: -O -//@ ignore-debug +//@ ignore-std-debug-assertions #![crate_type = "lib"] use std::collections::binary_heap::PeekMut; diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index e62f1a953dfd0..e62adfa0ba664 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -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"] diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs index 7209fa21925ad..41c3660dc15c0 100644 --- a/tests/codegen/mem-replace-simple-type.rs +++ b/tests/codegen/mem-replace-simple-type.rs @@ -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"] diff --git a/tests/codegen/slice-reverse.rs b/tests/codegen/slice-reverse.rs index 21add929f051f..87cdad479628a 100644 --- a/tests/codegen/slice-reverse.rs +++ b/tests/codegen/slice-reverse.rs @@ -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"] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index c6b77363a4e50..5d05f242617fb 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -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"] diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index 4b798fe6c9cba..873904c2569e4 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -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)] diff --git a/tests/codegen/vec-with-capacity.rs b/tests/codegen/vec-with-capacity.rs index 47051f2eef891..e8c5bc88bd0db 100644 --- a/tests/codegen/vec-with-capacity.rs +++ b/tests/codegen/vec-with-capacity.rs @@ -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"] diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs index fca1ed367e6fc..8a34ba0674b1b 100644 --- a/tests/codegen/vecdeque-drain.rs +++ b/tests/codegen/vecdeque-drain.rs @@ -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"] diff --git a/tests/codegen/vecdeque_no_panic.rs b/tests/codegen/vecdeque_no_panic.rs index be2c4810ebc44..da948d12254cd 100644 --- a/tests/codegen/vecdeque_no_panic.rs +++ b/tests/codegen/vecdeque_no_panic.rs @@ -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"] diff --git a/tests/mir-opt/pre-codegen/mem_replace.rs b/tests/mir-opt/pre-codegen/mem_replace.rs index a68fe31f6094d..be23dcdb22ae5 100644 --- a/tests/mir-opt/pre-codegen/mem_replace.rs +++ b/tests/mir-opt/pre-codegen/mem_replace.rs @@ -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"] diff --git a/tests/mir-opt/pre-codegen/ptr_offset.rs b/tests/mir-opt/pre-codegen/ptr_offset.rs index 88ee00296a078..120be99fc94af 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.rs +++ b/tests/mir-opt/pre-codegen/ptr_offset.rs @@ -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"] diff --git a/tests/mir-opt/pre-codegen/slice_iter.rs b/tests/mir-opt/pre-codegen/slice_iter.rs index fee4214982d59..46ded729852ab 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.rs +++ b/tests/mir-opt/pre-codegen/slice_iter.rs @@ -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"] diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index 5dda0da845825..36739e3fc04c5 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -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. From 072088074e81e8bd945ba7bb26b8ec970ce17172 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 6 Nov 2024 13:41:55 +0100 Subject: [PATCH 07/10] Separate f128 `%` operation to deal with missing `fmodl` symbol --- library/std/src/f128/tests.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs index 7051c051bf723..cbcf9f96239bb 100644 --- a/library/std/src/f128/tests.rs +++ b/library/std/src/f128/tests.rs @@ -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] From 9f5e17fd0a6dcab130a39f5ef76998bcb2cf9073 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 7 Nov 2024 17:13:00 +0100 Subject: [PATCH 08/10] Fix file formatting --- src/librustdoc/scrape_examples.rs | 33 ++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 3134d25e54403..980a9f7a47cd3 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -42,10 +42,16 @@ impl ScrapeExamplesOptions { 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 @@ where }; // 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 @@ where 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 @@ where // 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 @@ where 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() From 0e58f1c21af074bef9b1246ca7264c7d3743bdb9 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 7 Nov 2024 16:48:29 +0100 Subject: [PATCH 09/10] Update test for LLVM 20's new vector splat syntax that was introduced in https://github.com/llvm/llvm-project/pull/112548 --- .../simd-intrinsic/simd-intrinsic-generic-bitmask.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs index 81ac90269b7df..e9112f1f321b1 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -31,7 +31,7 @@ extern "rust-intrinsic" { // CHECK-LABEL: @bitmask_int #[no_mangle] pub unsafe fn bitmask_int(x: i32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|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}}, + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|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}}, + // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, {{|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 From 0ce579f6f3a45ed0bab7f2957ea14683e69412f6 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 25 Oct 2024 01:05:59 -0700 Subject: [PATCH 10/10] [StableMIR] API to retrieve definitions from crates Add functions to retrieve function definitions and static items from all crates (local and external). For external crates, add a query to retrieve the number of defs in a foreign crate. --- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 10 ++ compiler/rustc_smir/src/rustc_smir/context.rs | 16 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 34 +++- compiler/stable_mir/src/compiler_interface.rs | 6 + compiler/stable_mir/src/lib.rs | 13 +- .../stable-mir/check_crate_defs.rs | 149 ++++++++++++++++++ 7 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 tests/ui-fulldeps/stable-mir/check_crate_defs.rs diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 7bb40996d58f2..81d93ef2a4f27 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -387,6 +387,7 @@ provide! { tcx, def_id, other, cdata, 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() } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f8ba606e087c8..0c56708c95021 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1812,6 +1812,16 @@ rustc_queries! { 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 diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 8fa8f2ac4021e..cfcac5b66b635 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -34,7 +34,7 @@ use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, I 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 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } + fn crate_functions(&self, crate_num: CrateNum) -> Vec { + 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 { + 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, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 9b27b94fb5a56..91aae2ba82c7c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -15,8 +15,8 @@ use rustc_middle::mir::interpret::AllocId; 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 @@ impl<'tcx> Tables<'tcx> { }; !must_override && self.tcx.is_mir_available(def_id) } + + fn to_fn_def(&mut self, def_id: DefId) -> Option { + 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 { + 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(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec +where + F: FnMut(DefId) -> Option, +{ + 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. diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 4b7707ebccfed..a6f7c254583e2 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -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; + + /// Retrieve all functions defined in this crate. + fn crate_functions(&self, crate_num: CrateNum) -> Vec; + + /// Retrieve all static items defined in this crate. + fn crate_statics(&self, crate_num: CrateNum) -> Vec; fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec; fn all_trait_decls(&self) -> TraitDecls; diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index b523e949cde3e..0b4cebadad1d4 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -25,8 +25,9 @@ use serde::Serialize; 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 @@ impl Crate { 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 { + 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 { + with(|cx| cx.crate_statics(self.id)) + } } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs new file mode 100644 index 0000000000000..e039ca07dd4ad --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -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", + "::drop", + "DummyTrait::method", + "::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::::is_some", + "std::ptr::swap", + " as std::iter::Iterator>::next", + "core::num::::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(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(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 DummyTrait for T {{ + fn method(&self) -> T {{ + *self + }} + }} + + pub mod dummy {{ + pub static mut PUBLIC_STATIC: Option = 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(()) +}