[clang] [clang] fix range of empty enumeration without fixed underlying type (PR #106841)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 31 02:54:48 PDT 2024
https://github.com/keinflue created https://github.com/llvm/llvm-project/pull/106841
In C++ enumerations without fixed underlying type which have either no enumerator or only enumerators with value 0 have a value set containing only 0, instead of 0 and 1. See [decl.enum]/8.
This PR affects casts in C++ constant expressions, where casting a value of 1 to such an enumeration type is now no longer permitted. It also affects code generation in C++ mode with `-fstrict-enums` which may now assume that loading from such enumeration types will always produce 0.
Fixes #106815
>From 4f6d2107fffe0ab15157c095f29fd3c45ddca889 Mon Sep 17 00:00:00 2001
From: keinflue <80230456+keinflue at users.noreply.github.com>
Date: Sat, 31 Aug 2024 11:27:57 +0200
Subject: [PATCH] [clang] fix range of empty enumeration without fixed
underlying type
In C++ enumerations without fixed underlying type which have either no
enumerator or only enumerators with value 0 have a value set containing
only 0, instead of 0 and 1. See [decl.enum]/8.
Fixes #106815
---
clang/lib/Sema/SemaChecking.cpp | 1 -
clang/lib/Sema/SemaDecl.cpp | 11 +----------
clang/test/AST/ByteCode/cxx11.cpp | 8 ++++++--
clang/test/CodeGenCXX/pr12251.cpp | 4 ++--
clang/test/SemaCXX/constant-expression-cxx11.cpp | 8 ++++++--
5 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b021e27209cf1b..5a092279ea12b0 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -10284,7 +10284,6 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// inconsistency by storing this as a signed type.
if (S.getLangOpts().CPlusPlus11 &&
!BitfieldEnumDecl->getIntegerTypeSourceInfo() &&
- BitfieldEnumDecl->getNumPositiveBits() > 0 &&
BitfieldEnumDecl->getNumNegativeBits() == 0) {
S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield)
<< BitfieldEnumDecl;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6327ae9b99aa4c..3efd01673f40fa 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19903,23 +19903,14 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
- // If the enumerator is zero that should still be counted as a positive
- // bit since we need a bit to store the value zero.
unsigned ActiveBits = InitVal.getActiveBits();
- NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
+ NumPositiveBits = std::max(NumPositiveBits, ActiveBits);
} else {
NumNegativeBits =
std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
}
}
- // If we have an empty set of enumerators we still need one bit.
- // From [dcl.enum]p8
- // If the enumerator-list is empty, the values of the enumeration are as if
- // the enumeration had a single enumerator with value 0
- if (!NumPositiveBits && !NumNegativeBits)
- NumPositiveBits = 1;
-
// Figure out the type that should be used for this enum.
QualType BestType;
unsigned BestWidth;
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index 481e3da9289efa..ead47faffcf7a6 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -115,15 +115,19 @@ void testValueInRangeOfEnumerationValues() {
constexpr E4 x11 = static_cast<E4>(0);
constexpr E4 x12 = static_cast<E4>(1);
+ // both-error at -1 {{constexpr variable 'x12' must be initialized by a constant expression}}
+ // both-note at -2 {{integer value 1 is outside the valid range of values [0, 0] for the enumeration type 'E4'}}
constexpr E4 x13 = static_cast<E4>(2);
// both-error at -1 {{constexpr variable 'x13' must be initialized by a constant expression}}
- // both-note at -2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
+ // both-note at -2 {{integer value 2 is outside the valid range of values [0, 0] for the enumeration type 'E4'}}
constexpr EEmpty x14 = static_cast<EEmpty>(0);
constexpr EEmpty x15 = static_cast<EEmpty>(1);
+ // both-error at -1 {{constexpr variable 'x15' must be initialized by a constant expression}}
+ // both-note at -2 {{integer value 1 is outside the valid range of values [0, 0] for the enumeration type 'EEmpty'}}
constexpr EEmpty x16 = static_cast<EEmpty>(2);
// both-error at -1 {{constexpr variable 'x16' must be initialized by a constant expression}}
- // both-note at -2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
+ // both-note at -2 {{integer value 2 is outside the valid range of values [0, 0] for the enumeration type 'EEmpty'}}
constexpr EFixed x17 = static_cast<EFixed>(100);
constexpr EScoped x18 = static_cast<EScoped>(100);
diff --git a/clang/test/CodeGenCXX/pr12251.cpp b/clang/test/CodeGenCXX/pr12251.cpp
index bd5c85b83f2caf..5d0afb639d668d 100644
--- a/clang/test/CodeGenCXX/pr12251.cpp
+++ b/clang/test/CodeGenCXX/pr12251.cpp
@@ -18,14 +18,14 @@ e1 g1(e1 *x) {
return *x;
}
// CHECK-LABEL: define{{.*}} i32 @_Z2g1P2e1
-// CHECK: ret i32 %0
+// CHECK: ret i32 0
enum e2 { e2_a = 0 };
e2 g2(e2 *x) {
return *x;
}
// CHECK-LABEL: define{{.*}} i32 @_Z2g2P2e2
-// CHECK: ret i32 %0
+// CHECK: ret i32 0
enum e3 { e3_a = 16 };
e3 g3(e3 *x) {
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 44ef540f41fa8c..2c64f603029b85 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -2485,15 +2485,19 @@ void testValueInRangeOfEnumerationValues() {
constexpr E4 x11 = static_cast<E4>(0);
constexpr E4 x12 = static_cast<E4>(1);
+ // expected-error at -1 {{constexpr variable 'x12' must be initialized by a constant expression}}
+ // expected-note at -2 {{integer value 1 is outside the valid range of values [0, 0] for the enumeration type 'E4'}}
constexpr E4 x13 = static_cast<E4>(2);
// expected-error at -1 {{constexpr variable 'x13' must be initialized by a constant expression}}
- // expected-note at -2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
+ // expected-note at -2 {{integer value 2 is outside the valid range of values [0, 0] for the enumeration type 'E4'}}
constexpr EEmpty x14 = static_cast<EEmpty>(0);
constexpr EEmpty x15 = static_cast<EEmpty>(1);
+ // expected-error at -1 {{constexpr variable 'x15' must be initialized by a constant expression}}
+ // expected-note at -2 {{integer value 1 is outside the valid range of values [0, 0] for the enumeration type 'EEmpty'}}
constexpr EEmpty x16 = static_cast<EEmpty>(2);
// expected-error at -1 {{constexpr variable 'x16' must be initialized by a constant expression}}
- // expected-note at -2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
+ // expected-note at -2 {{integer value 2 is outside the valid range of values [0, 0] for the enumeration type 'EEmpty'}}
constexpr EFixed x17 = static_cast<EFixed>(100);
constexpr EScoped x18 = static_cast<EScoped>(100);
More information about the cfe-commits
mailing list