[gccrs COMMIT 2/2] gccrs: Gate `cfg_select!` macro behind `-frust-compat-version=1.90`

[email protected] Mon, 3 Aug 2026 10:42:57 +0000
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.rust
Message-ID <[email protected]>
From: Yap Zhi Heng <[email protected]>

gcc/rust/ChangeLog:

	* expand/rust-macro-builtins.cc: Made it more explicit that cfg_select! is
	backported.
	* rust-session-manager.h (Session::should_support_cfg_select): New function to
	check whether cfg_select! should be compiled.
	* resolve/rust-early-name-resolver-2.0.cc (Early::visit(MacroInvocation)):
	Conditionally resolve cfg_select!.
	* expand/rust-macro-expand.cc (MacroExpander::expand_invoc): Ditto.

gcc/testsuite/ChangeLog:

	* rust/execute/torture/cfg_select1.rs: Add new dg-additional-options, remove
	the no-longer-needed cfg_select! declaration.
	* rust/execute/torture/cfg_select2.rs: Ditto.
	* rust/compile/c_string_null_byte_check.rs: Ditto.
	* rust/execute/torture/c_string.rs: Ditto.
	* rust/execute/torture/c_string_ensure_null_term.rs: Ditto.

Signed-off-by: Yap Zhi Heng <[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/03b5b9e4ae8e7ef12a85d1a1b619b5b94bf6f38d

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

 gcc/rust/expand/rust-macro-builtins.cc         |  3 ++-
 gcc/rust/expand/rust-macro-expand.cc           | 18 ++++++++++++++++++
 .../resolve/rust-early-name-resolver-2.0.cc    |  9 +++++++--
 gcc/rust/rust-session-manager.h                |  5 +++++
 .../rust/compile/c_string_null_byte_check.rs   |  9 ++-------
 gcc/testsuite/rust/execute/torture/c_string.rs |  9 ++-------
 .../torture/c_string_ensure_null_term.rs       |  9 ++-------
 .../rust/execute/torture/cfg_select1.rs        | 11 +++--------
 .../rust/execute/torture/cfg_select2.rs        | 11 +++--------
 9 files changed, 44 insertions(+), 40 deletions(-)

diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc
index df651fd9b..d96b23f99 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -125,7 +125,6 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc>
     {"concat", MacroBuiltin::concat_handler},
     {"env", MacroBuiltin::env_handler},
     {"cfg", MacroBuiltin::cfg_handler},
-    {"cfg_select", MacroBuiltin::cfg_select_handler},
     {"include", MacroBuiltin::include_handler},
     {"format_args", format_args_maker (AST::FormatArgs::Newline::No)},
     {"format_args_nl", format_args_maker (AST::FormatArgs::Newline::Yes)},
@@ -166,6 +165,8 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc>
     /* offset_of is not declared in Rust 1.49 but still needed for
        Rust-for-Linux, so we still create a transcriber and warn the user */
     {"offset_of", MacroBuiltin::offset_of_handler},
+    /* cfg_select! is also not declared in Rust 1.49 but also needed for RfL */
+    {"cfg_select", MacroBuiltin::cfg_select_handler},
 };
 
 tl::optional<BuiltinMacro>
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 30373722e..3b798202e 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -329,6 +329,24 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
       return;
     }
 
+  // TODO: Also remove code below as we progress to Rust 1.90, when cfg_select
+  // gets added to nightly.
+  auto assume_builtin_cfg_select
+    = Session::get_instance ().should_support_cfg_select ()
+      && (invoc.get_invoc_data ().get_path ().as_string () == "cfg_select")
+      && !rules_def;
+
+  if (assume_builtin_cfg_select)
+    {
+      fragment = MacroBuiltin::cfg_select_handler (invoc.get_locus (),
+						   invoc_data, semicolon)
+		   .value_or (AST::Fragment::create_empty ());
+
+      set_expanded_fragment (std::move (fragment));
+
+      return;
+    }
+
   // If there's no rule associated with the invocation, we can simply return
   // early. The early name resolver will have already emitted an error.
   if (!rules_def)
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 56f91db89..830932cdd 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -339,6 +339,11 @@ Early::visit (AST::MacroInvocation &invoc)
   auto resolve_offset_of = Session::get_instance ().should_support_offset_of ()
 			   && (path.as_string () == "offset_of");
 
+  // Ditto, but for `cfg_select!()`.
+  auto resolve_cfg_select
+    = Session::get_instance ().should_support_cfg_select ()
+      && (path.as_string () == "cfg_select");
+
   if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
     for (auto &pending_invoc : invoc.get_pending_eager_invocations ())
       pending_invoc->accept_vis (*this);
@@ -366,10 +371,10 @@ Early::visit (AST::MacroInvocation &invoc)
     ns_def = ctx.resolve_path (path, Namespace::Macros);
 
   // if the definition still does not have a value, then it's an error - unless
