diff --git a/Cargo.lock b/Cargo.lock index 7cb05bce70ec4..2c9dc442663f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4430,6 +4430,7 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_ast_ir", + "rustc_attr_ir", "rustc_crate_store", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_attr_ir/src/lib.rs b/compiler/rustc_attr_ir/src/lib.rs index 588bcfafb208d..0b142ca92df6b 100644 --- a/compiler/rustc_attr_ir/src/lib.rs +++ b/compiler/rustc_attr_ir/src/lib.rs @@ -1,7 +1,7 @@ //! Data structures for representing parsed attributes in the Rust compiler. //! //! For detailed documentation about attribute processing, -//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html). +//! see [rustc_attr_parsing](../rustc_attr_parsing/index.html). // tidy-alphabetical-start #![feature(const_default)] @@ -20,7 +20,6 @@ pub use lang_items::*; pub use pretty_printing::PrintAttribute; pub use stability::*; -// FIXME remove pub on some of these modules? It's fairly inconsistent. mod attr; mod canonical_symbols; mod data_structures; @@ -35,40 +34,38 @@ pub mod weak_lang_items; /// A trait for types that can provide a list of attributes given a `TyCtxt`. /// -/// It allows `find_attr!` to accept either a `DefId`, `LocalDefId`, `OwnerId`, or `HirId`. -/// It is defined here with a generic `Tcx` because `rustc_hir` can't depend on `rustc_middle`. -/// The concrete implementations are in `rustc_middle`. +/// It is an implementation detail of the [`find_attr!`] macro to be able to accept either a +/// [`DefId`], [`LocalDefId`], [`OwnerId`], or [`HirId`]. It is defined here with a generic `Tcx` +/// because this crate can't depend on `rustc_middle`. The concrete implementations are in +/// `rustc_middle`. +/// +/// Not to be confused with [`rustc_ast::ast_traits::HasAttrs`]. +/// +/// [`DefId`]: rustc_span::def_id::DefId +/// [`LocalDefId`]: rustc_span::def_id::LocalDefId +/// [`OwnerId`]: ../rustc_hir/struct.OwnerId.html +/// [`HirId`]: ../rustc_hir/struct.HirId.html pub trait HasAttrs<'tcx, Tcx> { - fn get_attrs(self, tcx: &Tcx) -> &'tcx [crate::attr::Attribute]; + fn get_attrs(self, tcx: &Tcx) -> &'tcx [crate::Attribute]; } -/// Finds attributes in sequences of attributes by pattern matching. +/// Finds attributes by pattern matching. /// /// A little like `matches` but for attributes. /// -/// ```rust,ignore (illustrative) -/// // finds the repr attribute -/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { -/// -/// } -/// -/// // checks if one has matched -/// if find_attr!(attrs, AttributeKind::Repr(_)) { -/// -/// } -/// ``` +/// Note that this macro accepts several "id" types: [`DefId`], [`LocalDefId`], [`OwnerId`] and +/// [`HirId`]. /// -/// Often this requires you to first end up with a list of attributes. -/// Often these are available through the `tcx`. +/// # Examples /// -/// As a convenience, this macro can do that for you! +/// It is most commonly used to check whether something has an attribute or to get its contents +/// if it is present: +/// ```rust,ignore (illustrative) +/// let is_naked: bool = find_attr!(tcx, def_id, Naked(..)); /// -/// Instead of providing an attribute list, provide the `tcx` and an id -/// (a `DefId`, `LocalDefId`, `OwnerId` or `HirId`). +/// let is_visible: bool = find_attr!(tcx, def_id, Doc(doc) if doc.hidden.is_none()); /// -/// ```rust,ignore (illustrative) -/// find_attr!(tcx, def_id, ) -/// find_attr!(tcx, hir_id, ) +/// let link_name: Option = find_attr!(tcx, def_id, LinkName { name, .. } => *name); /// ``` /// /// Another common case is finding attributes applied to the root of the current crate. @@ -77,6 +74,27 @@ pub trait HasAttrs<'tcx, Tcx> { /// ```rust, ignore (illustrative) /// find_attr!(tcx, crate, ) /// ``` +/// +/// If you already have a list of attributes in scope, you can also use that: +/// +/// ```rust,ignore (illustrative) +/// let attrs = ; +/// +/// // finds the repr attribute +/// if let Some(r) = find_attr!(attrs, Repr(r) => r) { +/// +/// } +/// +/// // checks if one has matched +/// if find_attr!(attrs, Repr(_)) { +/// +/// } +/// ``` +/// +/// [`DefId`]: rustc_span::def_id::DefId +/// [`LocalDefId`]: rustc_span::def_id::LocalDefId +/// [`OwnerId`]: ../rustc_hir/struct.OwnerId.html +/// [`HirId`]: ../rustc_hir/struct.HirId.html #[macro_export] macro_rules! find_attr { ($tcx: expr, crate, $pattern: pat $(if $guard: expr)?) => { @@ -89,6 +107,7 @@ macro_rules! find_attr { ($tcx: expr, $id: expr, $pattern: pat $(if $guard: expr)?) => { $crate::find_attr!($tcx, $id, $pattern $(if $guard)? => ()).is_some() }; + ($tcx: expr, $id: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ $crate::find_attr!( $crate::HasAttrs::get_attrs($id, &$tcx), @@ -96,7 +115,6 @@ macro_rules! find_attr { ) }}; - ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() }}; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 220d1376ccc6f..53114d0ca9d8a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -361,7 +361,7 @@ fn parse_directive_items<'p>( WrappedParserError { description: e.description, label: e.label, - span: slice_span(input.span, e.span.clone(), is_snippet), + span: slice_span(input.span, e.span, is_snippet), }, input.span, ); diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 38077109b7811..74653139fec02 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -40,7 +40,7 @@ pub(crate) fn expand_option_env<'cx>( Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; let ExpandResult::Ready(mac) = - expr_to_string(cx, var_expr.clone(), "argument must be a string literal") + expr_to_string(cx, var_expr, "argument must be a string literal") else { return ExpandResult::Retry(()); }; diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index d9304a978ccd4..b75131db68207 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -134,9 +134,9 @@ pub(crate) fn expand_kernel( // host function let mut host_fn = Box::new(ast::Fn { defaultness: ast::Defaultness::Implicit, - sig: sig.clone(), + sig, ident, - generics: generics.clone(), + generics, contract: None, body: Some(body), define_opaque: None, @@ -176,7 +176,7 @@ pub(crate) fn expand_kernel( thin_vec![rustc_offload_kernel, inline_never], ast::ItemKind::Fn(host_fn), ); - item.vis = vis.clone(); + item.vis = vis; Annotatable::Item(item) }; diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 9763b0c0fa867..ecf7c4f9b30c9 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -30,6 +30,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span], + _target_features: &[String], ) { codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options); } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index a485261cc6c23..68b30a85324cd 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -929,6 +929,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, line_spans: &[Span], + _target_features: &[String], ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 6099e25df4b3e..5d01e51cc6d6a 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -414,6 +414,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span], + target_features: &[String], ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); @@ -499,14 +500,11 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { template_str.push_str("\n.att_syntax\n"); } - let target_features = self.tcx.global_backend_features(()).join(","); - let target_cpu = llvm_util::target_cpu(self.tcx.sess); - llvm::append_module_inline_asm( self.llmod, template_str.as_bytes(), - &target_features, - target_cpu, + &target_features.join(","), + llvm_util::target_cpu(self.tcx.sess), ); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 05d3bd0b08b95..684bba7a717db 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -894,6 +894,8 @@ unsafe extern "C" { SLen: c_uint, ) -> MetadataKindId; + pub(crate) fn LLVMGetVersion(major: &mut c_uint, minor: &mut c_uint, patch: &mut c_uint); + pub(crate) fn LLVMDisposeTargetMachine(T: ptr::NonNull); // Create modules. diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 298b58dd0007f..9819699ca5228 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -48,6 +48,31 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); + // Check to ensure we're running against the correct LLVM version. + unsafe { + let mut llvm_major = 0; + let mut llvm_minor = 0; + let mut llvm_patch = 0; + llvm::LLVMGetVersion(&mut llvm_major, &mut llvm_minor, &mut llvm_patch); + let expected_version = llvm::LLVMRustVersionMajor(); + if llvm_major != expected_version { + panic!( + concat!( + "LLVM version mismatch: this compiler was built for LLVM {}, ", + "but LLVM {}.{}.{} was found{}" + ), + expected_version, + llvm_major, + llvm_minor, + llvm_patch, + match rustc_session::filesearch::dll_path(llvm::LLVMGetVersion as *mut _) { + Ok(path) => format!(" at {}", path.display()), + Err(_) => String::new(), + } + ); + } + } + unsafe { llvm::LLVMRustInstallErrorHandlers(); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 9eb4fd510fd7f..d66dec54237dd 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -490,7 +490,14 @@ where }) .collect(); - cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans); + let target_features = cx.tcx().global_backend_features(()); + cx.codegen_global_asm( + asm.template, + &operands, + asm.options, + asm.line_spans, + &target_features, + ); } else { span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") } diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 05b87bb6d7159..b3ea2409762fb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -54,7 +54,9 @@ pub fn codegen_naked_asm< template_vec.extend(template.iter().cloned()); template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into())); - cx.codegen_global_asm(&template_vec, &operands, options, line_spans); + let target_features: Vec<_> = + cx.tcx().asm_target_features(instance.def_id()).iter().map(|s| format!("+{s}")).collect(); + cx.codegen_global_asm(&template_vec, &operands, options, line_spans, &target_features); } fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>>( diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 85a2fe09ba414..554e7efaf7c3a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -72,6 +72,7 @@ pub trait AsmCodegenMethods<'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, line_spans: &[Span], + target_features: &[String], ); /// The mangled name of this instance diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index b26969a830f11..361aa2583fd2b 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -15,6 +15,7 @@ rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_attr_ir = { path = "../rustc_attr_ir" } rustc_crate_store = { path = "../rustc_crate_store" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index f4f3cda4f94a1..5794a6533bd1d 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -53,6 +53,8 @@ use rustc_arena::TypedArena; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::tokenstream::TokenStream; +use rustc_attr_ir::lang_items::{LangItem, LanguageItems}; +use rustc_attr_ir::{CanonicalSymbols, EiiDecl, EiiImpl, StrippedCfgItem}; use rustc_crate_store::{ CrateDepKind, CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib, }; @@ -63,8 +65,6 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{ErrorGuaranteed, catch_fatal_errors}; use rustc_hir as hir; -use rustc_hir::attrs::lang_items::{LangItem, LanguageItems}; -use rustc_hir::attrs::{CanonicalSymbols, EiiDecl, EiiImpl, StrippedCfgItem}; use rustc_hir::def::{DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdSet, LocalModId}; use rustc_hir::{ItemLocalId, PreciseCapturingArgKind}; @@ -1524,8 +1524,12 @@ rustc_queries! { /// Returns the attributes on the item at `def_id`. /// - /// Do not use this directly, use `tcx.get_attrs` instead. - query attrs_for_def(def_id: DefId) -> &'tcx [hir::Attribute] { + ///
+ /// + /// Do not use this directly, use [`rustc_attr_ir::find_attr`] instead. + /// + ///
+ query attrs_for_def(def_id: DefId) -> &'tcx [rustc_attr_ir::Attribute] { desc { "collecting attributes of `{}`", tcx.def_path_str(def_id) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ddaa01640b64b..0ced7d1ea2bc5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -31,18 +31,18 @@ use rustc_abi::{ use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, NodeId}; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; +use rustc_attr_ir::lang_items::LangItem; +use rustc_attr_ir::{self as attr, StrippedCfgItem, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Diag, ErrorGuaranteed, LintBuffer}; -use rustc_hir::attrs::StrippedCfgItem; -use rustc_hir::attrs::lang_items::LangItem; +use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::PerParentDisambiguatorState; -use rustc_hir::{self as hir, MissingLifetimeKind, attrs as attr, find_attr}; use rustc_index::bit_set::BitMatrix; use rustc_index::{IndexVec, static_assert_size}; pub use rustc_lint_defs::RegisteredTools; @@ -221,7 +221,7 @@ pub struct PerOwnerResolverData<'tcx> { /// Resolution for import nodes, which have multiple resolutions in different namespaces. pub import_res: hir::def::PerNS>> = Default::default(), /// Lifetime parameters that lowering will have to introduce. - pub extra_lifetime_params_map: NodeMap> = Default::default(), + pub extra_lifetime_params_map: NodeMap> = Default::default(), /// The id of the owner pub id: ast::NodeId, @@ -251,7 +251,10 @@ impl<'tcx> PerOwnerResolverData<'tcx> { /// /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring /// should appear at the enclosing `PolyTraitRef`. - pub fn extra_lifetime_params(&self, id: NodeId) -> &[(Ident, NodeId, MissingLifetimeKind)] { + pub fn extra_lifetime_params( + &self, + id: NodeId, + ) -> &[(Ident, NodeId, hir::MissingLifetimeKind)] { self.extra_lifetime_params_map.get(&id).map_or(&[], |v| &v[..]) } } @@ -2008,17 +2011,22 @@ impl<'tcx> TyCtxt<'tcx> { self, did: impl Into, attr: Symbol, - ) -> impl Iterator { + ) -> impl Iterator { #[expect(deprecated)] - self.get_all_attrs(did).iter().filter(move |a: &&hir::Attribute| a.has_name(attr)) + self.get_all_attrs(did).iter().filter(move |a: &&rustc_attr_ir::Attribute| a.has_name(attr)) } /// Gets all attributes. /// + ///
+ /// /// To see if an item has a specific attribute, you should use - /// [`rustc_hir::find_attr!`] so you can use matching. + /// [`rustc_attr_ir::find_attr!`] so you can use matching. + /// + ///
+ /// #[deprecated = "Though there are valid usecases for this method, especially when your attribute is not a parsed attribute, usually you want to call rustc_hir::find_attr! instead."] - pub fn get_all_attrs(self, did: impl Into) -> &'tcx [hir::Attribute] { + pub fn get_all_attrs(self, did: impl Into) -> &'tcx [rustc_attr_ir::Attribute] { let did: DefId = did.into(); if let Some(did) = did.as_local() { self.hir_attrs(self.local_def_id_to_hir_id(did)) @@ -2031,8 +2039,8 @@ impl<'tcx> TyCtxt<'tcx> { self, did: DefId, attr: &[Symbol], - ) -> impl Iterator { - let filter_fn = move |a: &&hir::Attribute| a.path_matches(attr); + ) -> impl Iterator { + let filter_fn = move |a: &&rustc_attr_ir::Attribute| a.path_matches(attr); if let Some(did) = did.as_local() { self.hir_attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) } else { @@ -2474,8 +2482,8 @@ impl<'tcx> TyCtxt<'tcx> { // `HasAttrs` impls: allow `find_attr!(tcx, id, ...)` to work with both DefId-like types and HirId. -impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for DefId { - fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { +impl<'tcx> rustc_attr_ir::HasAttrs<'tcx, TyCtxt<'tcx>> for DefId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [rustc_attr_ir::Attribute] { if let Some(did) = self.as_local() { tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)) } else { @@ -2484,20 +2492,20 @@ impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for DefId { } } -impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for LocalDefId { - fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { +impl<'tcx> rustc_attr_ir::HasAttrs<'tcx, TyCtxt<'tcx>> for LocalDefId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [rustc_attr_ir::Attribute] { tcx.hir_attrs(tcx.local_def_id_to_hir_id(self)) } } -impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for hir::OwnerId { - fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { - hir::attrs::HasAttrs::get_attrs(self.def_id, tcx) +impl<'tcx> rustc_attr_ir::HasAttrs<'tcx, TyCtxt<'tcx>> for hir::OwnerId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [rustc_attr_ir::Attribute] { + rustc_attr_ir::HasAttrs::get_attrs(self.def_id, tcx) } } -impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for hir::HirId { - fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { +impl<'tcx> rustc_attr_ir::HasAttrs<'tcx, TyCtxt<'tcx>> for hir::HirId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [rustc_attr_ir::Attribute] { tcx.hir_attrs(self) } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0046ccdba6ec4..f5f40a641b66e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -4273,7 +4273,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // we identified that the return expression references only one argument, we // would suggest borrowing only that argument, and we'd skip the prior // "use `'static`" suggestion entirely. - let mut lifetime_refs = lifetime_refs.clone().into_iter(); + let mut lifetime_refs = lifetime_refs.into_iter(); if let Some(lt) = lifetime_refs.next() && lifetime_refs.next().is_none() && (lt.kind == MissingLifetimeKind::Ampersand diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index d88fed2f84ab8..6ec1466500a86 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -146,86 +146,78 @@ pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf { sysroot.join(rustlib_path).join("bin") } +/// Attempts to find the path to the dynamic library containing a function. +/// +/// SAFETY: `function` must be a valid pointer to some function. #[cfg(unix)] -fn current_dll_path() -> Result { - use std::sync::OnceLock; +pub unsafe fn dll_path(function: *mut std::ffi::c_void) -> Result { + use std::ffi::{CStr, OsStr}; + use std::os::unix::prelude::*; - // This is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr` - // needs to iterate over the symbol table of librustc_driver.so until it finds a match. - // As such cache this to avoid recomputing if we try to get the sysroot in multiple places. - static CURRENT_DLL_PATH: OnceLock> = OnceLock::new(); - CURRENT_DLL_PATH - .get_or_init(|| { - use std::ffi::{CStr, OsStr}; - use std::os::unix::prelude::*; - - #[cfg(not(target_os = "aix"))] - unsafe { - let addr = current_dll_path as fn() -> Result as *mut _; - let mut info = std::mem::zeroed(); - if libc::dladdr(addr, &mut info) == 0 { - return Err("dladdr failed".into()); + #[cfg(not(target_os = "aix"))] + unsafe { + let mut info = std::mem::zeroed(); + if libc::dladdr(function, &mut info) == 0 { + return Err("dladdr failed".into()); + } + #[cfg(target_os = "cygwin")] + let fname_ptr = info.dli_fname.as_ptr(); + #[cfg(not(target_os = "cygwin"))] + let fname_ptr = { + assert!(!info.dli_fname.is_null(), "dli_fname cannot be null"); + info.dli_fname + }; + let bytes = CStr::from_ptr(fname_ptr).to_bytes(); + let os = OsStr::from_bytes(bytes); + try_canonicalize(Path::new(os)).map_err(|e| e.to_string()) + } + + #[cfg(target_os = "aix")] + unsafe { + // On AIX, the symbol references a function descriptor. + // A function descriptor is consisted of (See https://reviews.llvm.org/D62532) + // * The address of the entry point of the function. + // * The TOC base address for the function. + // * The environment pointer. + // The function descriptor is in the data section. + let addr = function as u64; + let mut buffer = vec![std::mem::zeroed::(); 64]; + loop { + if libc::loadquery( + libc::L_GETINFO, + buffer.as_mut_ptr() as *mut libc::c_void, + (size_of::() * buffer.len()) as u32, + ) >= 0 + { + break; + } else { + if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM { + return Err("loadquery failed".into()); } - #[cfg(target_os = "cygwin")] - let fname_ptr = info.dli_fname.as_ptr(); - #[cfg(not(target_os = "cygwin"))] - let fname_ptr = { - assert!(!info.dli_fname.is_null(), "dli_fname cannot be null"); - info.dli_fname - }; - let bytes = CStr::from_ptr(fname_ptr).to_bytes(); + buffer.resize(buffer.len() * 2, std::mem::zeroed::()); + } + } + let mut current = buffer.as_mut_ptr() as *mut libc::ld_info; + loop { + let data_base = (*current).ldinfo_dataorg as u64; + let data_end = data_base + (*current).ldinfo_datasize; + if (data_base..data_end).contains(&addr) { + let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes(); let os = OsStr::from_bytes(bytes); - try_canonicalize(Path::new(os)).map_err(|e| e.to_string()) + return try_canonicalize(Path::new(os)).map_err(|e| e.to_string()); } - - #[cfg(target_os = "aix")] - unsafe { - // On AIX, the symbol `current_dll_path` references a function descriptor. - // A function descriptor is consisted of (See https://reviews.llvm.org/D62532) - // * The address of the entry point of the function. - // * The TOC base address for the function. - // * The environment pointer. - // The function descriptor is in the data section. - let addr = current_dll_path as u64; - let mut buffer = vec![std::mem::zeroed::(); 64]; - loop { - if libc::loadquery( - libc::L_GETINFO, - buffer.as_mut_ptr() as *mut libc::c_void, - (size_of::() * buffer.len()) as u32, - ) >= 0 - { - break; - } else { - if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM { - return Err("loadquery failed".into()); - } - buffer.resize(buffer.len() * 2, std::mem::zeroed::()); - } - } - let mut current = buffer.as_mut_ptr() as *mut libc::ld_info; - loop { - let data_base = (*current).ldinfo_dataorg as u64; - let data_end = data_base + (*current).ldinfo_datasize; - if (data_base..data_end).contains(&addr) { - let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes(); - let os = OsStr::from_bytes(bytes); - return try_canonicalize(Path::new(os)).map_err(|e| e.to_string()); - } - if (*current).ldinfo_next == 0 { - break; - } - current = (current as *mut i8).offset((*current).ldinfo_next as isize) - as *mut libc::ld_info; - } - return Err(format!("current dll's address {} is not in the load map", addr)); + if (*current).ldinfo_next == 0 { + break; } - }) - .clone() + current = + (current as *mut i8).offset((*current).ldinfo_next as isize) as *mut libc::ld_info; + } + return Err(format!("current dll's address {} is not in the load map", addr)); + } } #[cfg(windows)] -fn current_dll_path() -> Result { +pub unsafe fn dll_path(function: *mut std::ffi::c_void) -> Result { use std::ffi::OsString; use std::io; use std::os::windows::prelude::*; @@ -240,10 +232,7 @@ fn current_dll_path() -> Result { unsafe { GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - PCWSTR( - current_dll_path as fn() -> Result - as *mut u16, - ), + PCWSTR(function as *mut u16), &mut module, ) } @@ -269,8 +258,20 @@ fn current_dll_path() -> Result { } #[cfg(target_os = "wasi")] +pub unsafe fn dll_path(function: *mut std::ffi::c_void) -> Result { + Err("dll_path is not supported on WASI".to_string()) +} + fn current_dll_path() -> Result { - Err("current_dll_path is not supported on WASI".to_string()) + use std::sync::OnceLock; + + // This is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr` + // needs to iterate over the symbol table of librustc_driver.so until it finds a match. + // As such cache this to avoid recomputing if we try to get the sysroot in multiple places. + static CURRENT_DLL_PATH: OnceLock> = OnceLock::new(); + CURRENT_DLL_PATH + .get_or_init(|| unsafe { dll_path(current_dll_path as fn() -> _ as *mut _) }) + .clone() } /// This function checks if sysroot is found using env::args().next(), and if it diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs index ef5112ad74f13..c23e0afe6c979 100644 --- a/library/std/src/sys/personality/dwarf/eh.rs +++ b/library/std/src/sys/personality/dwarf/eh.rs @@ -48,9 +48,20 @@ pub struct EHContext<'a> { type LPad = *const u8; pub enum EHAction { None, + /// Destructors should be executed when stack unwinds. Cleanup(LPad), + /// Stack unwind should be stopped as the exception is going to be caught by `catch_unwind`. Catch(LPad), + /// Stack unwind should be stopped for termination (`UnwindAction::Terminate`). + /// + /// Note that due to inlining the landing pad can execute destructors before terminating. So + /// this is different from `Terminate`. + /// + /// Handling of this is mostly identical to `Catch`; except that Rust frames that have no + /// destructors but only `UnwindAction::Terminate` is considered as plain-old-frame (POF) and + /// forced unwind is allowed to unwind past it; so this is treated as `None` during forced unwind. Filter(LPad), + /// Process should be terminated as the call site does not permit unwinding. Terminate, } @@ -160,7 +171,19 @@ unsafe fn interpret_cs_action( let action_record = unsafe { action_table.offset(cs_action_entry as isize - 1) }; let mut action_reader = DwarfReader::new(action_record); let ttype_index = unsafe { action_reader.read_sleb128() }; - if ttype_index == 0 { + let next_action = unsafe { action_reader.read_sleb128() }; + if next_action != 0 { + // We observed multiple actions. Action records contain no duplicates (at least that is + // true for both LLVM/GCC), and as Rust does not have exception specification, this + // indicates that we have at least 2 of "cleanup", "catch" and "filter", so we should + // catch all exceptions. + // + // Note that even for the case of "cleanup" + "filter", decoding them as "catch" is + // fine: "filter" behaves identically to "catch" except for forced unwind; in case of + // forced unwind, hitting a "cleanup" landing pad is UB as it indicates that we're + // unwinding past a non-POF Rust frame. + EHAction::Catch(lpad) + } else if ttype_index == 0 { EHAction::Cleanup(lpad) } else if ttype_index > 0 { // Stop unwinding Rust panics at catch_unwind. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f4c96defa7ae6..6fbf632472b2b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -448,21 +448,22 @@ impl Config { // Undo `src/bootstrap` manifest_dir.parent().unwrap().parent().unwrap().to_owned() }; - let src = if let Some(s) = compute_src_directory(flags_src, &exec_ctx) { - s - } else { - default_src_dir.clone() - }; - #[cfg(test)] - { - if let Some(config_path) = flags_config.as_ref() { - assert!( + // Determine the root of the `rust-lang/rust` source directory from one of: + // - An explicit command-line argument `--src=PATH`. + // - Running git to find a checkout directory from the current working directory. + // - The source directory that this bootstrap executable was built from. + let src = flags_src + .or_else(|| compute_src_directory_via_git(&exec_ctx)) + .unwrap_or_else(|| default_src_dir.clone()); + + if cfg!(test) { + match flags_config.as_deref() { + Some(config_path) => assert!( !config_path.starts_with(&src), "Path {config_path:?} should not be inside or equal to src dir {src:?}" - ); - } else { - panic!("During test the config should be explicitly added"); + ), + None => panic!("During test the config should be explicitly added"), } } @@ -2038,54 +2039,49 @@ fn reconcile_jemalloc( } } -fn compute_src_directory(src_dir: Option, exec_ctx: &ExecutionContext) -> Option { - if let Some(src) = src_dir { - return Some(src); - } else { - // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, - // running on a completely different machine from where it was compiled. - let mut cmd = helpers::git(None); - // NOTE: we cannot support running from outside the repository because the only other path we have available - // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. - // We still support running outside the repository if we find we aren't in a git directory. - - // NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path, - // and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap - // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path. - cmd.arg("rev-parse").arg("--show-cdup"); - // Discard stderr because we expect this to fail when building from a tarball. - let output = cmd.allow_failure().run_capture_stdout(exec_ctx); - if output.is_success() { - let git_root_relative = output.stdout(); - // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes, - // and to resolve any relative components. - let git_root = env::current_dir() - .unwrap() - .join(PathBuf::from(git_root_relative.trim())) - .canonicalize() - .unwrap(); - let s = git_root.to_str().unwrap(); - - // Bootstrap is quite bad at handling /? in front of paths - let git_root = match s.strip_prefix("\\\\?\\") { - Some(p) => PathBuf::from(p), - None => git_root, - }; - // If this doesn't have at least `stage0`, we guessed wrong. This can happen when, - // for example, the build directory is inside of another unrelated git directory. - // In that case keep the original `CARGO_MANIFEST_DIR` handling. - // - // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside - // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1. - if git_root.join("src").join("stage0").exists() { - return Some(git_root); - } - } else { - // We're building from a tarball, not git sources. - // We don't support pre-downloaded bootstrap in this case. - } +fn compute_src_directory_via_git(exec_ctx: &ExecutionContext) -> Option { + // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, + // running on a completely different machine from where it was compiled. + // NOTE: we cannot support running from outside the repository because the only other path we have available + // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. + // We still support running outside the repository if we find we aren't in a git directory. + + // NOTE: We get a relative path from git (`--show-cdup`) to work around an issue on MSYS/mingw. + // If we used an absolute path, and end up using MSYS's git rather than git-for-windows, we would + // get a unix-y MSYS path. But as bootstrap has already been (kinda-cross-)compiled to Windows land, + // we require a normal Windows path. + + // Ask git to print the path of the repository root, relative to the working directory. + // If the working directory is the repo root, the output will be empty, which is fine. + let mut cmd = helpers::git(None); + cmd.arg("rev-parse").arg("--show-cdup"); + // Discard stderr because we expect this to fail when building from a tarball. + let output = cmd.allow_failure().run_capture_stdout(exec_ctx); + if output.is_failure() { + // We're building from a tarball, not git sources. + // We don't support pre-downloaded bootstrap in this case. + return None; + } + + // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes, + // and to resolve any relative components. + let stdout = output.stdout(); + let relative_root = stdout.trim(); + let git_root = env::current_dir().unwrap().join(relative_root).canonicalize().unwrap(); + + // Bootstrap is quite bad at handling /? in front of paths + let git_root = match git_root.to_str().unwrap().strip_prefix("\\\\?\\") { + Some(p) => PathBuf::from(p), + None => git_root, }; - None + + // If this doesn't have at least `./src/stage0`, we guessed wrong. This can happen when, + // for example, the build directory is inside of another unrelated git directory. + // In that case keep the original `CARGO_MANIFEST_DIR` handling. + // + // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside + // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1. + if git_root.join("src").join("stage0").exists() { Some(git_root) } else { None } } #[derive(Clone)] diff --git a/tests/assembly-llvm/naked-functions/target-feature.rs b/tests/assembly-llvm/naked-functions/target-feature.rs new file mode 100644 index 0000000000000..500e2a778e475 --- /dev/null +++ b/tests/assembly-llvm/naked-functions/target-feature.rs @@ -0,0 +1,165 @@ +//@ revisions: aarch64-elf aarch64-macho aarch64-coff x86_64 s390x riscv64 powerpc64 loongarch64 +//@ add-minicore +//@ assembly-output: emit-asm +//@ min-llvm-version: 23 +// +//@ [x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@ [x86_64] needs-llvm-components: x86 +// +//@ [aarch64-elf] compile-flags: --target aarch64-unknown-linux-gnu +//@ [aarch64-elf] needs-llvm-components: aarch64 +//@ [aarch64-macho] compile-flags: --target aarch64-apple-darwin +//@ [aarch64-macho] needs-llvm-components: aarch64 +//@ [aarch64-coff] compile-flags: --target aarch64-pc-windows-gnullvm +//@ [aarch64-coff] needs-llvm-components: aarch64 +// +//@ [s390x] compile-flags: --target s390x-unknown-linux-gnu +//@ [s390x] needs-llvm-components: systemz +// +//@ [powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@ [powerpc64] needs-llvm-components: powerpc +// +//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64] needs-llvm-components: riscv +// +// NOTE: loongarch64 does not error when using an instruction without enabling the corresponding +// target feature. +//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [loongarch64] needs-llvm-components: loongarch + +// Test that the #[target_feature(enable = ...)]` works on naked functions. + +#![crate_type = "lib"] +#![feature(no_core, naked_functions_target_feature)] +#![feature(s390x_target_feature, powerpc_target_feature, loongarch_target_feature)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// x86_64-LABEL: vpclmulqdq: +// x86_64: vpclmulqdq +#[no_mangle] +#[unsafe(naked)] +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "vpclmulqdq")] +unsafe extern "C" fn vpclmulqdq() { + naked_asm!("vpclmulqdq zmm1, zmm2, zmm3, 4") +} + +// i8mm is not enabled by default +// +// note that aarch64-apple-darwin enables more features than aarch64-unknown-linux-gnu +// +// aarch64-elf-LABEL: i8mm: +// aarch64-elf: usdot +// aarch64-macho-LABEL: i8mm: +// aarch64-macho: usdot +// aarch64-coff-LABEL: i8mm: +// aarch64-coff: usdot +#[no_mangle] +#[unsafe(naked)] +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "i8mm")] +unsafe extern "C" fn i8mm() { + naked_asm!("usdot v0.4s, v1.16b, v2.4b[3]") +} + +// riscv64: sh1add: +// riscv64: sh1add +#[no_mangle] +#[unsafe(naked)] +#[cfg(target_arch = "riscv64")] +#[target_feature(enable = "zba")] +unsafe extern "C" fn sh1add() { + naked_asm!("sh1add a0, a1, a2", "ret"); +} + +#[cfg(target_arch = "s390x")] +mod s390x { + use super::*; + + // s390x: vector: + // s390x: vavglg + #[no_mangle] + #[unsafe(naked)] + #[target_feature(enable = "vector")] + unsafe extern "C" fn vector() { + naked_asm!("vavglg %v0, %v0, %v0") + } + + // s390x: vector_enhancements_1: + // s390x: vfcesbs + #[no_mangle] + #[unsafe(naked)] + #[target_feature(enable = "vector-enhancements-1")] + unsafe extern "C" fn vector_enhancements_1() { + naked_asm!("vfcesbs %v0, %v0, %v0") + } + + // s390x: vector_enhancements_2: + // s390x: vclfp + #[no_mangle] + #[unsafe(naked)] + #[target_feature(enable = "vector-enhancements-2")] + unsafe extern "C" fn vector_enhancements_2() { + naked_asm!("vclfp %v0, %v0, 0, 0, 0") + } + + // s390x: vector_packed_decimal: + // s390x: vlrlr + #[no_mangle] + #[unsafe(naked)] + #[target_feature(enable = "vector-packed-decimal")] + unsafe extern "C" fn vector_packed_decimal() { + naked_asm!("vlrlr %v24, %r3, 0(%r2)", "br %r14") + } + + // s390x: vector_packed_decimal_enhancement: + // s390x: vcvbg + #[no_mangle] + #[unsafe(naked)] + #[target_feature(enable = "vector-packed-decimal-enhancement")] + unsafe extern "C" fn vector_packed_decimal_enhancement() { + naked_asm!("vcvbg %r0, %v0, 0, 1") + } + + // s390x: vector_packed_decimal_enhancement_2: + // s390x: vupkzl + #[no_mangle] + #[unsafe(naked)] + #[target_feature(enable = "vector-packed-decimal-enhancement-2")] + unsafe extern "C" fn vector_packed_decimal_enhancement_2() { + naked_asm!("vupkzl %v0, %v0, 0") + } +} + +// powerpc64: power10_vector: +// powerpc64: xxpermx +#[no_mangle] +#[unsafe(naked)] +#[cfg(target_arch = "powerpc64")] +#[target_feature(enable = "power10-vector")] +unsafe extern "C" fn power10_vector() { + naked_asm!("xxpermx 34, 0, 1, 2, 0", "blr") +} + +// loongarch64: lasx: +// loongarch64: xvadd.b +#[no_mangle] +#[unsafe(naked)] +#[cfg(target_arch = "loongarch64")] +#[target_feature(enable = "lasx")] +unsafe extern "C" fn lasx() { + naked_asm!("xvadd.b $xr0, $xr0, $xr1", "ret") +} + +// wasm32: simd128: +// wasm32: i8x16.shuffle +#[no_mangle] +#[unsafe(naked)] +#[cfg(target_arch = "wasm32")] +#[target_feature(enable = "simd128")] +unsafe extern "C" fn simd128() { + naked_asm!("i8x16.shuffle 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15", "return"); +} diff --git a/tests/ui/asm/naked-functions/target-feature-aarch64.rs b/tests/ui/asm/naked-functions/target-feature-aarch64.rs new file mode 100644 index 0000000000000..f82122f773ca0 --- /dev/null +++ b/tests/ui/asm/naked-functions/target-feature-aarch64.rs @@ -0,0 +1,47 @@ +//@ add-minicore +//@ build-fail +//@ revisions: vanilla sha3 +//@ compile-flags: --target aarch64-unknown-linux-gnu -Z deduplicate-diagnostics=yes +//@[sha3] compile-flags: -Ctarget-feature=+sha3 +//@ needs-llvm-components: aarch64 +//@ min-llvm-version: 23 + +#![crate_type = "lib"] +#![feature(no_core, naked_functions_target_feature)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// check that a naked function using target features does not keep these features enabled +// for subsequent asm blocks. + +#[no_mangle] +#[unsafe(naked)] +#[target_feature(enable = "i8mm")] +unsafe extern "C" fn a() { + naked_asm!("usdot v0.4s, v1.16b, v2.4b[3]") +} + +//~? ERROR instruction requires: i8mm + +#[no_mangle] +#[unsafe(naked)] +unsafe extern "C" fn c() { + naked_asm!("usdot v0.4s, v2.16b, v2.4b[3]") +} + +#[no_mangle] +#[unsafe(naked)] +#[target_feature(enable = "sha3")] +unsafe extern "C" fn d() { + naked_asm!("eor3 v0.16b, v1.16b, v2.16b, v3.16b") +} + +//[vanilla]~? ERROR instruction requires: sha3 + +#[no_mangle] +#[unsafe(naked)] +unsafe extern "C" fn b() { + naked_asm!("eor3 v0.16b, v1.16b, v2.16b, v3.16b") +} diff --git a/tests/ui/asm/naked-functions/target-feature-aarch64.sha3.stderr b/tests/ui/asm/naked-functions/target-feature-aarch64.sha3.stderr new file mode 100644 index 0000000000000..49a65eaadb904 --- /dev/null +++ b/tests/ui/asm/naked-functions/target-feature-aarch64.sha3.stderr @@ -0,0 +1,10 @@ +error: instruction requires: i8mm + | +note: instantiated into assembly here + --> :15:1 + | +LL | usdot v0.4s, v2.16b, v2.4b[3] + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/asm/naked-functions/target-feature-aarch64.vanilla.stderr b/tests/ui/asm/naked-functions/target-feature-aarch64.vanilla.stderr new file mode 100644 index 0000000000000..8ac31d19f5e3e --- /dev/null +++ b/tests/ui/asm/naked-functions/target-feature-aarch64.vanilla.stderr @@ -0,0 +1,18 @@ +error: instruction requires: sha3 + | +note: instantiated into assembly here + --> :6:1 + | +LL | eor3 v0.16b, v1.16b, v2.16b, v3.16b + | ^ + +error: instruction requires: i8mm + | +note: instantiated into assembly here + --> :15:1 + | +LL | usdot v0.4s, v2.16b, v2.4b[3] + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/asm/naked-functions/target-feature-s390x.rs b/tests/ui/asm/naked-functions/target-feature-s390x.rs new file mode 100644 index 0000000000000..b0f806c4c0a16 --- /dev/null +++ b/tests/ui/asm/naked-functions/target-feature-s390x.rs @@ -0,0 +1,30 @@ +//@ add-minicore +//@ build-fail +//@ compile-flags: --target s390x-unknown-linux-gnu -Z deduplicate-diagnostics=yes +//@ needs-llvm-components: systemz +//@ min-llvm-version: 23 + +#![crate_type = "lib"] +#![feature(no_core, naked_functions_target_feature)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// check that a naked function using target features does not keep these features enabled +// for subsequent asm blocks. + +#[no_mangle] +#[unsafe(naked)] +#[target_feature(enable = "vector-packed-decimal")] +unsafe extern "C" fn a() { + naked_asm!("vlrlr %v24, %r3, 0(%r2)") +} + +//~? ERROR instruction requires: vector-packed-decimal + +#[no_mangle] +#[unsafe(naked)] +unsafe extern "C" fn b() { + naked_asm!("vlrlr %v24, %r3, 0(%r3)") +} diff --git a/tests/ui/asm/naked-functions/target-feature-s390x.stderr b/tests/ui/asm/naked-functions/target-feature-s390x.stderr new file mode 100644 index 0000000000000..84d60c43bc765 --- /dev/null +++ b/tests/ui/asm/naked-functions/target-feature-s390x.stderr @@ -0,0 +1,10 @@ +error: instruction requires: vector-packed-decimal + | +note: instantiated into assembly here + --> :6:1 + | +LL | vlrlr %v24, %r3, 0(%r3) + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/panics/lsda-multiple-action.rs b/tests/ui/panics/lsda-multiple-action.rs new file mode 100644 index 0000000000000..236e8b90ca5b1 --- /dev/null +++ b/tests/ui/panics/lsda-multiple-action.rs @@ -0,0 +1,29 @@ +//@ run-pass +//@ needs-unwind +//@ ignore-backends: gcc +//@ compile-flags: -Copt-level=3 + +struct Guard; + +impl Drop for Guard { + fn drop(&mut self) { + core::hint::black_box(()); + } +} + +#[inline(never)] +fn unwind() { + if core::hint::black_box(true) { + std::panic::resume_unwind(Box::new(())); + } +} + +fn main() { + // The `catch_unwind` will generate `landingpad catch` and the destructor will generate + // `landingpad cleanup`; after LLVM inlining it will become `landingpad cleanup catch`, and this + // is translated to action record chains in LSDA. + let _ = std::panic::catch_unwind(|| { + let _guard = Guard; + unwind(); + }); +}