diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 6ae4e31af9df9..544f5a6f43e7a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -474,6 +474,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", 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 3514fb145612a..c9055e13c8953 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -403,6 +403,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 c91d3ec63a028..3a8cd94d12c4f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1440,13 +1440,38 @@ 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; @@ -1464,12 +1489,6 @@ pub(crate) fn build_global_var_di_node<'ll>( 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); @@ -1489,6 +1508,7 @@ pub(crate) fn build_global_var_di_node<'ll>( line_number, type_di_node, is_local_to_unit, + is_definition, global, // (value) None, // (decl) Some(global_align), @@ -1767,6 +1787,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 c3fa86f8a2ad3..1d17027f2a198 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -30,10 +30,10 @@ use tracing::debug; use self::create_scope_map::compute_mir_scopes; 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; @@ -759,3 +759,88 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } } + +impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { + /// Creates a `DISubprogram` for a foreign function declaration (without `SPFlagDefinition`). + 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); + + // Foreign function declarations do not need the platform-specific + // adjustments used for regular function definitions. + 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; + } + + 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, // Attach to LLVM function if provided + template_parameters, + None, // No decl + ); + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index bc24f1692fcf2..33ea3561e6815 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1895,7 +1895,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". @@ -1906,6 +1906,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 f7fccf6296bd1..6c87b45b2c4b7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1147,6 +1147,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..6db13127bed95 --- /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-SAME: spFlags: DISPFlagZero + #[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..1b5193ed8dff0 --- /dev/null +++ b/tests/codegen-llvm/link-section-foreign.rs @@ -0,0 +1,26 @@ +// Verifies that #[link_section] works on foreign (extern) items. +// +//@ ignore-wasm32 custom sections work differently on wasm +//@ compile-flags: -C no-prepopulate-passes + +#![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(); +} + +// Ensure the extern items are used so they appear in the IR +pub fn use_extern_items() -> i32 { + unsafe { + extern_fn(); + EXTERN_STATIC + } +} diff --git a/tests/ui/attributes/attr-on-mac-call.stderr b/tests/ui/attributes/attr-on-mac-call.stderr index 3bb50f2d6f654..01833c38f1632 100644 --- a/tests/ui/attributes/attr-on-mac-call.stderr +++ b/tests/ui/attributes/attr-on-mac-call.stderr @@ -82,7 +82,7 @@ LL | #[link_section = "x"] | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_ordinal]` attribute cannot be used on macro calls --> $DIR/attr-on-mac-call.rs:33:5 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 0770ccae41469..10c6ceaf9afa0 100644 --- a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr @@ -19,7 +19,7 @@ LL | #[link_section = ".text"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks + = help: `#[link_section]` can be applied to foreign functions, foreign statics, functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks error: `#[linkage]` attribute cannot be used on required trait methods --> $DIR/codegen_attr_on_required_trait_method.rs:14:5 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 fd03fa62864af..c399077024609 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr @@ -143,7 +143,7 @@ LL | #[cfg_attr(true, link_section)] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics = note: requested on the command line with `-W unused-attributes` error: aborting due to 13 previous errors; 1 warning emitted 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 724d623e79eee..d9b6d1caa8003 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 @@ -870,7 +870,7 @@ LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_section]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:17 @@ -879,7 +879,7 @@ LL | mod inner { #![link_section="1800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_section]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:5 @@ -888,7 +888,7 @@ LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_section]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 @@ -897,7 +897,7 @@ LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_section]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5 @@ -906,7 +906,7 @@ LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_section]` attribute cannot be used on traits --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 @@ -915,7 +915,7 @@ LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[link_section]` attribute cannot be used on required trait methods --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:9 @@ -924,7 +924,7 @@ LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks + = help: `#[link_section]` can be applied to foreign functions, foreign statics, functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks warning: `#[must_use]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1 @@ -1574,7 +1574,7 @@ LL | #![link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to functions and statics + = help: `#[link_section]` can be applied to foreign statics, functions, and statics warning: `#[must_use]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:82:1