From: Arthur Cohen <[email protected]>
Gate derive(CoercePointee) behind `#![feature(derive_coerce_pointee)` and start
adding the
infrastructure required to support it. Warn that it doesn't do anything yet.
gcc/rust/ChangeLog:
* checks/errors/feature/rust-feature-defs.h (FEATURE_ACTIVE): New
feature.
* expand/rust-derive.cc (DeriveVisitor::derive): Add base handling for
CoercePointee derive.
* expand/rust-macro-builtins.cc: Add CoercePointee as a built-in derive
* expand/rust-macro-builtins.h (enum class): Likewise.
* resolve/rust-early-name-resolver-2.0.cc
(Early::visit_derive_attribute): Special case
derive(CoercePointee).
* rust-session-manager.h (should_support_coerce_pointee): New method.
* expand/rust-derive-coerce-pointee.cc: New file.
* expand/rust-derive-coerce-pointee.h: New file.
* Make-lang.in: Compile it.
gcc/testsuite/ChangeLog:
* rust/compile/derive-coerce-pointee1.rs: New test.
* rust/compile/derive-coerce-pointee2.rs: New test.
* rust/compile/derive-coerce-pointee3.rs: New test.
Tested on x86_64-pc-linux-gnu.
---
gcc/rust/Make-lang.in | 1 +
.../checks/errors/feature/rust-feature-defs.h | 4 +
gcc/rust/expand/rust-derive-coerce-pointee.cc | 76 +++++++++++++++++++
gcc/rust/expand/rust-derive-coerce-pointee.h | 44 +++++++++++
gcc/rust/expand/rust-derive.cc | 3 +
gcc/rust/expand/rust-macro-builtins.cc | 1 +
gcc/rust/expand/rust-macro-builtins.h | 1 +
.../resolve/rust-early-name-resolver-2.0.cc | 6 ++
gcc/rust/rust-session-manager.h | 5 ++
.../rust/compile/derive-coerce-pointee1.rs | 16 ++++
.../rust/compile/derive-coerce-pointee2.rs | 14 ++++
.../rust/compile/derive-coerce-pointee3.rs | 14 ++++
12 files changed, 185 insertions(+)
create mode 100644 gcc/rust/expand/rust-derive-coerce-pointee.cc
create mode 100644 gcc/rust/expand/rust-derive-coerce-pointee.h
create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee1.rs
create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee2.rs
create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee3.rs
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index acecc31416a..0acd0896ac3 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -108,6 +108,7 @@ GRS_OBJS = \
rust/rust-derive-eq.o \
rust/rust-derive-ord.o \
rust/rust-derive-hash.o \
+ rust/rust-derive-coerce-pointee.o \
rust/rust-proc-macro.o \
rust/rust-macro-invoc-lexer.o \
rust/rust-macro-substitute-ctx.o \
diff --git a/gcc/rust/checks/errors/feature/rust-feature-defs.h
b/gcc/rust/checks/errors/feature/rust-feature-defs.h
index b541bbd2350..b91a041c665 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-defs.h
+++ b/gcc/rust/checks/errors/feature/rust-feature-defs.h
@@ -521,6 +521,10 @@ FEATURE_ACTIVE ("destructuring_assignment",
DESTRUCTURING_ASSIGNMENT, "1.49.0",
ISSUE_SOME (71126), EDITION_NONE)
FEATURE_ACTIVE ("cfg_panic", CFG_PANIC, "1.49.0", ISSUE_SOME (77443),
EDITION_NONE)
+FEATURE_ACTIVE ("derive_coerce_pointee", DERIVE_COERCE_POINTEE,
+ "1.84.0" /* Not sure about the version number for this one */,
+ /* We also need a compatibility check to enable this */
+ ISSUE_SOME (123430), EDITION_NONE)
FEATURE_REMOVED ("import_shadowing", IMPORT_SHADOWING, "1.0.0", ISSUE_NONE,
REASON_NONE)
FEATURE_REMOVED ("managed_boxes", MANAGED_BOXES, "1.0.0", ISSUE_NONE,
diff --git a/gcc/rust/expand/rust-derive-coerce-pointee.cc
b/gcc/rust/expand/rust-derive-coerce-pointee.cc
new file mode 100644
index 00000000000..51bb7d3e4ea
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-coerce-pointee.cc
@@ -0,0 +1,76 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-derive-coerce-pointee.h"
+#include "rust-session-manager.h"
+#include "rust-feature.h"
+#include "rust-feature-store.h"
+
+namespace Rust {
+namespace AST {
+
+DeriveCoercePointee::DeriveCoercePointee (location_t loc,
+ Builder::Source item_source)
+ : DeriveVisitor (loc, item_source)
+{}
+
+std::unique_ptr<AST::Item>
+DeriveCoercePointee::go (Item &item)
+{
+ Features::EarlyFeatureGateStore::get ().add (
+ Feature::Name::DERIVE_COERCE_POINTEE,
+ Error (loc, "use of unstable library feature %<derive_coerce_pointee%>"));
+
+ // NOTE: This is technically a library feature, so I don't think this is
+ // how it should be gated. But as far as I can tell at the moment we have
+ // no mechanisms for handling these, and furthermore this will go through
+ // our compatibility layer.
+ //
+ // What this means is that the `CoercePointee` macro will *not* be defined
+ // in the `core` that we will be using to compile the kernel at first.
+ //
+ // The basic example for `CoercePointee` is something like this:
+ //
+ // ```rust
+ // use std::marker::CoercePointee;
+ //
+ // #[derive(CoercePointee)]
+ // struct Flip<Flop>(*const Flop);
+ // ```
+ //
+ // but the marker will not be present in the `core` we will be using at
+ // first, so we will need to fake its existence with
+ // -frust-compat-version, and then the compiler can assume that it is a
+ // built-in derive. At least that's my expectation.
+
+ if (!Session::get_instance ().should_support_coerce_pointee ())
+ {
+ rust_error_at (loc, "derive(CoercePointee) requires a compatibility mode
"
+ "greater or equal to 1.84");
+ return {};
+ }
+
+ rust_warning_at (
+ loc, 0,
+ "derive(CoercePointee) is currently unimplemented and has no effect");
+
+ return {};
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-derive-coerce-pointee.h
b/gcc/rust/expand/rust-derive-coerce-pointee.h
new file mode 100644
index 00000000000..b6f5c2b464f
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-coerce-pointee.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_DERIVE_COERCE_POINTEE_H
+#define RUST_DERIVE_COERCE_POINTEE_H
+
+#include "rust-derive.h"
+
+namespace Rust {
+namespace AST {
+
+class DeriveCoercePointee : DeriveVisitor
+{
+public:
+ DeriveCoercePointee (location_t loc, Builder::Source item_source);
+
+ std::unique_ptr<Item> go (Item &item);
+
+private:
+ virtual void visit_struct (StructStruct &item) override {}
+ virtual void visit_tuple (TupleStruct &item) override {}
+ virtual void visit_enum (Enum &item) override {}
+ virtual void visit_union (Union &item) override {}
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DERIVE_COERCE_POINTEE_H
diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc
index f45acaa8c24..7e60eff9470 100644
--- a/gcc/rust/expand/rust-derive.cc
+++ b/gcc/rust/expand/rust-derive.cc
@@ -18,6 +18,7 @@
#include "rust-derive.h"
#include "rust-derive-clone.h"
+#include "rust-derive-coerce-pointee.h"
#include "rust-derive-copy.h"
#include "rust-derive-debug.h"
#include "rust-derive-default.h"
@@ -83,6 +84,8 @@ DeriveVisitor::derive (Item &item, const Attribute &attr,
? "RustcEncodable"
: "RustcDecodable");
return {};
+ case BuiltinMacro::CoercePointee:
+ return vec (DeriveCoercePointee (loc, item_source).go (item));
default:
rust_unreachable ();
};
diff --git a/gcc/rust/expand/rust-macro-builtins.cc
b/gcc/rust/expand/rust-macro-builtins.cc
index d96b23f9992..998477c5253 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -83,6 +83,7 @@ const BiMap<std::string, BuiltinMacro> MacroBuiltin::builtins
= {{
{"Ord", BuiltinMacro::Ord},
{"PartialOrd", BuiltinMacro::PartialOrd},
{"Hash", BuiltinMacro::Hash},
+ {"CoercePointee", BuiltinMacro::CoercePointee},
}};
AST::MacroTranscriberFunc
diff --git a/gcc/rust/expand/rust-macro-builtins.h
b/gcc/rust/expand/rust-macro-builtins.h
index b0c2db57f05..c433ab1a372 100644
--- a/gcc/rust/expand/rust-macro-builtins.h
+++ b/gcc/rust/expand/rust-macro-builtins.h
@@ -76,6 +76,7 @@ enum class BuiltinMacro
Ord,
PartialOrd,
Hash,
+ CoercePointee,
};
tl::optional<BuiltinMacro>
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 8b3220d49f3..4860163beb6 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -392,6 +392,12 @@ Early::visit_derive_attribute (AST::Attribute &attr,
auto traits = attr.get_traits_to_derive ();
for (auto &trait : traits)
{
+ // Special case CoercePointee if we're in a proper compatibility mode.
+ // Count it as a builtin derive macro and keep going.
+ if (trait.get ().as_string () == "CoercePointee"
+ && Session::get_instance ().should_support_coerce_pointee ())
+ continue;
+
auto ns_def = ctx.resolve_path (trait.get (), Namespace::Macros);
if (!ns_def.has_value ())
{
diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h
index 6a0acda7c1a..0f4ba7257a1 100644
--- a/gcc/rust/rust-session-manager.h
+++ b/gcc/rust/rust-session-manager.h
@@ -519,6 +519,11 @@ public:
return get_compat_version () >= 90;
}
+ bool should_support_coerce_pointee () const
+ {
+ return get_compat_version () >= 84;
+ }
+
private:
Session () : mappings (Analysis::Mappings::get ()) {}
void compile_crate (const char *filename);
diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee1.rs
b/gcc/testsuite/rust/compile/derive-coerce-pointee1.rs
new file mode 100644
index 00000000000..ebc9cde10be
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive-coerce-pointee1.rs
@@ -0,0 +1,16 @@
+// { dg-additional-options "-frust-compat-version=1.84" }
+
+// check that we error out when the compat mode is right but the feature is
missing
+
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+ // { dg-error "use of unstable library feature" "" {
target *-*-* } .-1 }
+struct Floop<T> {
+ a: *const T,
+}
diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee2.rs
b/gcc/testsuite/rust/compile/derive-coerce-pointee2.rs
new file mode 100644
index 00000000000..8c84a7fb336
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive-coerce-pointee2.rs
@@ -0,0 +1,14 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![feature(derive_coerce_pointee)]
+#![no_core]
+
+// check that we error out when the feature is right but the compat mode is
missing (opposite of derive-coerce-pointee1.rs)
+
+#[lang = "sized"]
+trait Sized {}
+
+#[derive(CoercePointee)]
+// { dg-error "derive.CoercePointee. requires a compatibility mode" "" {
target *-*-* } .-1 }
+// { dg-error "could not resolve trait .CoercePointee." "" { target *-*-* }
.-2 }
+pub struct Floop<T>(*const T);
diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee3.rs
b/gcc/testsuite/rust/compile/derive-coerce-pointee3.rs
new file mode 100644
index 00000000000..8ca8a1bae58
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive-coerce-pointee3.rs
@@ -0,0 +1,14 @@
+// { dg-additional-options "-frust-compat-version=1.84" }
+
+// this time everything is enabled - check we fake name resolve properly and
we have access to the derive
+
+#![feature(no_core)]
+#![feature(lang_items)]
+#![feature(derive_coerce_pointee)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+pub struct Floop<T>(*const T);
--
2.55.0