From 19fd8d5b95d7cd2c1e105a05fef85dfc7e281fc7 Mon Sep 17 00:00:00 2001 From: Daniel Mellado Date: Thu, 20 Aug 2026 10:08:18 +0200 Subject: [PATCH] Generate debug info for BPF extern declarations Enable ksyms/kfunc support for BPF programs by emitting debug info metadata for extern statics and functions on BPF targets. - Allow #[link_section] on ForeignStatic and ForeignFn targets - Add LLVMRustDIBuilderCreateGlobalVariableExpression C++ wrapper to expose the isDefinition parameter (the LLVM-C API hard-codes it to true) - Emit DIGlobalVariable with isDefinition: false for extern statics and DISubprogram without SPFlagDefinition for extern functions, gated to Arch::Bpf - Refactor build_global_var_di_node into a shared inner function to avoid duplicating the static variable debug info logic The BTF entries generated from this metadata are required by the kernel verifier to resolve ksyms and kfuncs at BPF program load time. Co-authored-by: Altug Bozkurt --- .../src/attributes/link_attrs.rs | 13 ++- .../rustc_attr_parsing/src/diagnostics.rs | 7 ++ compiler/rustc_codegen_llvm/src/callee.rs | 8 ++ compiler/rustc_codegen_llvm/src/consts.rs | 7 ++ .../src/debuginfo/di_builder.rs | 7 +- .../src/debuginfo/metadata.rs | 44 ++++++--- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 89 ++++++++++++++++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 16 ++++ tests/codegen-llvm/bpf-extern-debuginfo.rs | 35 ++++++++ .../extern-no-debuginfo-non-bpf.rs | 24 +++++ tests/codegen-llvm/link-section-foreign.rs | 35 ++++++++ tests/ui/attributes/attr-on-mac-call.stderr | 2 +- ...degen_attr_on_required_trait_method.stderr | 2 +- .../cfg_attr-attr-syntax-validation.stderr | 2 +- ...issue-43106-gating-of-builtin-attrs.stderr | 16 ++-- .../link-section-foreign-bpf-only.rs | 25 ++++++ .../link-section-foreign-bpf-only.stderr | 14 +++ 18 files changed, 318 insertions(+), 31 deletions(-) create mode 100644 tests/codegen-llvm/bpf-extern-debuginfo.rs create mode 100644 tests/codegen-llvm/extern-no-debuginfo-non-bpf.rs create mode 100644 tests/codegen-llvm/link-section-foreign.rs create mode 100644 tests/ui/linkage-attr/link-section-foreign-bpf-only.rs create mode 100644 tests/ui/linkage-attr/link-section-foreign-bpf-only.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 6289b1c726684..59aaf31631dd2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -17,8 +17,8 @@ use crate::diagnostics::{ AsNeededCompatibility, BothFfiConstAndPure, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, - LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection, - RawDylibOnlyWindows, WholeArchiveNeedsStatic, + LinkOrdinalOutOfRange, LinkRequiresName, LinkSectionForeignBpfOnly, MultipleModifiers, + NullOnLinkName, NullOnLinkSection, RawDylibOnlyWindows, WholeArchiveNeedsStatic, }; pub(crate) struct LinkNameParser; @@ -505,6 +505,8 @@ impl SingleAttributeParser for LinkSectionParser { Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::ForeignStatic), + Allow(Target::ForeignFn), ]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "name", @@ -512,6 +514,13 @@ impl SingleAttributeParser for LinkSectionParser { ); fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { + if matches!(cx.target, Target::ForeignStatic | Target::ForeignFn) + && cx.sess.target.arch != Arch::Bpf + { + cx.emit_err(LinkSectionForeignBpfOnly { span: cx.attr_span }); + return None; + } + let nv = cx.expect_name_value(args, cx.attr_span, None)?; let name = cx.expect_string_literal(nv)?; if name.as_str().contains('\0') { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 9d72bdcb75ce3..7ec21a2decbba 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1235,6 +1235,13 @@ pub(crate) struct NullOnLinkSection { pub span: Span, } +#[derive(Diagnostic)] +#[diag("`link_section` on foreign items is only supported on BPF targets")] +pub(crate) struct LinkSectionForeignBpfOnly { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("link name may not contain null characters", code = E0648)] pub(crate) struct NullOnLinkName { diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 9215273eed17d..76e93f9e8fce3 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_target::spec::{Arch, Env}; use tracing::debug; +use crate::base; use crate::context::CodegenCx; use crate::llvm::{self, Value}; @@ -152,6 +153,13 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t cx.assume_dso_local(llfn, true); + if tcx.is_foreign_item(instance_def_id) { + base::set_link_section(llfn, tcx.codegen_fn_attrs(instance_def_id)); + if tcx.sess.target.arch == Arch::Bpf { + cx.dbg_scope_foreign_fn(instance, fn_abi, Some(llfn)); + } + } + llfn }; diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5ecd5c19b6f8e..76fae918de115 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -465,6 +465,13 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_dllimport_storage_class(g); } + if self.tcx.is_foreign_item(def_id) { + base::set_link_section(g, fn_attrs); + if self.tcx.sess.target.arch == Arch::Bpf { + debuginfo::build_extern_static_di_node(self, def_id, g); + } + } + self.instances.borrow_mut().insert(instance, g); g } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs index 0b5ef6c687404..73f3ff44b54c1 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs @@ -43,6 +43,7 @@ pub(crate) trait DIBuilderExt<'ll> { unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) } } + /// Creates a DIGlobalVariable debug info node. fn create_static_variable( &self, scope: Option<&'ll llvm::Metadata>, @@ -52,6 +53,7 @@ pub(crate) trait DIBuilderExt<'ll> { line_number: c_uint, ty: &'ll llvm::Metadata, is_local_to_unit: bool, + is_definition: bool, val: &'ll llvm::Value, decl: Option<&'ll llvm::Metadata>, align: Option, @@ -59,14 +61,14 @@ pub(crate) trait DIBuilderExt<'ll> { let this = self.as_di_builder(); let align_in_bits = align.map_or(0, |align| align.bits() as u32); - // `LLVMDIBuilderCreateGlobalVariableExpression` would assert if we + // `LLVMRustDIBuilderCreateGlobalVariableExpression` would assert if we // gave it a null `Expr` pointer, so give it an empty expression // instead, which is what the C++ `createGlobalVariableExpression` // method would do if given a null `DIExpression` pointer. let expr = self.create_expression(&[]); let global_var_expr = unsafe { - llvm::LLVMDIBuilderCreateGlobalVariableExpression( + llvm::LLVMRustDIBuilderCreateGlobalVariableExpression( this, scope, name.as_ptr(), @@ -77,6 +79,7 @@ pub(crate) trait DIBuilderExt<'ll> { line_number, ty, is_local_to_unit.to_llvm_bool(), + is_definition.to_llvm_bool(), expr, decl, align_in_bits, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 33f6eca6be9cc..67507adf1e9e0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1462,43 +1462,57 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( } } -/// Creates debug information for the given global variable. +/// Creates debug information for the given global variable (definition). /// /// Adds the created debuginfo nodes directly to the crate's IR. pub(crate) fn build_global_var_di_node<'ll>( cx: &CodegenCx<'ll, '_>, def_id: DefId, global: &'ll Value, +) { + let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() }; + if nested { + return; + } + + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + build_static_var_di_node_inner(cx, def_id, global, is_local_to_unit, true); +} + +/// Creates debug information for a foreign static (declaration, not definition). +pub(crate) fn build_extern_static_di_node<'ll>( + cx: &CodegenCx<'ll, '_>, + def_id: DefId, + global: &'ll Value, +) { + build_static_var_di_node_inner(cx, def_id, global, false, false); +} + +fn build_static_var_di_node_inner<'ll>( + cx: &CodegenCx<'ll, '_>, + def_id: DefId, + global: &'ll Value, + is_local_to_unit: bool, + is_definition: bool, ) { if cx.dbg_cx.is_none() { return; } - // Only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo != DebugInfo::Full { return; } let tcx = cx.tcx; - // We may want to remove the namespace scope if we're in an extern block (see - // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952). let var_scope = get_namespace_for_item(cx, def_id); let (file_metadata, line_number) = file_metadata_from_def_id(cx, Some(def_id)); - let is_local_to_unit = is_node_local_to_unit(cx, def_id); - - let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() }; - if nested { - return; - } let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, cx.typing_env()); let type_di_node = type_di_node(cx, variable_type); let var_name = tcx.item_name(def_id); let var_name = var_name.as_str(); let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name; - // When empty, linkage_name field is omitted, - // which is what we want for no_mangle statics let linkage_name = if var_name == linkage_name { "" } else { linkage_name }; let global_align = cx.align_of(variable_type); @@ -1511,8 +1525,9 @@ pub(crate) fn build_global_var_di_node<'ll>( line_number, type_di_node, is_local_to_unit, - global, // (value) - None, // (decl) + is_definition, + global, + None, Some(global_align), ); } @@ -1789,6 +1804,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( UNKNOWN_LINE_NUMBER, vtable_type_di_node, true, // (is_local_to_unit) + true, // (is_definition) vtable, // (value) None, // (decl) None::, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index d6d9946450899..dc1254cd3afee 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -27,10 +27,10 @@ use smallvec::SmallVec; use tracing::debug; pub(crate) use self::di_builder::DIBuilderExt; -pub(crate) use self::metadata::build_global_var_di_node; use self::metadata::{ UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node, }; +pub(crate) use self::metadata::{build_extern_static_di_node, build_global_var_di_node}; use self::namespace::mangled_name_of_instance; use self::utils::{DIB, create_DIArray, is_node_local_to_unit}; use crate::builder::Builder; @@ -755,3 +755,90 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { metadata::create_vtable_di_node(self, ty, trait_ref, vtable) } } + +impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { + /// Creates a `DISubprogram` for a foreign function declaration (without `SPFlagDefinition`). + /// + /// This is gated to BPF targets and emits the debug info that LLVM's BPF backend + /// needs to generate BTF FUNC entries for kfunc resolution. + pub(crate) fn dbg_scope_foreign_fn( + &self, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: Option<&'ll Value>, + ) { + if self.dbg_cx.is_none() { + return; + } + + if self.sess().opts.debuginfo != DebugInfo::Full { + return; + } + + let tcx = self.tcx; + let def_id = instance.def_id(); + + let scope = namespace::item_namespace( + self, + DefId { + krate: def_id.krate, + index: tcx.def_key(def_id).parent.expect("dbg_scope_foreign_fn: missing parent?"), + }, + ); + + let span = tcx.def_span(def_id); + let loc = self.lookup_debug_loc(span.lo()); + let file_metadata = file_metadata(self, &loc.file); + + let signature: Vec<_> = iter::once(if fn_abi.ret.is_ignore() { + None + } else { + Some(type_di_node(self, fn_abi.ret.layout.ty)) + }) + .chain(fn_abi.args.iter().map(|arg| Some(type_di_node(self, arg.layout.ty)))) + .collect(); + + let function_type_metadata = create_subroutine_type(self, &signature); + + let mut name = String::with_capacity(64); + type_names::push_item_name(tcx, def_id, false, &mut name); + + let linkage_name = &mangled_name_of_instance(self, instance).name; + let linkage_name = if &name == linkage_name { "" } else { linkage_name }; + + let scope_line = loc.line; + + let mut flags = DIFlags::FlagPrototyped; + if fn_abi.ret.layout.is_uninhabited() { + flags |= DIFlags::FlagNoReturn; + } + + // No SPFlagDefinition -- this is a declaration only. + let mut spflags = DISPFlags::SPFlagZero; + if self.sess().opts.optimize != config::OptLevel::No { + spflags |= DISPFlags::SPFlagOptimized; + } + + let template_parameters = create_DIArray(DIB(self), &[]); + + unsafe { + llvm::LLVMRustDIBuilderCreateFunction( + DIB(self), + scope, + name.as_c_char_ptr(), + name.len(), + linkage_name.as_c_char_ptr(), + linkage_name.len(), + file_metadata, + loc.line, + function_type_metadata, + scope_line, + flags, + spflags, + llfn, + template_parameters, + None, + ); + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1a60b59a93525..514326311f4c1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1901,7 +1901,7 @@ unsafe extern "C" { Length: size_t, ) -> &'ll Metadata; - pub(crate) fn LLVMDIBuilderCreateGlobalVariableExpression<'ll>( + pub(crate) fn LLVMRustDIBuilderCreateGlobalVariableExpression<'ll>( Builder: &DIBuilder<'ll>, Scope: Option<&'ll Metadata>, Name: *const c_uchar, // See "PTR_LEN_STR". @@ -1912,6 +1912,7 @@ unsafe extern "C" { LineNo: c_uint, Ty: &'ll Metadata, LocalToUnit: llvm::Bool, + IsDefined: llvm::Bool, Expr: &'ll Metadata, Decl: Option<&'ll Metadata>, AlignInBits: u32, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 983a506bd4ac6..5c0edde77e63f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1071,6 +1071,22 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod( return wrap(Sub); } +// Wraps DIBuilder::createGlobalVariableExpression. Unlike the LLVM-C API +// (LLVMDIBuilderCreateGlobalVariableExpression), this exposes the IsDefined +// parameter instead of hard-coding it to true. +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateGlobalVariableExpression( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *Linkage, size_t LinkLen, LLVMMetadataRef File, + unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, + LLVMBool IsDefined, LLVMMetadataRef Expr, LLVMMetadataRef Decl, + uint32_t AlignInBits) { + return wrap(unwrap(Builder)->createGlobalVariableExpression( + unwrapDI(Scope), {Name, NameLen}, {Linkage, LinkLen}, + unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, + IsDefined, unwrap(Expr), unwrapDI(Decl), nullptr, + AlignInBits)); +} + extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, diff --git a/tests/codegen-llvm/bpf-extern-debuginfo.rs b/tests/codegen-llvm/bpf-extern-debuginfo.rs new file mode 100644 index 0000000000000..a038e06ea05c9 --- /dev/null +++ b/tests/codegen-llvm/bpf-extern-debuginfo.rs @@ -0,0 +1,35 @@ +// Checks that BPF extern declarations are emitted as debug info declarations. +// +//@ only-bpf +//@ needs-llvm-components: bpf +//@ compile-flags: --target bpfel-unknown-none -C debuginfo=2 + +#![no_std] +#![no_main] +#![crate_type = "lib"] + +extern "C" { + // CHECK: !DIGlobalVariable(name: "KERNEL_VERSION" + // CHECK-SAME: isLocal: false + // CHECK-SAME: isDefinition: false + #[link_section = ".ksyms"] + pub static KERNEL_VERSION: u64; +} + +extern "C" { + // CHECK: !DISubprogram(name: "bpf_kfunc" + // CHECK-SAME: flags: DIFlagPrototyped + // CHECK-NOT: DISPFlagDefinition + #[link_section = ".ksyms"] + pub fn bpf_kfunc(x: u64) -> u64; +} + +#[no_mangle] +pub fn test_extern_items() -> u64 { + unsafe { KERNEL_VERSION + bpf_kfunc(42) } +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/codegen-llvm/extern-no-debuginfo-non-bpf.rs b/tests/codegen-llvm/extern-no-debuginfo-non-bpf.rs new file mode 100644 index 0000000000000..82c12797c39bd --- /dev/null +++ b/tests/codegen-llvm/extern-no-debuginfo-non-bpf.rs @@ -0,0 +1,24 @@ +// Checks that extern declarations do not get debug info outside BPF targets. +// +//@ compile-flags: -C debuginfo=2 + +#![crate_type = "lib"] + +extern "C" { + // CHECK: @EXTERN_STATIC = external {{.*}}global i32 + // CHECK-NOT: !DIGlobalVariable(name: "EXTERN_STATIC" + pub static EXTERN_STATIC: i32; +} + +extern "C" { + // CHECK: declare {{.*}}void @extern_fn() + // CHECK-NOT: !DISubprogram(name: "extern_fn" + pub fn extern_fn(); +} + +pub fn use_extern_items() -> i32 { + unsafe { + extern_fn(); + EXTERN_STATIC + } +} diff --git a/tests/codegen-llvm/link-section-foreign.rs b/tests/codegen-llvm/link-section-foreign.rs new file mode 100644 index 0000000000000..415cd95c271ba --- /dev/null +++ b/tests/codegen-llvm/link-section-foreign.rs @@ -0,0 +1,35 @@ +// Verifies that #[link_section] works on foreign (extern) items. +// This is only supported on BPF targets. +// +//@ only-bpf +//@ needs-llvm-components: bpf +//@ compile-flags: --target bpfel-unknown-none -C no-prepopulate-passes + +#![no_std] +#![no_main] +#![crate_type = "lib"] + +extern "C" { + // CHECK: @EXTERN_STATIC = external global i32, section ".ksyms" + #[link_section = ".ksyms"] + pub static EXTERN_STATIC: i32; +} + +extern "C" { + // CHECK: declare {{.*}}void @extern_fn(){{.*}} section ".ksyms" + #[link_section = ".ksyms"] + pub fn extern_fn(); +} + +#[no_mangle] +pub fn use_extern_items() -> i32 { + unsafe { + extern_fn(); + EXTERN_STATIC + } +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/attributes/attr-on-mac-call.stderr b/tests/ui/attributes/attr-on-mac-call.stderr index 3454998af2922..8d28d790188a5 100644 --- a/tests/ui/attributes/attr-on-mac-call.stderr +++ b/tests/ui/attributes/attr-on-mac-call.stderr @@ -129,7 +129,7 @@ warning: the `link_section` attribute cannot be used on macro calls LL | #[link_section = "__TEXT,__text"] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr index b5452ba2882c0..f3fc7041e03c5 100644 --- a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr @@ -26,7 +26,7 @@ error: the `link_section` attribute cannot be used on required trait methods LL | #[link_section = "__TEXT,__text"] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions with a body and statics + = help: the `link_section` attribute can be applied to foreign functions, foreign statics, functions with a body, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: aborting due to 3 previous errors diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr index f21c791cdf7f4..f3fed3d18820a 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr @@ -180,7 +180,7 @@ warning: the `link_section` attribute cannot be used on structs LL | #[cfg_attr(true, link_section)] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index a677339551153..07bf48bb5e942 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -284,7 +284,7 @@ warning: the `link_section` attribute cannot be used on crates LL | #![link_section = ",1800"] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `must_use` attribute cannot be used on crates @@ -876,7 +876,7 @@ warning: the `link_section` attribute cannot be used on modules LL | #[link_section = ",1800"] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link_section` attribute cannot be used on modules @@ -885,7 +885,7 @@ warning: the `link_section` attribute cannot be used on modules LL | mod inner { #![link_section=",1800"] } | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link_section` attribute cannot be used on structs @@ -894,7 +894,7 @@ warning: the `link_section` attribute cannot be used on structs LL | #[link_section = ",1800"] struct S; | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link_section` attribute cannot be used on type aliases @@ -903,7 +903,7 @@ warning: the `link_section` attribute cannot be used on type aliases LL | #[link_section = ",1800"] type T = S; | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link_section` attribute cannot be used on inherent impl blocks @@ -912,7 +912,7 @@ warning: the `link_section` attribute cannot be used on inherent impl blocks LL | #[link_section = ",1800"] impl S { } | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link_section` attribute cannot be used on traits @@ -921,7 +921,7 @@ warning: the `link_section` attribute cannot be used on traits LL | #[link_section = ",1800"] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions and statics + = help: the `link_section` attribute can be applied to foreign statics, functions, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link` attribute cannot be used on modules @@ -1598,7 +1598,7 @@ warning: the `link_section` attribute cannot be used on required trait methods LL | #[link_section = ",1800"] | ^^^^^^^^^^^^ | - = help: the `link_section` attribute can be applied to functions with a body and statics + = help: the `link_section` attribute can be applied to foreign functions, foreign statics, functions with a body, and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: 171 warnings emitted diff --git a/tests/ui/linkage-attr/link-section-foreign-bpf-only.rs b/tests/ui/linkage-attr/link-section-foreign-bpf-only.rs new file mode 100644 index 0000000000000..bd2d769d6e405 --- /dev/null +++ b/tests/ui/linkage-attr/link-section-foreign-bpf-only.rs @@ -0,0 +1,25 @@ +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +extern "C" { + #[unsafe(link_section = ".ksyms")] + //~^ ERROR `link_section` on foreign items is only supported on BPF targets + static foo: u32; + + #[unsafe(link_section = ".ksyms")] + //~^ ERROR `link_section` on foreign items is only supported on BPF targets + fn bar(); +} + +#[unsafe(link_section = ".text")] +fn regular_fn() {} + +#[unsafe(link_section = ".data")] +static BAZ: u32 = 42; diff --git a/tests/ui/linkage-attr/link-section-foreign-bpf-only.stderr b/tests/ui/linkage-attr/link-section-foreign-bpf-only.stderr new file mode 100644 index 0000000000000..8bf61ec9eed52 --- /dev/null +++ b/tests/ui/linkage-attr/link-section-foreign-bpf-only.stderr @@ -0,0 +1,14 @@ +error: `link_section` on foreign items is only supported on BPF targets + --> $DIR/link-section-foreign-bpf-only.rs:12:5 + | +LL | #[unsafe(link_section = ".ksyms")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `link_section` on foreign items is only supported on BPF targets + --> $DIR/link-section-foreign-bpf-only.rs:16:5 + | +LL | #[unsafe(link_section = ".ksyms")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +