From 1cbccdd1e8dc39620ac1921798151428238a8677 Mon Sep 17 00:00:00 2001 From: Owen Avery Date: Sun, 14 Sep 2025 16:57:49 -0400 Subject: [PATCH] Handle link_name attribute gcc/rust/ChangeLog: * backend/rust-compile-extern.h: Add includes. (CompileExternItem::visit): Use get_link_name. (CompileExternItem::get_link_name): New static member function. * util/rust-attribute-values.h (Attributes::LINK_NAME): New static constexpr member variable. * util/rust-attributes.cc (__definitions): New entry for LINK_NAME. * util/rust-ggc.cc: Include "rust-ast.h". (Ident::Ident): Add overload for Rust::Identifier. * util/rust-ggc.h (class Identifier): Forward declare. (Ident::Ident): Add overload for Rust::Identifier. gcc/testsuite/ChangeLog: * rust/execute/torture/link-name.rs: New test. Signed-off-by: Owen Avery --- gcc/rust/backend/rust-compile-extern.h | 46 ++++++++++++++----- gcc/rust/util/rust-attribute-values.h | 1 + gcc/rust/util/rust-attributes.cc | 1 + gcc/rust/util/rust-ggc.cc | 3 ++ gcc/rust/util/rust-ggc.h | 4 ++ .../rust/execute/torture/link-name.rs | 16 +++++++ 6 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/link-name.rs diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h index d6aa5899f624..a78f9eeeefe2 100644 --- a/gcc/rust/backend/rust-compile-extern.h +++ b/gcc/rust/backend/rust-compile-extern.h @@ -24,6 +24,8 @@ #include "rust-compile-type.h" #include "rust-diagnostics.h" #include "rust-hir-full-decls.h" +#include "rust-attributes.h" +#include "rust-attribute-values.h" namespace Rust { namespace Compile { @@ -57,8 +59,7 @@ class CompileExternItem : public HIRCompileBase, rust_assert (ok); std::string name = item.get_item_name ().as_string (); - // FIXME this is assuming C ABI - std::string asm_name = name; + GGC::Ident asm_name = get_link_name (item); tree type = TyTyResolveCompile::compile (ctx, resolved_type); bool is_external = true; @@ -124,16 +125,7 @@ class CompileExternItem : public HIRCompileBase, tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype); std::string ir_symbol_name = function.get_item_name ().as_string (); - std::string asm_name = function.get_item_name ().as_string (); - if (fntype->get_abi () == ABI::RUST) - { - // then we need to get the canonical path of it and mangle it - auto canonical_path = ctx->get_mappings ().lookup_canonical_path ( - function.get_mappings ().get_nodeid ()); - - ir_symbol_name = canonical_path->get () + fntype->subst_as_string (); - asm_name = ctx->mangle_item (fntype, *canonical_path); - } + GGC::Ident asm_name = get_link_name (function); const unsigned int flags = Backend::function_is_declaration; tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name, @@ -158,6 +150,36 @@ class CompileExternItem : public HIRCompileBase, ref_locus (ref_locus) {} + template static GGC::Ident get_link_name (T &obj) + { + AST::Attribute *use_attr = nullptr; + + for (auto &attr : obj.get_outer_attrs ()) + { + if (attr.get_path ().as_string () == Values::Attributes::LINK_NAME) + { + // later attributes override earlier ones + // TODO: add warning -- should duplicate + // attributes be folded elsewhere? + use_attr = &attr; + } + } + + if (use_attr) + { + auto link_name + = Analysis::Attributes::extract_string_literal (*use_attr); + + if (!link_name.has_value ()) + rust_error_at (use_attr->get_locus (), + "malformed % attribute input"); + else + return *link_name; + } + + return obj.get_item_name (); + } + TyTy::BaseType *concrete; tree reference; location_t ref_locus; diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index 3b09e8493d18..0f35f56f798e 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -36,6 +36,7 @@ class Attributes static constexpr auto &DOC = "doc"; static constexpr auto &MUST_USE = "must_use"; static constexpr auto &LANG = "lang"; + static constexpr auto &LINK_NAME = "link_name"; static constexpr auto &LINK_SECTION = "link_section"; static constexpr auto &NO_MANGLE = "no_mangle"; static constexpr auto &REPR = "repr"; diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index 716af3af699a..bd91fdd5d031 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -78,6 +78,7 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::DOC, HIR_LOWERING}, {Attrs::MUST_USE, STATIC_ANALYSIS}, {Attrs::LANG, HIR_LOWERING}, + {Attrs::LINK_NAME, CODE_GENERATION}, {Attrs::LINK_SECTION, CODE_GENERATION}, {Attrs::NO_MANGLE, CODE_GENERATION}, {Attrs::REPR, CODE_GENERATION}, diff --git a/gcc/rust/util/rust-ggc.cc b/gcc/rust/util/rust-ggc.cc index 0722af2b7188..46220a2acd80 100644 --- a/gcc/rust/util/rust-ggc.cc +++ b/gcc/rust/util/rust-ggc.cc @@ -17,6 +17,7 @@ // . #include "rust-ggc.h" +#include "rust-ast.h" #include "stringpool.h" namespace Rust { @@ -29,6 +30,8 @@ Ident::Ident (const std::string &str) : inner (get_identifier_with_length (str.c_str (), str.length ())) {} +Ident::Ident (const Rust::Identifier &ident) : Ident (ident.as_string ()) {} + bool Ident::operator== (const std::string &other) const { diff --git a/gcc/rust/util/rust-ggc.h b/gcc/rust/util/rust-ggc.h index da28edeffe0b..da4ede159850 100644 --- a/gcc/rust/util/rust-ggc.h +++ b/gcc/rust/util/rust-ggc.h @@ -24,6 +24,9 @@ namespace Rust { +// forward declare +class Identifier; + namespace GGC { class Ident @@ -33,6 +36,7 @@ class Ident public: Ident (const char *str); Ident (const std::string &str); + Ident (const Rust::Identifier &ident); bool operator== (const Ident &other) const { return inner == other.inner; } bool operator== (const std::string &other) const; diff --git a/gcc/testsuite/rust/execute/torture/link-name.rs b/gcc/testsuite/rust/execute/torture/link-name.rs new file mode 100644 index 000000000000..1ab1ac1b3515 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/link-name.rs @@ -0,0 +1,16 @@ +// { dg-additional-options "-fdump-rtl-final" } +// { dg-final { scan-rtl-dump "printf" "final" } } +// { dg-output "gcc\r*\n" } + +extern "C" { + #[link_name = "printf"] + fn druckt(fmt: *const i8, ...); +} + +fn main() -> i32 { + let a = "gcc\0"; + + unsafe { druckt("%s\n\0" as *const str as *const i8, a as *const str as *const i8); } + + 0 +}