Skip to content

Commit caa2b04

Browse files
error or warn when using no_mangle on language items
1 parent 49e5e4e commit caa2b04

5 files changed

+120
-1
lines changed

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+47-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
8787
let mut link_ordinal_span = None;
8888
let mut no_sanitize_span = None;
8989
let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
90+
let mut no_mangle_span = None;
9091

9192
for attr in attrs.iter() {
9293
// In some cases, attribute are only valid on functions, but it's the `check_attr`
@@ -139,6 +140,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
139140
}
140141
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
141142
sym::no_mangle => {
143+
no_mangle_span = Some(attr.span());
142144
if tcx.opt_item_name(did.to_def_id()).is_some() {
143145
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
144146
mixed_export_name_no_mangle_lint_state.track_no_mangle(
@@ -608,11 +610,55 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
608610
// strippable by the linker.
609611
//
610612
// Additionally weak lang items have predetermined symbol names.
611-
if let Some((name, _)) = lang_items::extract(attrs)
613+
if let Some((name, span)) = lang_items::extract(attrs)
612614
&& let Some(lang_item) = LangItem::from_name(name)
613615
{
616+
let has_no_mangle = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE);
614617
if WEAK_LANG_ITEMS.contains(&lang_item) {
615618
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
619+
if has_no_mangle {
620+
// This should never use the default as `no_mangle` is present in the attributes list
621+
let no_mangle_span = no_mangle_span.unwrap_or_default();
622+
let label_attr = format!("this defines it as the `{}` item", lang_item.name());
623+
let label = format!("is the {} item", lang_item.name());
624+
let mut err = tcx.dcx()
625+
.struct_span_err(no_mangle_span, "`#[no_mangle]` cannot be used on weak language items")
626+
.with_note("The linker requires specific names for internal language items,")
627+
.with_note("like panic handlers, eh personality functions or eh catch typeinfo variables.")
628+
.with_span_label(tcx.def_span(did), label)
629+
.with_span_label(span, label_attr);
630+
if let Some(link_name) = lang_item.link_name() {
631+
let renamed =
632+
format!("In this case it is automatically renamed to `{}`", link_name);
633+
err = err.with_note(renamed);
634+
}
635+
err.emit();
636+
}
637+
} else {
638+
if has_no_mangle {
639+
// This should never use the default as `no_mangle` is present in the attributes list
640+
let no_mangle_span = no_mangle_span.unwrap_or_default();
641+
let label_attr = format!("this defines it as the `{}` item", lang_item.name());
642+
let label = format!("is the {} item", lang_item.name());
643+
let mut warn = tcx
644+
.dcx()
645+
.struct_span_warn(
646+
no_mangle_span,
647+
"`#[no_mangle]` should not be used on std internal language items",
648+
)
649+
.with_note("The linker requires specific names for internal language items,")
650+
.with_note("as they might require a specific link name in the future.")
651+
.with_span_label(tcx.def_span(did), label)
652+
.with_span_label(span, label_attr);
653+
if let Some(link_name) = lang_item.link_name() {
654+
let renamed = format!(
655+
"In this case this should be automatically renamed to `{}`",
656+
link_name
657+
);
658+
warn = warn.with_note(renamed);
659+
}
660+
warn.emit();
661+
}
616662
}
617663
if let Some(link_name) = lang_item.link_name() {
618664
codegen_fn_attrs.export_name = Some(link_name);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Issue a warning when the user #[no_mangle] on weak language items
2+
//@ check-pass
3+
//@ edition:2024
4+
5+
#![crate_type="lib"]
6+
#![no_std]
7+
#![no_main]
8+
#![feature(lang_items)]
9+
10+
#[lang = "start"]
11+
#[unsafe(no_mangle)] //~WARN `#[no_mangle]` should not be used on std internal language items
12+
fn my_custom_start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8, _arg: u8) -> isize { //~ WARN functions generic over types or consts must be mangled
13+
main();
14+
0
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
warning: `#[no_mangle]` should not be used on std internal language items
2+
--> $DIR/no_mangle_on_std_internal_lang_items.rs:11:1
3+
|
4+
LL | #[lang = "start"]
5+
| ----------------- this defines it as the `start` item
6+
LL | #[unsafe(no_mangle)]
7+
| ^^^^^^^^^^^^^^^^^^^^
8+
LL | fn my_custom_start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8, _arg: u8) -> isize {
9+
| ------------------------------------------------------------------------------------------------ is the start item
10+
|
11+
= note: The linker requires specific names for internal language items,
12+
= note: as they might require a specific link name in the future.
13+
14+
warning: functions generic over types or consts must be mangled
15+
--> $DIR/no_mangle_on_std_internal_lang_items.rs:12:1
16+
|
17+
LL | #[unsafe(no_mangle)]
18+
| -------------------- help: remove this attribute
19+
LL | / fn my_custom_start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8, _arg: u8) -> isize {
20+
LL | | main();
21+
LL | | 0
22+
LL | | }
23+
| |_^
24+
|
25+
= note: `#[warn(no_mangle_generic_items)]` on by default
26+
27+
warning: 2 warnings emitted
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Issue an error when the user #[no_mangle] on weak language items
2+
//@ edition:2024
3+
4+
#![crate_type="lib"]
5+
#![no_std]
6+
#![no_main]
7+
8+
use core::panic::PanicInfo;
9+
10+
#[unsafe(no_mangle)] //~ ERROR `#[no_mangle]` cannot be used on weak language items
11+
#[panic_handler]
12+
pub unsafe fn panic_fmt(pi: &PanicInfo) -> ! {
13+
loop {}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: `#[no_mangle]` cannot be used on weak language items
2+
--> $DIR/no_mangle_on_weak_lang_items.rs:10:1
3+
|
4+
LL | #[unsafe(no_mangle)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
LL | #[panic_handler]
7+
| ---------------- this defines it as the `panic_impl` item
8+
LL | pub unsafe fn panic_fmt(pi: &PanicInfo) -> ! {
9+
| -------------------------------------------- is the panic_impl item
10+
|
11+
= note: The linker requires specific names for internal language items,
12+
= note: like panic handlers, eh personality functions or eh catch typeinfo variables.
13+
= note: In this case it is automatically renamed to `rust_begin_unwind`
14+
15+
error: aborting due to 1 previous error
16+

0 commit comments

Comments
 (0)