[PATCH] Rust: backend: Add proper handling for #[used] attribute.
Arthur Cohen
arthur.cohen@opensrcsec.com
Wed Sep 16 14:30:32 GMT 2026
Updated version with a better testcase that doesn't fail on platforms
using an older linker.
Thanks and thanks to the rustc_codegen_gcc team for reviewing it and
ACKing it :)
Best,
Arthur
---
From 31b188a0396c25cfca9f152f3a58d8188ab4274e Mon Sep 17 00:00:00 2001
From: Arthur Cohen <arthur.cohen@opensrcsec.com>
Date: Wed, 16 Sep 2026 05:02:30 +0200
Subject: [PATCH] backend: Add proper handling for #[used] attribute.
We now support the full implementation of the #[used] attribute, which
can be used to conserve a static variable even if the compiler deems it
unused. This commit also implements #[used(linker)], which instructs the
linker to not garbage collect the static even if it seems unused.
This behavior is equivalent to the `used` and `retain` attributes in C.
gcc/rust/ChangeLog:
* backend/rust-compile-item.cc (handle_used_attr): New function.
(CompileItem::visit): Call it.
gcc/testsuite/ChangeLog:
* rust/compile/used-attr4.rs: New test.
---
gcc/rust/backend/rust-compile-item.cc | 61 ++++++++++++++++++------
gcc/testsuite/rust/compile/used-attr4.rs | 16 +++++++
2 files changed, 63 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/used-attr4.rs
diff --git a/gcc/rust/backend/rust-compile-item.cc
b/gcc/rust/backend/rust-compile-item.cc
index fa1e8eec99f..d9afdcacc3c 100644
--- a/gcc/rust/backend/rust-compile-item.cc
+++ b/gcc/rust/backend/rust-compile-item.cc
@@ -23,10 +23,53 @@
#include "rust-substitution-mapper.h"
#include "rust-type-util.h"
#include "rust-finalized-name-resolution-context.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "target.h"
namespace Rust {
namespace Compile {
+static void
+handle_used_attr (HIR::StaticItem &var, tree decl)
+{
+ auto used_compiler = false; /* equivalent to C's used attribute */
+ auto used_linker = false; /* equivalent to C's retain attribute */
+
+ // If the attribute has no argument, then it is equivalent to
`used(compiler)`
+ for (const auto &attr : var.get_outer_attrs ())
+ {
+ if (attr.as_string () == "used")
+ used_compiler = true;
+
+ // We've already checked that the attribute was used properly, so
just
+ // fetch the information we need
+ if (attr.has_attr_input ())
+ {
+ auto input
+ = static_cast<const AST::DelimTokenTree &> (attr.get_attr_input ())
+ .parse_to_meta_item ();
+
+ for (const auto &item : input->get_items ())
+ if (item->as_string () == "linker")
+ used_linker = true;
+ }
+ }
+
+ if (used_compiler)
+ {
+ DECL_PRESERVE_P (decl) = 1;
+ DECL_READ_P (decl) = 1;
+ }
+
+ // Check that the linker supports the attribute, and then add it
+ if (SUPPORTS_SHF_GNU_RETAIN && used_linker)
+ {
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (get_identifier ("retain"), NULL, DECL_ATTRIBUTES (decl));
+ }
+}
+
void
CompileItem::visit (HIR::StaticItem &var)
{
@@ -71,24 +114,14 @@ CompileItem::visit (HIR::StaticItem &var)
bool is_hidden = false;
bool in_unique_section = true;
- // NOTE: We currently compile global variables and always mark them
as "used"
- // with TREE_USED(tree). I'm not sure this is correct - they should
be marked
- // as used only if the `MarkLive` pass reaches them and flags them.
However,
- // the `#[used]` built-in attribute can be used here to *force* a static
- // variable to be used by the compiler so that it isn't deleted.
- // We should probably be doing something along the lines of:
- //
- // - Removing the `TREE_USED (decl) = 1` line in
`Backend::global_variable`
- // - Check if the static item has a `used` attribute
- // - If it does, check whether it's the default `used` version, or
the version
- // with an argument - `used(compiler)` or `used(linker)`
- // - If we have the attribute or the `compiler` version of the
attribute, then
- // we `TREE_USED` the decl.
-
Bvariable *static_global
= Backend::global_variable (name, asm_name, type, is_external,
is_hidden,
in_unique_section, var.get_locus ());
+ // Static items are concerned by the #[used] attribute which needs to be
+ // handled here
+ handle_used_attr (var, static_global->get_decl ());
+
tree init = value == error_mark_node ? error_mark_node :
DECL_INITIAL (value);
Backend::global_variable_set_init (static_global, init);
diff --git a/gcc/testsuite/rust/compile/used-attr4.rs
b/gcc/testsuite/rust/compile/used-attr4.rs
new file mode 100644
index 00000000000..18078a8ca1f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/used-attr4.rs
@@ -0,0 +1,16 @@
+#![feature(no_core)]
+#![feature(used_with_arg)]
+#![no_core]
+
+#[used]
+static FOO0: i32 = 15;
+// { dg-final { scan-assembler "FOO0" } }
+
+#[used(compiler)]
+static FOO1: i32 = 15;
+// { dg-final { scan-assembler "FOO1" } }
+
+#[used(linker)]
+static FOO2: i32 = 15;
+// { dg-final { scan-assembler "FOO2" } }
+// { dg-final { scan-assembler ".section.*awR" { target gnu_retain } } }
--
2.50.1
More information about the Gcc-rust
mailing list