diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 3e24b62125fea..7c1d89ef93507 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -93,8 +93,19 @@ fn process_builtin_attrs( AttributeKind::LinkSection { name } => codegen_fn_attrs.link_section = Some(*name), AttributeKind::NoMangle(attr_span) => { interesting_spans.no_mangle = Some(*attr_span); - if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + if let Some(name) = tcx.opt_item_name(did.to_def_id()) { + // Don't override #[export_name]. + + // Also don't override #[link_name]. All places where #[link_name] is allowed + // shouldn't allow #[no_mangle], so #[link_name] shouldn't be a concern here, + // however currently #[no_mangle] is currently merely a warning on foreign + // items rather than a hard error, so we still need to take #[no_mangle] + + // #[link_name] into account. + // FIXME remove this comment once #[no_mangle] on foreign items is a hard error. + + if codegen_fn_attrs.symbol_name.is_none() { + codegen_fn_attrs.symbol_name = Some(name); + } } else { tcx.dcx() .span_delayed_bug(*attr_span, "no_mangle should be on a named function"); @@ -402,6 +413,8 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // get the same symbol name as the *mangled* foreign item they refer to so that's all good. } else if codegen_fn_attrs.symbol_name.is_some() { // * This can be overridden with the `#[link_name]` attribute + } else if codegen_fn_attrs.link_ordinal.is_some() { + // * `#[link_ordinal]` and `#[link_name]` are incompatible with each other } else { // NOTE: there's one more exception that we cannot apply here. On wasm, // some items cannot be `no_mangle`. @@ -410,7 +423,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // import will *still* be mangled despite this. // // if none of the exceptions apply; apply no_mangle - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + codegen_fn_attrs.symbol_name = Some(tcx.item_name(did)); } } } @@ -543,22 +556,24 @@ fn handle_lang_items( // strippable by the linker. // // Additionally weak lang items have predetermined symbol names. - if let Some(lang_item) = lang_item + let link_name_override = if let Some(lang_item) = lang_item && let Some(link_name) = lang_item.link_name() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - codegen_fn_attrs.symbol_name = Some(link_name); - } + Some(link_name) + } else { + None + }; - // error when using no_mangle on a lang item item + // error when using no_mangle, or export_name on a lang item item if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - && codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) + && codegen_fn_attrs.symbol_name.is_some() { let mut err = tcx .dcx() .struct_span_err( interesting_spans.no_mangle.unwrap_or_default(), - "`#[no_mangle]` cannot be used on internal language items", + "`#[no_mangle]` and `#[export_name]` cannot be used on internal language items", ) .with_note("Rustc requires this item to have a specific mangled name.") .with_span_label(tcx.def_span(did), "should be the internal language item"); @@ -574,6 +589,10 @@ fn handle_lang_items( } err.emit(); } + + if let Some(link_name_override) = link_name_override { + codegen_fn_attrs.symbol_name = Some(link_name_override); + } } /// Generate the [`CodegenFnAttrs`] for an item (identified by the [`LocalDefId`]). diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 3010eadb61057..373371c625aa9 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -77,23 +77,11 @@ struct ClashingExternDeclarations { seen_decls: UnordMap, } -/// Differentiate between whether the name for an extern decl came from the link_name attribute or -/// just from declaration itself. This is important because we don't want to report clashes on -/// symbol name if they don't actually clash because one or the other links against a symbol with a -/// different name. -enum SymbolName { - /// The name of the symbol + the span of the annotation which introduced the link name. - Link(Symbol, Span), - /// No link name, so just the name of the symbol. - Normal(Symbol), -} - -impl SymbolName { - fn get_name(&self) -> Symbol { - match self { - SymbolName::Link(s, _) | SymbolName::Normal(s) => *s, - } - } +struct SymbolName { + /// The name of the symbol that will be linked against. + link_name: Symbol, + /// The span of the annotation which introduced the link name. + span: Option, } impl ClashingExternDeclarations { @@ -140,7 +128,7 @@ impl ClashingExternDeclarations { // Finally, emit the diagnostic. let this = tcx.item_name(this_fi.owner_id.to_def_id()); - let orig = orig.get_name(); + let orig = orig.link_name; let previous_decl_label = get_relevant_span(tcx, existing_did); let mismatch_label = get_relevant_span(tcx, this_fi.owner_id); let sub = @@ -176,28 +164,24 @@ impl ClashingExternDeclarations { /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the /// symbol's name. fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { - if let Some((overridden_link_name, overridden_link_name_span)) = - tcx.codegen_fn_attrs(fi).symbol_name.map(|overridden_link_name| { - // FIXME: Instead of searching through the attributes again to get span - // information, we could have codegen_fn_attrs also give span information back for - // where the attribute was defined. However, until this is found to be a - // bottleneck, this does just fine. - (overridden_link_name, find_attr!(tcx, fi, LinkName {span, ..} => *span).unwrap()) - }) - { - SymbolName::Link(overridden_link_name, overridden_link_name_span) - } else { - SymbolName::Normal(tcx.item_name(fi.to_def_id())) + // FIXME if symbol_name is not set, this is likely a #[rustc_std_internal_symbol] or EII which + // actually have their name mangled and thus should use the mangled name here. + let link_name = + tcx.codegen_fn_attrs(fi).symbol_name.unwrap_or_else(|| tcx.item_name(fi.to_def_id())); + SymbolName { + link_name, + // FIXME: Instead of searching through the attributes again to get span + // information, we could have codegen_fn_attrs also give span information back for + // where the attribute was defined. However, until this is found to be a + // bottleneck, this does just fine. + span: find_attr!(tcx, fi, LinkName {span, ..} => *span), } } /// We want to ensure that we use spans for both decls that include where the /// name was defined, whether that was from the link_name attribute or not. fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span { - match name_of_extern_decl(tcx, fi) { - SymbolName::Normal(_) => tcx.def_span(fi), - SymbolName::Link(_, annot_span) => annot_span, - } + if let Some(span) = name_of_extern_decl(tcx, fi).span { span } else { tcx.def_span(fi) } } /// Checks whether two types are structurally the same enough that the declarations shouldn't diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index b6ae4a98a34e3..a3460a1326eb9 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -36,10 +36,6 @@ impl<'tcx> TyCtxt<'tcx> { if let InstanceKind::Shim(ShimKind::Reify(_, _)) = instance_kind && attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) { - if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - attrs.to_mut().flags.remove(CodegenFnAttrFlags::NO_MANGLE); - } - if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { attrs.to_mut().flags.remove(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); } @@ -203,9 +199,6 @@ bitflags::bitflags! { /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue /// should be generated. const NAKED = 1 << 2; - /// `#[no_mangle]`: an indicator that the function's name should be the same - /// as its symbol. - const NO_MANGLE = 1 << 3; /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a /// "weird symbol" for the standard library in that it has slightly /// different linkage, visibility, and reachability rules. @@ -290,8 +283,7 @@ impl CodegenFnAttrs { return false; } - self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) - || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) // note: for these we do also set a symbol name so technically also handled by the // condition below. However, I think that regardless these should be treated as extern. || self.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 482848578a81b..a9f2375d0fa21 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -221,11 +221,6 @@ pub fn symbol_name_from_attrs<'tcx>( // Use provided name return Some(name.to_string()); } - - if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - // Don't mangle - return Some(tcx.item_name(def_id).to_string()); - } } None diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 683e9095f9b0c..3d8cda11c3d85 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -136,7 +136,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let attrs = tcx.codegen_fn_attrs(def_id); // Skip over items without an explicitly defined symbol name. if !(attrs.symbol_name.is_some() - || attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)) { return interp_ok(()); diff --git a/tests/ui/codegen/no-mangle-on-internal-lang-items.rs b/tests/ui/codegen/no-mangle-on-internal-lang-items.rs index 37766936410ed..58a03f04554f6 100644 --- a/tests/ui/codegen/no-mangle-on-internal-lang-items.rs +++ b/tests/ui/codegen/no-mangle-on-internal-lang-items.rs @@ -4,11 +4,7 @@ #![feature(rustc_attrs)] #[rustc_std_internal_symbol] -#[unsafe(no_mangle)] //~ERROR `#[no_mangle]` cannot be used on internal language items -fn internal_lang_function () { +#[unsafe(no_mangle)] //~ERROR `#[no_mangle]` and `#[export_name]` cannot be used on internal language items +fn internal_lang_function() {} -} - -fn main() { - -} +fn main() {} diff --git a/tests/ui/codegen/no-mangle-on-internal-lang-items.stderr b/tests/ui/codegen/no-mangle-on-internal-lang-items.stderr index 12461a6abb964..a02111673309c 100644 --- a/tests/ui/codegen/no-mangle-on-internal-lang-items.stderr +++ b/tests/ui/codegen/no-mangle-on-internal-lang-items.stderr @@ -1,10 +1,10 @@ -error: `#[no_mangle]` cannot be used on internal language items +error: `#[no_mangle]` and `#[export_name]` cannot be used on internal language items --> $DIR/no-mangle-on-internal-lang-items.rs:7:1 | LL | #[unsafe(no_mangle)] | ^^^^^^^^^^^^^^^^^^^^ -LL | fn internal_lang_function () { - | ---------------------------- should be the internal language item +LL | fn internal_lang_function() {} + | --------------------------- should be the internal language item | = note: Rustc requires this item to have a specific mangled name. diff --git a/tests/ui/codegen/no-mangle-on-panic-handler.rs b/tests/ui/codegen/no-mangle-on-panic-handler.rs index 1dc0cce0a2ece..6760c7a8bf045 100644 --- a/tests/ui/codegen/no-mangle-on-panic-handler.rs +++ b/tests/ui/codegen/no-mangle-on-panic-handler.rs @@ -1,13 +1,13 @@ // Issue an error when the user uses #[no_mangle] on the panic handler //@ edition:2024 -#![crate_type="lib"] +#![crate_type = "lib"] #![no_std] #![no_main] use core::panic::PanicInfo; -#[unsafe(no_mangle)] //~ ERROR `#[no_mangle]` cannot be used on internal language items +#[unsafe(no_mangle)] //~ ERROR `#[no_mangle]` and `#[export_name]` cannot be used on internal language items #[panic_handler] pub unsafe fn panic_fmt(pi: &PanicInfo) -> ! { loop {} diff --git a/tests/ui/codegen/no-mangle-on-panic-handler.stderr b/tests/ui/codegen/no-mangle-on-panic-handler.stderr index dc88b66d1b5d7..3808eb11f4cb6 100644 --- a/tests/ui/codegen/no-mangle-on-panic-handler.stderr +++ b/tests/ui/codegen/no-mangle-on-panic-handler.stderr @@ -1,4 +1,4 @@ -error: `#[no_mangle]` cannot be used on internal language items +error: `#[no_mangle]` and `#[export_name]` cannot be used on internal language items --> $DIR/no-mangle-on-panic-handler.rs:10:1 | LL | #[unsafe(no_mangle)]