From: Arthur Cohen <[email protected]>

Tool attributes are allowed in Rust code, and should be ignored by the
compiler and handled by the specified tools instead.

gcc/rust/ChangeLog:

        * util/rust-attributes.h: Change Attributes::is_known API to return an 
enum, add
        AttributeKnowledge result enum.
        * util/rust-attribute-values.h: Add more known tool attributes.
        * util/rust-attributes.cc (Attributes::is_known): Check for tool 
attributes and
        adapt return type.
        * hir/rust-ast-lower-base.cc 
(ASTLoweringBase::handle_outer_attributes): Use new
        API and ignore tool attributes.
        * resolve/rust-early-name-resolver-2.0.cc (Early::visit): Likewise.

gcc/testsuite/ChangeLog:

        * rust/compile/tool-attribute1.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/95197bbf4951b8e5a823ffecf5e428b35e516e12

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/4752

 gcc/rust/hir/rust-ast-lower-base.cc           |  8 ++++-
 .../resolve/rust-early-name-resolver-2.0.cc   | 16 ++++++----
 gcc/rust/util/rust-attribute-values.h         |  4 +++
 gcc/rust/util/rust-attributes.cc              | 31 +++++++++++++++++--
 gcc/rust/util/rust-attributes.h               | 19 +++++++++++-
 gcc/testsuite/rust/compile/tool-attribute1.rs | 22 +++++++++++++
 6 files changed, 90 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/tool-attribute1.rs

diff --git a/gcc/rust/hir/rust-ast-lower-base.cc 
b/gcc/rust/hir/rust-ast-lower-base.cc
index 0de6ace8a..a4ab5d5ed 100644
--- a/gcc/rust/hir/rust-ast-lower-base.cc
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -797,13 +797,19 @@ ASTLoweringBase::handle_outer_attributes (const 
ItemWrapper &item)
   for (const auto &attr : item.get_outer_attrs ())
     {
       const auto &str_path = attr.get_path ().as_string ();
-      if (!Analysis::Attributes::is_known (str_path))
+      auto known_check = Analysis::Attributes::is_known (str_path);
+      if (known_check == Analysis::Attributes::AttributeKnowledge::Unknown)
        {
          rust_error_at (attr.get_locus (), "unknown attribute: %qs",
                         str_path.c_str ());
          continue;
        }
 
+      // If it is a tool attribute, the compiler can ignore it and let the tool
+      // handle it
+      if (known_check == Analysis::Attributes::AttributeKnowledge::Tool)
+       return;
+
       bool is_lang_item = str_path == Values::Attributes::LANG
                          && attr.has_attr_input ()
                          && attr.get_attr_input ().get_attr_input_type ()
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index 830932cdd..8a07f8f29 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -454,17 +454,21 @@ Early::visit (AST::Attribute &attr)
   auto &mappings = Analysis::Mappings::get ();
 
   auto name = attr.get_path ().get_segments ().at (0).get_segment_name ();
-  auto is_not_builtin = [&name] (AST::Attribute &attr) {
-    return Analysis::BuiltinAttributeMappings::get ()
-      ->lookup_builtin (name)
-      .is_error ();
-  };
+  auto known_check = Analysis::Attributes::is_known (name);
+
+  // If it is a tool attribute, the compiler can ignore it and let the tool
+  // handle it
+  if (known_check == Analysis::Attributes::AttributeKnowledge::Tool)
+    return;
+
+  auto is_builtin
+    = known_check == Analysis::Attributes::AttributeKnowledge::Known;
 
   if (attr.is_derive ())
     {
       visit_derive_attribute (attr, mappings);
     }
-  else if (is_not_builtin (attr)) // Do not resolve builtins
+  else if (!is_builtin) // Do not resolve builtins
     {
       visit_non_builtin_attribute (attr, mappings, name);
     }
diff --git a/gcc/rust/util/rust-attribute-values.h 
b/gcc/rust/util/rust-attribute-values.h
index 3ab91d35f..e2718ca4a 100644
--- a/gcc/rust/util/rust-attribute-values.h
+++ b/gcc/rust/util/rust-attribute-values.h
@@ -105,6 +105,10 @@ public:
   static constexpr auto &NON_EXHAUSTIVE = "non_exhaustive";
 
   static constexpr auto &RUSTFMT = "rustfmt";
+  static constexpr auto &CLIPPY = "clippy";
+  static constexpr auto &DIAGNOSTIC = "diagnostic";
+  static constexpr auto &MIRI = "miri";
+  static constexpr auto &RUST_ANALYZER = "rust_analyzer";
 
   static constexpr auto &TEST = "test";
 
diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc
index 2ae917fdb..8ab4bc608 100644
--- a/gcc/rust/util/rust-attributes.cc
+++ b/gcc/rust/util/rust-attributes.cc
@@ -94,6 +94,10 @@ static const BuiltinAttrDefinition __definitions[]
      {Attrs::FUNDAMENTAL, TYPE_CHECK},
      {Attrs::NON_EXHAUSTIVE, TYPE_CHECK},
      {Attrs::RUSTFMT, EXTERNAL},
+     {Attrs::CLIPPY, EXTERNAL},
+     {Attrs::DIAGNOSTIC, EXTERNAL},
+     {Attrs::MIRI, EXTERNAL},
+     {Attrs::RUST_ANALYZER, EXTERNAL},
      {Attrs::TEST, CODE_GENERATION},
      {Attrs::NEEDS_ALLOCATOR, CODE_GENERATION},
      {Attrs::RUSTC_ALLOCATOR, CODE_GENERATION},
@@ -120,13 +124,36 @@ static const std::set<std::string> __outer_attributes
      Attrs::LINK_NAME,
      Attrs::LINK_SECTION};
 
