From: Enes Cevik <[email protected]>

This patch introduces the `rustc_allocator` and `rustc_allocator_nounwind`
attributes.
These attributes instruct the GCC backend to apply `malloc` and `nothrow`.

gcc/rust/ChangeLog:

        * backend/rust-compile-base.cc (HIRCompileBase::setup_fndecl): Dispatch 
the new
        attributes.
        (HIRCompileBase::handle_rustc_allocator_on_fndecl): New function.
        (HIRCompileBase::handle_rustc_allocator_nounwind_on_fndecl): New 
function.
        * backend/rust-compile-base.h (handle_rustc_allocator_on_fndecl): New 
declaration.
        (handle_rustc_allocator_nounwind_on_fndecl): Likewise.
        * util/rust-attribute-values.h (Attributes): Add RUSTC_ALLOCATOR and
        RUSTC_ALLOCATOR_NOUNWIND constexprs.
        * util/rust-attributes.cc (__definitions): Register rustc_allocator and
        rustc_allocator_nounwind in the BuiltinAttributes list.
        * checks/errors/rust-builtin-attribute-checker.cc (rustc_allocator): 
New function.
        (rustc_allocator_nounwind): New function.
        (attribute_checking_handlers): Add rustc_allocator and 
rustc_allocator_nounwind
        functions.

gcc/testsuite/ChangeLog:

        * rust/compile/attr-allocator1.rs: New test.
        * rust/compile/attr-allocator2.rs: New test.
        * rust/compile/attr-allocator3.rs: New test.

Signed-off-by: Enes Cevik <[email protected]>
---
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/7a4484b9258617de89901b0eaad22644f9bbff03

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

 gcc/rust/backend/rust-compile-base.cc         | 60 +++++++++++++++++++
 gcc/rust/backend/rust-compile-base.h          |  7 +++
 .../errors/rust-builtin-attribute-checker.cc  | 26 ++++++++
 gcc/rust/util/rust-attribute-values.h         |  3 +
 gcc/rust/util/rust-attributes.cc              |  4 +-
 gcc/testsuite/rust/compile/attr-allocator1.rs | 12 ++++
 gcc/testsuite/rust/compile/attr-allocator2.rs | 10 ++++
 gcc/testsuite/rust/compile/attr-allocator3.rs |  6 ++
 8 files changed, 127 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/rust/compile/attr-allocator1.rs
 create mode 100644 gcc/testsuite/rust/compile/attr-allocator2.rs
 create mode 100644 gcc/testsuite/rust/compile/attr-allocator3.rs

diff --git a/gcc/rust/backend/rust-compile-base.cc 
b/gcc/rust/backend/rust-compile-base.cc
index 1318b876e..54b531173 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -96,6 +96,9 @@ HIRCompileBase::setup_fndecl (tree fndecl, bool 
is_main_entry_point,
        = attr_str == Values::Attributes::PROC_MACRO_ATTRIBUTE;
       bool is_proc_macro_derive
        = attr_str == Values::Attributes::PROC_MACRO_DERIVE;
+      bool is_allocator = attr_str == Values::Attributes::RUSTC_ALLOCATOR;
+      bool is_allocator_nounwind
+       = attr_str == Values::Attributes::RUSTC_ALLOCATOR_NOUNWIND;
 
       if (is_inline)
        {
@@ -137,6 +140,14 @@ HIRCompileBase::setup_fndecl (tree fndecl, bool 
is_main_entry_point,
        {
          handle_derive_proc_macro_attribute_on_fndecl (fndecl, attr);
        }
+      else if (is_allocator)
+       {
+         handle_rustc_allocator_on_fndecl (fndecl, attr);
+       }
+      else if (is_allocator_nounwind)
+       {
+         handle_rustc_allocator_nounwind_on_fndecl (fndecl, attr);
+       }
     }
 }
 
@@ -298,6 +309,55 @@ 
HIRCompileBase::handle_rustc_std_internal_symbol_attribute_on_fndecl (
                 NULL_TREE, DECL_ATTRIBUTES (fndecl));
 }
 
