https://gcc.gnu.org/g:cc7611b3bbe09e9b205936d8cb82ea9c47123231
commit r17-5431-gcc7611b3bbe09e9b205936d8cb82ea9c47123231 Author: Arthur Cohen <[email protected]> Date: Thu Sep 3 05:36:06 2026 +0200 gccrs: attr: Allow `#[used]` attribute and its argument variant. This commit allows recognizing both forms of the `#[used]` attribute: The basic one, which forbids any argument, and the one gated behind `feature(used_with_arg)`, which allows specifying whether the compiler or linker should be responsible for marking the static item as used. This does not do anything in the backend for actually marking the item as used even if the compiler decides it should not be used. This is a first step towards handling it as the kernel requires it. gcc/rust/ChangeLog: * checks/errors/feature/rust-feature-defs-rfl.h (FEATURE_ACTIVE): Add `used_with_arg` feature. * checks/errors/feature/rust-feature-gate.cc (FeatureGate::check_used_attribute): New function. (FeatureGate::visit): Implement feature gating visits for static items. * checks/errors/feature/rust-feature-gate.h: Declare them. * checks/errors/rust-builtin-attribute-checker.cc (used): New handler. (check_valid_attribute_for_item): Handle `used` attribute for static items. * util/rust-attribute-values.h: Add new attribute value for `used`. * util/rust-attributes.cc: Likewise. * backend/rust-compile-item.cc (CompileItem::visit): Add note about implementing the `#[used]` attribute properly in our backend. gcc/testsuite/ChangeLog: * rust/compile/used-attr1.rs: New test. * rust/compile/used-attr2.rs: New test. * rust/compile/used-attr3.rs: New test. Diff: --- gcc/rust/backend/rust-compile-item.cc | 14 +++++++ .../checks/errors/feature/rust-feature-defs-rfl.h | 3 ++ .../checks/errors/feature/rust-feature-gate.cc | 17 ++++++++ gcc/rust/checks/errors/feature/rust-feature-gate.h | 2 + .../errors/rust-builtin-attribute-checker.cc | 48 +++++++++++++++++++++- gcc/rust/util/rust-attribute-values.h | 1 + gcc/rust/util/rust-attributes.cc | 3 +- gcc/testsuite/rust/compile/used-attr1.rs | 5 +++ gcc/testsuite/rust/compile/used-attr2.rs | 11 +++++ gcc/testsuite/rust/compile/used-attr3.rs | 15 +++++++ gcc/testsuite/rust/compile/used-attr5.rs | 5 +++ 11 files changed, 121 insertions(+), 3 deletions(-) diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 2d23aa62cdd0..1fad40104fa1 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -71,6 +71,20 @@ 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 ()); diff --git a/gcc/rust/checks/errors/feature/rust-feature-defs-rfl.h b/gcc/rust/checks/errors/feature/rust-feature-defs-rfl.h index 288ffc862929..03f54dff6a43 100644 --- a/gcc/rust/checks/errors/feature/rust-feature-defs-rfl.h +++ b/gcc/rust/checks/errors/feature/rust-feature-defs-rfl.h @@ -26,3 +26,6 @@ FEATURE_ACTIVE ("extended_key_value_attributes", EXTENDED_KEY_VALUE_ATTRIBUTES, "1.50.0", ISSUE_SOME (78835), EDITION_NONE) FEATURE_ACTIVE ("cfi_encoding", CFI_ENCODING, "1.71.0", ISSUE_SOME (89653), EDITION_NONE) +// FIXME: We need to enable this when the compatibility mode is >= 1.60 I guess? +FEATURE_ACTIVE ("used_with_arg", USED_WITH_ARG, "1.60.0", ISSUE_SOME (93798), + EDITION_NONE) diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.cc b/gcc/rust/checks/errors/feature/rust-feature-gate.cc index 6b481fafa177..f3216532734c 100644 --- a/gcc/rust/checks/errors/feature/rust-feature-gate.cc +++ b/gcc/rust/checks/errors/feature/rust-feature-gate.cc @@ -123,6 +123,15 @@ FeatureGate::visit (AST::ExternBlock &block) AST::DefaultASTVisitor::visit (block); } +void +FeatureGate::check_used_attribute (const AST::Attribute &attribute) +{ + if (attribute.get_path ().as_string () == Values::Attributes::USED) + if (attribute.has_attr_input ()) + gate (Feature::Name::USED_WITH_ARG, attribute.get_locus (), + "malformed #[used] attribute input"); +} + void FeatureGate::check_no_core_attribute (const AST::Attribute &attribute) { @@ -367,6 +376,14 @@ FeatureGate::visit (AST::EnumItem &enum_variant) check_lang_item_attribute (enum_variant.get_outer_attrs ()); AST::DefaultASTVisitor::visit (enum_variant); } +void +FeatureGate::visit (AST::StaticItem &static_item) +{ + for (const auto &attr : static_item.get_outer_attrs ()) + check_used_attribute (attr); + + AST::DefaultASTVisitor::visit (static_item); +} void FeatureGate::visit (AST::Attribute &attr) diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.h b/gcc/rust/checks/errors/feature/rust-feature-gate.h index e74a98605acf..e83a14ea78ca 100644 --- a/gcc/rust/checks/errors/feature/rust-feature-gate.h +++ b/gcc/rust/checks/errors/feature/rust-feature-gate.h @@ -51,6 +51,7 @@ public: void visit (AST::TraitItemType &trait_item_type) override; void visit (AST::Enum &enum_item) override; void visit (AST::EnumItem &enum_variant) override; + void visit (AST::StaticItem &static_item) override; void visit (AST::Attribute &attr) override; @@ -65,6 +66,7 @@ public: private: void check_no_core_attribute (const AST::Attribute &attribute); + void check_used_attribute (const AST::Attribute &attribute); void check_rustc_attri (const std::vector<AST::Attribute> &attributes); void check_may_dangle_attribute (const std::vector<AST::Attribute> &attributes); diff --git a/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc b/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc index d8a9bb0fb885..f054fae7ba80 100644 --- a/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc +++ b/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc @@ -354,6 +354,47 @@ target_feature (const AST::Attribute &attribute) } } +static void +used (const AST::Attribute &attribute) +{ + auto is_invalid = false; + if (attribute.has_attr_input ()) + { + switch (attribute.get_attr_input ().get_attr_input_type ()) + { + case AST::AttrInput::TOKEN_TREE: + { + auto input = static_cast<const AST::DelimTokenTree &> ( + attribute.get_attr_input ()) + .parse_to_meta_item (); + + for (const auto &item : input->get_items ()) + { + if (item->as_string () != "compiler" + && item->as_string () != "linker") + is_invalid = true; + } + } + + break; + case AST::AttrInput::EXPR: + case AST::AttrInput::LITERAL: + case AST::AttrInput::META_ITEM: + is_invalid = true; + break; + } + } + + if (is_invalid) + { + rust_error_at (attribute.get_locus (), + "malformed %<used%> attribute input"); + rust_inform (attribute.get_locus (), + "must be of the form: %<#[used(compiler)]%> or " + "%<#[used(linker)]%>"); + } +} + void expect_no_input (const AST::Attribute &attribute) { @@ -385,6 +426,7 @@ const std::unordered_map<std::string, std::function<void (AST::Attribute &)>> {Attrs::PROC_MACRO, handlers::proc_macro}, {Attrs::PROC_MACRO_ATTRIBUTE, handlers::proc_macro}, {Attrs::TARGET_FEATURE, handlers::target_feature}, + {Attrs::USED, handlers::used}, {Attrs::RUSTC_STD_INTERNAL_SYMBOL, handlers::expect_no_input}, {Attrs::RUSTC_ALLOCATOR, handlers::expect_no_input}, {Attrs::RUSTC_ALLOCATOR_NOUNWIND, handlers::expect_no_input}, @@ -443,8 +485,10 @@ check_valid_attribute_for_item (const AST::Attribute &attr, "to structs, enums and unions", attr.get_path ().as_string ().c_str ()); } - else if (attr.get_path () == Values::Attributes::GLOBAL_ALLOCATOR - && item.get_item_kind () != AST::Item::Kind::StaticItem) + else if (item.get_item_kind () != AST::Item::Kind::StaticItem + && (attr.get_path () == Values::Attributes::GLOBAL_ALLOCATOR + || attr.get_path () == Values::Attributes::USED)) + { rust_error_at (attr.get_locus (), "the %<#[%s]%> attribute may only be applied " diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index f4409e1fa06b..e42a67296033 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -127,6 +127,7 @@ public: = "rustc_conversion_suggestion"; static constexpr auto &CFI_ENCODING = "cfi_encoding"; + static constexpr auto &USED = "used"; }; } // namespace Values } // namespace Rust diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index 58c789fd1592..634f0c3caedd 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -105,7 +105,8 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::RUSTC_ALLOCATOR_NOUNWIND, CODE_GENERATION}, {Attrs::GLOBAL_ALLOCATOR, CODE_GENERATION}, {Attrs::RUSTC_CONVERSION_SUGGESTION, TYPE_CHECK}, - {Attrs::CFI_ENCODING, CODE_GENERATION}}; + {Attrs::CFI_ENCODING, CODE_GENERATION}, + {Attrs::USED, CODE_GENERATION}}; static const std::set<std::string> __outer_attributes = {Attrs::INLINE, diff --git a/gcc/testsuite/rust/compile/used-attr1.rs b/gcc/testsuite/rust/compile/used-attr1.rs new file mode 100644 index 000000000000..218c4dd52225 --- /dev/null +++ b/gcc/testsuite/rust/compile/used-attr1.rs @@ -0,0 +1,5 @@ +#![feature(no_core)] +#![no_core] + +#[used] +static STAT0: i32 = 15; diff --git a/gcc/testsuite/rust/compile/used-attr2.rs b/gcc/testsuite/rust/compile/used-attr2.rs new file mode 100644 index 000000000000..52c9122cea9d --- /dev/null +++ b/gcc/testsuite/rust/compile/used-attr2.rs @@ -0,0 +1,11 @@ +#![feature(no_core)] +#![no_core] + +#[used] +static STAT0: i32 = 15; + +#[used(compiler)] // { dg-error "malformed ..used. attribute input" } +static STAT1: i32 = 15; + +#[used(linker)] // { dg-error "malformed ..used. attribute input" } +static STAT2: i32 = 15; diff --git a/gcc/testsuite/rust/compile/used-attr3.rs b/gcc/testsuite/rust/compile/used-attr3.rs new file mode 100644 index 000000000000..b339419135a6 --- /dev/null +++ b/gcc/testsuite/rust/compile/used-attr3.rs @@ -0,0 +1,15 @@ +#![feature(no_core)] +#![no_core] +#![feature(used_with_arg)] + +#[used] +static STAT0: i32 = 15; + +#[used(compiler)] +static STAT1: i32 = 15; + +#[used(linker)] +static STAT2: i32 = 15; + +#[used(assembler)] // { dg-error "malformed .used. attribute input" } +static STAT3: i32 = 15; diff --git a/gcc/testsuite/rust/compile/used-attr5.rs b/gcc/testsuite/rust/compile/used-attr5.rs new file mode 100644 index 000000000000..1606530ebed5 --- /dev/null +++ b/gcc/testsuite/rust/compile/used-attr5.rs @@ -0,0 +1,5 @@ +#![feature(no_core)] +#![no_core] + +#[used] // { dg-error "may only be applied to static items" } +pub fn foo() {}
