From: Lucas Ly Ba <[email protected]>
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 <[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/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
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.