From: Arthur Cohen <[email protected]>

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.
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/9de77c038fcdc0a111c7534afad187bb98a4f251

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4837

 gcc/rust/backend/rust-compile-item.cc         | 14 ++++++
 .../errors/feature/rust-feature-defs-rfl.h    |  3 ++
 .../errors/feature/rust-feature-gate.cc       | 17 +++++++
 .../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(-)
 create mode 100644 gcc/testsuite/rust/compile/used-attr1.rs
 create mode 100644 gcc/testsuite/rust/compile/used-attr2.rs
 create mode 100644 gcc/testsuite/rust/compile/used-attr3.rs
 create mode 100644 gcc/testsuite/rust/compile/used-attr5.rs

diff --git a/gcc/rust/backend/rust-compile-item.cc 
b/gcc/rust/backend/rust-compile-item.cc
index 2d23aa62c..1fad40104 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 288ffc862..03f54dff6 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 6b481fafa..f32165327 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 e74a98605..e83a14ea7 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 d8a9bb0fb..f054fae7b 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 f4409e1fa..e42a67296 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 58c789fd1..634f0c3ca 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 000000000..218c4dd52
--- /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 000000000..52c9122ce
--- /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 000000000..b33941913
--- /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 000000000..1606530eb
--- /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() {}

base-commit: de7f21f662e95c55c840741aebb2db3e98dd6c45
-- 
2.55.0

Reply via email to