-  // we should automatically resolve offset_of!() calls
+  // we should automatically resolve offset_of!() or cfg_select!() calls
   if (!ns_def.has_value ())
     {
-      if (!resolve_offset_of)
+      if (!resolve_offset_of && !resolve_cfg_select)
 	collect_error (Error (invoc.get_locus (), ErrorCode::E0433,
 			      "could not resolve macro invocation %qs",
 			      path.as_string ().c_str ()));
diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h
index 0a6cc8117..9f0209b90 100644
--- a/gcc/rust/rust-session-manager.h
+++ b/gcc/rust/rust-session-manager.h
@@ -509,6 +509,11 @@ public:
 
   bool should_support_offset_of () const { return get_compat_version () >= 71; }
 
+  bool should_support_cfg_select () const
+  {
+    return get_compat_version () >= 90;
+  }
+
 private:
   Session () : mappings (Analysis::Mappings::get ()) {}
   void compile_crate (const char *filename);
diff --git a/gcc/testsuite/rust/compile/c_string_null_byte_check.rs b/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
index 6c872e000..57dfe8623 100644
--- a/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
+++ b/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
@@ -1,12 +1,7 @@
-// { dg-additional-options "-frust-c-style-string-literals" }
-#![feature(no_core, lang_items, rustc_attrs)]
+// { dg-additional-options "-frust-c-style-string-literals -frust-compat-version=1.90" }
+#![feature(no_core, lang_items)]
 #![no_core]
 
-#[rustc_builtin_macro]
-macro_rules! cfg_select {
-    () => {{}};
-}
-
 cfg_select! {
     all(
         not(windows),
diff --git a/gcc/testsuite/rust/execute/torture/c_string.rs b/gcc/testsuite/rust/execute/torture/c_string.rs
index 9df72b8f0..be90e4e1c 100644
--- a/gcc/testsuite/rust/execute/torture/c_string.rs
+++ b/gcc/testsuite/rust/execute/torture/c_string.rs
@@ -1,13 +1,8 @@
-// { dg-additional-options "-frust-c-style-string-literals" }
+// { dg-additional-options "-frust-c-style-string-literals -frust-compat-version=1.90" }
 // { dg-output "gccrs" }
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items)]
 #![no_core]
 
-#[rustc_builtin_macro]
-macro_rules! cfg_select {
-    () => {{}};
-}
-
 cfg_select! {
     all(
         not(windows),
diff --git a/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs b/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
index a880bb735..488d9fdcd 100644
--- a/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
+++ b/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
@@ -1,5 +1,5 @@
-// { dg-additional-options "-frust-c-style-string-literals" }
-#![feature(no_core, intrinsics, staged_api, lang_items, rustc_attrs)]
+// { dg-additional-options "-frust-c-style-string-literals -frust-compat-version=1.90" }
+#![feature(no_core, intrinsics, staged_api, lang_items)]
 #![no_core]
 
 #[lang = "sized"]
@@ -26,11 +26,6 @@ impl<T> *const T {
     }
 }
 
-#[rustc_builtin_macro]
-macro_rules! cfg_select {
-    () => {{}};
-}
-
 cfg_select! {
     all(
         not(windows),
diff --git a/gcc/testsuite/rust/execute/torture/cfg_select1.rs b/gcc/testsuite/rust/execute/torture/cfg_select1.rs
index 5a37dcc6c..fda698e38 100644
--- a/gcc/testsuite/rust/execute/torture/cfg_select1.rs
+++ b/gcc/testsuite/rust/execute/torture/cfg_select1.rs
@@ -1,13 +1,8 @@
-// { dg-additional-options "-frust-cfg=A=\"foo\"" }
+// { dg-additional-options "-frust-compat-version=1.90 -frust-cfg=A=\"foo\"" }
 // { dg-output "wildcard\r*\n" }
-#![feature(no_core, rustc_attrs)]
+#![feature(no_core)]
 #![no_core]
 
-#[rustc_builtin_macro]
-macro_rules! cfg_select {
-    () => {{}};
-}
-
 extern "C" {
     fn printf(s: *const i8, ...);
 }
@@ -28,4 +23,4 @@ fn main() -> i32 {
         }
     }
     return 0;
-}
\ No newline at end of file
+}
diff --git a/gcc/testsuite/rust/execute/torture/cfg_select2.rs b/gcc/testsuite/rust/execute/torture/cfg_select2.rs
index fe0ad608e..2a6c5af7b 100644
--- a/gcc/testsuite/rust/execute/torture/cfg_select2.rs
+++ b/gcc/testsuite/rust/execute/torture/cfg_select2.rs
@@ -1,13 +1,8 @@
-// { dg-additional-options "-frust-cfg=A=\"foo\"" }
+// { dg-additional-options "-frust-compat-version=1.90 -frust-cfg=A=\"foo\"" }
 // { dg-output "pass\r*\n" }
-#![feature(no_core, rustc_attrs)]
+#![feature(no_core)]
 #![no_core]
 
-#[rustc_builtin_macro]
-macro_rules! cfg_select {
-    () => {{}};
-}
-
 extern "C" {
     fn printf(s: *const i8, ...);
 }
@@ -28,4 +23,4 @@ fn main() -> i32 {
         }
     }
     return 0;
-}
\ No newline at end of file
+}
-- 
2.54.0