[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 06:37:19 PDT 2024


https://github.com/keinflue updated https://github.com/llvm/llvm-project/pull/106841

>From 533f32f7be161bfec45ee93cef3fbd78fc55e721 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