[gccrs COMMIT 3/3] attr: Add attributes rustc_allocator and rustc_allocator_nounwind

gerris.rs@gmail.com gerris.rs@gmail.com
Wed Jun 10 14:57:16 GMT 2026


From: Enes Cevik <enes@nsvke.com>

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 <enes@nsvke.com>
---
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



More information about the Gcc-rust mailing list