+void
+HIRCompileBase::handle_rustc_allocator_on_fndecl (tree fndecl,
+                                                 const AST::Attribute &attr)
+{
+  tree return_type = TREE_TYPE (TREE_TYPE (fndecl));
+  if (!POINTER_TYPE_P (return_type))
+    {
+      rust_error_at (attr.get_locus (),
+                    "%<rustc_allocator%> attribute must be applied to a "
+                    "function returning a pointer");
+      return;
+    }
+
+  // 
https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs#L49
+  // `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
+  // function is never null.
+  //
+  // 
https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_typeck/src/collect.rs#L2482
+  // This attribute sets CodegenFnAttrFlags::ALLOCATOR.
+  //
+  // 
https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_codegen_llvm/src/attributes.rs#L302
+  // This flag activates LLVM::NoAlias attribute.
+  //
+  // In GCC, setting DECL_IS_MALLOC on a FUNCTION_DECL means this function
+  // should be treated as if it were a malloc, meaning it returns a pointer 
that
+  // is not an alias.
+  DECL_IS_MALLOC (fndecl) = 1;
+  DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("malloc"), NULL_TREE,
+                                       DECL_ATTRIBUTES (fndecl));
+}
+
+void
+HIRCompileBase::handle_rustc_allocator_nounwind_on_fndecl (
+  tree fndecl, const AST::Attribute &attr)
+{
+  // 
https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs#L55
+  // `#[rustc_allocator_nounwind]`: an indicator that an imported FFI
+  // function will never unwind.
+  //
+  // 
https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_typeck/src/collect.rs#L2484
+  // This attribute sets CodegenFnAttrFlags::NOUNWIND.
+  //
+  // In GCC, setting TREE_NOTHROW on a FUNCTION_DECL means a call to the
+  // function cannot throw an exception, which exactly matches this behavior.
+  TREE_NOTHROW (fndecl) = 1;
+  DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("nothrow"), NULL_TREE,
+                                       DECL_ATTRIBUTES (fndecl));
+}
+
 void
 HIRCompileBase::handle_deprecated_attribute_on_fndecl (
   tree fndecl, const AST::Attribute &attr)
diff --git a/gcc/rust/backend/rust-compile-base.h 
b/gcc/rust/backend/rust-compile-base.h
index 551a02e4d..d93cc3ba3 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -155,6 +155,13 @@ protected:
   static void handle_rustc_std_internal_symbol_attribute_on_fndecl (
     tree fndecl, const AST::Attribute &attr);
 
+  static void handle_rustc_allocator_on_fndecl (tree fndecl,
+                                               const AST::Attribute &attr);
+
+  static void
+  handle_rustc_allocator_nounwind_on_fndecl (tree fndecl,
+                                            const AST::Attribute &attr);
+
   static void setup_abi_options (tree fndecl, ABI abi);
 
   static tree indirect_expression (tree expr, location_t locus);
diff --git a/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc 
b/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
index 46b96f23a..ba1bf6be1 100644
--- a/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
+++ b/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
@@ -370,6 +370,30 @@ rustc_std_internal_symbol (const AST::Attribute &attribute)
     }
 }
 
+void
+rustc_allocator (const AST::Attribute &attribute)
+{
+  if (attribute.has_attr_input ())
+    {
+      rust_error_at (attribute.get_locus (),
+                    "malformed %<rustc_allocator%> attribute input");
+      rust_inform (attribute.get_locus (),
+                  "must be of the form: %<#[rustc_allocator]%>");
+    }
+}
+
+void
+rustc_allocator_nounwind (const AST::Attribute &attribute)
+{
+  if (attribute.has_attr_input ())
+    {
+      rust_error_at (attribute.get_locus (),
+                    "malformed %<rustc_allocator_nounwind%> attribute input");
+      rust_inform (attribute.get_locus (),
+                  "must be of the form: %<#[rustc_allocator_nounwind]%>");
+    }
+}
+
 } // namespace handlers
 
 const std::unordered_map<std::string, std::function<void (AST::Attribute &)>>
