[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