-bool
+Attributes::AttributeKnowledge
 Attributes::is_known (const std::string &attribute_path)
 {
   const auto &lookup
     = BuiltinAttributeMappings::get ()->lookup_builtin (attribute_path);
 
-  return !lookup.is_error ();
+  if (!lookup.is_error ())
+    return AttributeKnowledge::Known;
+
+  // We have to check for tool attributes as well
+  // https://doc.rust-lang.org/reference/attributes.html#tool-attributes
+  //
+  // > rustc currently recognizes the tools “clippy”, “rustfmt”, “diagnostic”,
+  // “miri”, and “rust_analyzer”.
+  static std::unordered_set<std::string> known_tools = {
+    "clippy", "rustfmt", "diagnostic", "miri", "rust_analyzer",
+  };
+
+  auto colon = attribute_path.find ("::");
+  if (colon != std::string::npos)
+    {
+      auto tool = attribute_path.substr (0, colon);
+
+      // If this is a known tool, the attribute is "known". The rest of the 
path
+      // is up to the tool to interpret.
+      if (known_tools.find (tool) != known_tools.end ())
+       return AttributeKnowledge::Tool;
+    }
+
+  return AttributeKnowledge::Unknown;
 }
 
 bool
diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h
index 778cc9e33..c173a3f76 100644
--- a/gcc/rust/util/rust-attributes.h
+++ b/gcc/rust/util/rust-attributes.h
@@ -27,7 +27,24 @@ namespace Analysis {
 class Attributes
 {
 public:
-  static bool is_known (const std::string &attribute_path);
+  enum class AttributeKnowledge
+  {
+    /**
+     * Built-in attribute
+     */
+    Known,
+    /**
+     * Tool attribute, to be handled by the specified tool rather than the
+     * compiler
+     */
+    Tool,
+    /**
+     * Unknown attribute
+     */
+    Unknown,
+  };
+
+  static AttributeKnowledge is_known (const std::string &attribute_path);
   static bool valid_outer_attribute (const std::string &attribute_path);
   static tl::optional<std::string>
   extract_string_literal (const AST::Attribute &attr);
diff --git a/gcc/testsuite/rust/compile/tool-attribute1.rs 
b/gcc/testsuite/rust/compile/tool-attribute1.rs
new file mode 100644
index 000000000..f8f198f50
--- /dev/null
+++ b/gcc/testsuite/rust/compile/tool-attribute1.rs
@@ -0,0 +1,22 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![feature(rustc_attrs)]
+#![no_core]
+
+#[rustfmt::skip]
+pub fn foo() {}
+
+#[clippy::something::useful]
+#[diagnostic::diagnose_this]
+struct Boo;
+
+#[miri::save_us_all]
+unsafe fn scary() {}
+
+#[rust_analyzer::vade_retro]
+unsafe fn stannanas() {}
+
+#[not_a_tool::but_still_tool_like]
+// { dg-error "macro not found" "" { target *-*-* } .-1 }
+// { dg-error "could not resolve attribute macro invocation" "" { target *-*-* 
} .-2 }
+pub fn ha_exclam() {}
-- 
2.54.0

Reply via email to