@@ -389,6 +413,8 @@ const std::unordered_map<std::string, std::function<void 
(AST::Attribute &)>>
     {Attrs::PROC_MACRO_ATTRIBUTE, handlers::proc_macro},
     {Attrs::TARGET_FEATURE, handlers::target_feature},
     {Attrs::RUSTC_STD_INTERNAL_SYMBOL, handlers::rustc_std_internal_symbol},
+    {Attrs::RUSTC_ALLOCATOR, handlers::rustc_allocator},
+    {Attrs::RUSTC_ALLOCATOR_NOUNWIND, handlers::rustc_allocator_nounwind},
 };
 
 tl::optional<std::function<void (AST::Attribute &)>>
diff --git a/gcc/rust/util/rust-attribute-values.h 
b/gcc/rust/util/rust-attribute-values.h
index 02d915f1a..9c14df39b 100644
--- a/gcc/rust/util/rust-attribute-values.h
+++ b/gcc/rust/util/rust-attribute-values.h
@@ -107,6 +107,9 @@ public:
 
   static constexpr auto &RUSTC_ARGS_REQUIRED_CONST
     = "rustc_args_required_const";
+
+  static constexpr auto &RUSTC_ALLOCATOR = "rustc_allocator";
+  static constexpr auto &RUSTC_ALLOCATOR_NOUNWIND = "rustc_allocator_nounwind";
 };
 } // namespace Values
 } // namespace Rust
diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc
index 7042f8bd1..08115d465 100644
--- a/gcc/rust/util/rust-attributes.cc
+++ b/gcc/rust/util/rust-attributes.cc
@@ -94,7 +94,9 @@ static const BuiltinAttrDefinition __definitions[]
      {Attrs::FUNDAMENTAL, TYPE_CHECK},
      {Attrs::NON_EXHAUSTIVE, TYPE_CHECK},
      {Attrs::RUSTFMT, EXTERNAL},
-     {Attrs::TEST, CODE_GENERATION}};
+     {Attrs::TEST, CODE_GENERATION},
+     {Attrs::RUSTC_ALLOCATOR, CODE_GENERATION},
+     {Attrs::RUSTC_ALLOCATOR_NOUNWIND, CODE_GENERATION}};
 
 static const std::set<std::string> __outer_attributes
   = {Attrs::INLINE,
diff --git a/gcc/testsuite/rust/compile/attr-allocator1.rs 
b/gcc/testsuite/rust/compile/attr-allocator1.rs
new file mode 100644
index 000000000..282109580
--- /dev/null
+++ b/gcc/testsuite/rust/compile/attr-allocator1.rs
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fdump-tree-gimple" }
+#![feature(no_core, rustc_attrs)]
+#![no_core]
+
+#[rustc_allocator]
+#[rustc_allocator_nounwind]
+fn _foo() -> *mut u8 {
+    0 as *mut u8
+}
+
+// { dg-final { scan-tree-dump "malloc" "gimple" } }
+// { dg-final { scan-tree-dump "nothrow" "gimple" } }
diff --git a/gcc/testsuite/rust/compile/attr-allocator2.rs 
b/gcc/testsuite/rust/compile/attr-allocator2.rs
new file mode 100644
index 000000000..215204391
--- /dev/null
+++ b/gcc/testsuite/rust/compile/attr-allocator2.rs
@@ -0,0 +1,10 @@
+#![feature(no_core, rustc_attrs)]
+#![no_core]
+
+#[rustc_allocator(invalid)] // { dg-error "malformed .rustc_allocator. 
attribute input" }
+pub fn _foo() -> *mut u8 {
+    0 as *mut u8
+}
+
+#[rustc_allocator_nounwind(invalid)] // { dg-error "malformed 
.rustc_allocator_nounwind. attribute input" }
+pub fn _bar() {}
diff --git a/gcc/testsuite/rust/compile/attr-allocator3.rs 
b/gcc/testsuite/rust/compile/attr-allocator3.rs
new file mode 100644
index 000000000..9eb70452b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/attr-allocator3.rs
@@ -0,0 +1,6 @@
+#![feature(no_core, rustc_attrs)]
+#![no_core]
+
+#[rustc_allocator] // { dg-error ".rustc_allocator. attribute must be applied 
to a function returning a pointer" }
+pub fn _foo() {}
+
-- 
2.54.0

Reply via email to