[gccrs COMMIT 6/6] gccrs: add repr_c_enums_larger_than_int lint

gerris.rs@gmail.com gerris.rs@gmail.com
Sat Aug 15 21:42:17 GMT 2026


From: Lucas Ly Ba <hi@lucaslyba.com>

Warn on a `#[repr(C)]` enum whose discriminant fits into neither a C
`int` nor a C `unsigned int`. Such an enum is non-portable: C only
permits enums whose discriminants do not all fit into one of those two
types since C23, and Rust interprets `repr(C)` discriminants as `isize`,
so its size may not match the C one.

The discriminant is const evaluated with query_compile_const_expr during
type resolution, so any constant discriminant expression is handled.

gcc/rust/ChangeLog:

	* typecheck/rust-hir-type-check-item.cc
	(check_repr_c_enum_discriminants): New.
	(TypeCheckItem::visit): Check repr(C) enum discriminants.

gcc/testsuite/ChangeLog:

	* rust/compile/repr-c-enums-larger-than-int_0.rs: New test.

Signed-off-by: Lucas Ly Ba <lucas.ly-ba@outlook.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/08ec968b3da40d830e5c4d9d13edd0e09bc46f42

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

 .../typecheck/rust-hir-type-check-item.cc     | 45 +++++++++++++++++++
 .../compile/repr-c-enums-larger-than-int_0.rs | 19 ++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 gcc/testsuite/rust/compile/repr-c-enums-larger-than-int_0.rs

diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 112ba0b41..1b8b929bd 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -36,10 +36,52 @@
 #include "rust-type-util.h"
 #include "rust-tyty-variance-analysis.h"
 #include "rust-tyty.h"
+#include "options.h"
+#include "rust-compile-base.h"
+#include "rust-compile-context.h"
 
 namespace Rust {
 namespace Resolver {
 
+// Const-evaluate the discriminants of a repr(C) enum and warn when a value does
+// not fit into a C int/unsigned int. Done here, during type resolution, using
+// the compile context (a singleton shared with the backend).
+static void
+check_repr_c_enum_discriminants (Compile::Context *ctx, TyTy::BaseType *type)
+{
+  if (type->get_kind () != TyTy::TypeKind::ADT)
+    return;
+
+  auto &adt = static_cast<TyTy::ADTType &> (*type);
+  if (!adt.is_enum ()
+      || adt.get_repr_options ().repr_kind != TyTy::ADTType::ReprKind::C)
+    return;
+
+  for (auto &variant : adt.get_variants ())
+    {
+      if (!variant->has_discriminant ())
+	continue;
+
+      HIR::Expr &discriminant = variant->get_discriminant ();
+      TyTy::BaseType *discrim_ty = nullptr;
+      if (!ctx->get_tyctx ()->lookup_type (
+	    discriminant.get_mappings ().get_hirid (), &discrim_ty))
+	continue;
+
+      tree folded
+	= Compile::HIRCompileBase::query_compile_const_expr (ctx, discrim_ty,
+							     discriminant);
+      if (folded == error_mark_node || TREE_CODE (folded) != INTEGER_CST)
+	continue;
+
+      widest_int value = wi::to_widest (folded);
+      if (wi::lts_p (value, INT32_MIN) || wi::gts_p (value, UINT32_MAX))
+	rust_warning_at (discriminant.get_locus (), OPT_Woverflow,
+			 "%<repr(C)%> enum discriminant does not fit into C "
+			 "%<int%> nor into C %<unsigned int%>");
+    }
+}
+
 TypeCheckItem::TypeCheckItem () : TypeCheckBase (), infered (nullptr) {}
 
 TyTy::BaseType *
@@ -493,6 +535,9 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
   infered = type;
 
   context->get_variance_analysis_ctx ().add_type_constraints (*type);
+
+  if (flag_unused_check_2_0)
+    check_repr_c_enum_discriminants (Compile::Context::get (), type);
 }
 
 void
diff --git a/gcc/testsuite/rust/compile/repr-c-enums-larger-than-int_0.rs b/gcc/testsuite/rust/compile/repr-c-enums-larger-than-int_0.rs
new file mode 100644
index 000000000..5dce847db
--- /dev/null
+++ b/gcc/testsuite/rust/compile/repr-c-enums-larger-than-int_0.rs
@@ -0,0 +1,19 @@
+// { dg-additional-options "-frust-unused-check-2.0" }
+// { dg-skip-if "discriminant needs a 64-bit isize" { ! lp64 } }
+#![feature(no_core)]
+#![no_core]
+
+#[repr(C)]
+pub enum Big {
+    A = 9223372036854775807,
+// { dg-warning "enum discriminant does not fit into C" "" { target *-*-* } .-1 }
+}
+
+#[repr(C)]
+pub enum Small {
+    B = 5,
+}
+
+pub enum NoRepr {
+    C = 9223372036854775807,
+}
-- 
2.54.0



More information about the Gcc-rust mailing list