Mordante updated this revision to Diff 284478.
Mordante added a comment.

Addresses the review comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85612/new/

https://reviews.llvm.org/D85612

Files:
  clang/lib/Sema/SemaCast.cpp
  clang/test/AST/ast-dump-enum-bool.cpp
  clang/test/CodeGen/enum-bool.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===================================================================
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -594,3 +594,16 @@
 }
 
 } // namespace special_ctor
+
+namespace dr2338 {
+namespace B {
+enum E : bool { Zero, One };
+consteval E c(int x) { return (E)x; }
+static_assert(static_cast<int>(c(2)) == 1);
+} // namespace B
+namespace D {
+enum class E : bool { Zero, One };
+consteval E c(int x) { return (E)x; }
+static_assert(static_cast<int>(c(2)) == 1);
+} // namespace D
+} // namespace dr2338
Index: clang/test/CodeGen/enum-bool.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/enum-bool.cpp
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
+
+namespace dr2338 {
+namespace A {
+enum E { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define i32 @_ZN6dr23381A1aEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   ret i32 %0
+// CHECK-NEXT: }
+
+E b(int x) { return (E)x; }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define i32 @_ZN6dr23381A1bEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   ret i32 %0
+// CHECK-NEXT: }
+
+} // namespace A
+namespace B {
+enum E : bool { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define zeroext i1 @_ZN6dr23381B1aEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   %tobool = icmp ne i32 %0, 0
+// CHECK-NEXT:   ret i1 %tobool
+// CHECK-NEXT: }
+
+E b(int x) { return (E)x; }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define zeroext i1 @_ZN6dr23381B1bEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   %tobool = icmp ne i32 %0, 0
+// CHECK-NEXT:   ret i1 %tobool
+// CHECK-NEXT: }
+
+} // namespace B
+namespace C {
+enum class E { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define i32 @_ZN6dr23381C1aEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   ret i32 %0
+// CHECK-NEXT: }
+
+E b(int x) { return (E)x; }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define i32 @_ZN6dr23381C1bEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   ret i32 %0
+// CHECK-NEXT: }
+
+} // namespace C
+namespace D {
+enum class E : bool { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define zeroext i1 @_ZN6dr23381D1aEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   %tobool = icmp ne i32 %0, 0
+// CHECK-NEXT:   ret i1 %tobool
+// CHECK-NEXT: }
+
+E b(int x) { return (E)x; }
+
+// CHECK:      ; Function Attrs: noinline nounwind optnone
+// CHECK-NEXT: define zeroext i1 @_ZN6dr23381D1bEi(i32 %x) #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   store i32 %x, i32* %x.addr, align 4
+// CHECK-NEXT:   %0 = load i32, i32* %x.addr, align 4
+// CHECK-NEXT:   %tobool = icmp ne i32 %0, 0
+// CHECK-NEXT:   ret i1 %tobool
+
+} // namespace D
+} // namespace dr2338
Index: clang/test/AST/ast-dump-enum-bool.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/ast-dump-enum-bool.cpp
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown -fsyntax-only -ast-dump %s | FileCheck %s
+
+namespace dr2338 { // dr2338: yes
+namespace A {
+enum E { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+E b(int x) { return (E)x; }
+consteval E c(int x) { return (E)x; }
+} // namespace A
+namespace B {
+enum E : bool { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+E b(int x) { return (E)x; }
+consteval E c(int x) { return (E)x; }
+} // namespace B
+namespace C {
+enum class E { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+E b(int x) { return (E)x; }
+consteval E c(int x) { return (E)x; }
+} // namespace C
+namespace D {
+enum class E : bool { Zero, One };
+E a(int x) { return static_cast<E>(x); }
+E b(int x) { return (E)x; }
+consteval E c(int x) { return (E)x; }
+} // namespace D
+} // namespace dr2338
+
+// CHECK:TranslationUnitDecl {{.*}} <<invalid sloc>> <invalid sloc>
+// CHECK:`-NamespaceDecl {{.*}} <{{.*}}ast-dump-enum-bool.cpp:3:1, line:28:1> line:3:11 dr2338
+// CHECK-NEXT:  |-NamespaceDecl {{.*}} <line:4:1, line:9:1> line:4:11 A
+// CHECK-NEXT:  | |-EnumDecl {{.*}} <line:5:1, col:20> col:6 referenced E
+// CHECK-NEXT:  | | |-EnumConstantDecl {{.*}} <col:10> col:10 Zero 'dr2338::A::E'
+// CHECK-NEXT:  | | `-EnumConstantDecl {{.*}} <col:16> col:16 One 'dr2338::A::E'
+// CHECK-NEXT:  | |-FunctionDecl {{.*}} <line:6:1, col:40> col:3 a 'dr2338::A::E (int)'
+// CHECK-NEXT:  | | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:  | | `-CompoundStmt {{.*}} <col:12, col:40>
+// CHECK-NEXT:  | |   `-ReturnStmt {{.*}} <col:14, col:37>
+// CHECK-NEXT:  | |     `-CXXStaticCastExpr {{.*}} <col:21, col:37> 'dr2338::A::E' static_cast<enum dr2338::A::E> <IntegralCast>
+// CHECK-NEXT:  | |       `-ImplicitCastExpr {{.*}} <col:36> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  | |         `-DeclRefExpr {{.*}} <col:36> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  | |-FunctionDecl {{.*}} <line:7:1, col:27> col:3 b 'dr2338::A::E (int)'
+// CHECK-NEXT:  | | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:  | | `-CompoundStmt {{.*}} <col:12, col:27>
+// CHECK-NEXT:  | |   `-ReturnStmt {{.*}} <col:14, col:24>
+// CHECK-NEXT:  | |     `-CStyleCastExpr {{.*}} <col:21, col:24> 'dr2338::A::E' <IntegralCast>
+// CHECK-NEXT:  | |       `-ImplicitCastExpr {{.*}} <col:24> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  | |         `-DeclRefExpr {{.*}} <col:24> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  | `-FunctionDecl {{.*}} <line:8:1, col:37> col:13 consteval c 'dr2338::A::E (int)'
+// CHECK-NEXT:  |   |-ParmVarDecl {{.*}} <col:15, col:19> col:19 used x 'int'
+// CHECK-NEXT:  |   `-CompoundStmt {{.*}} <col:22, col:37>
+// CHECK-NEXT:  |     `-ReturnStmt {{.*}} <col:24, col:34>
+// CHECK-NEXT:  |       `-CStyleCastExpr {{.*}} <col:31, col:34> 'dr2338::A::E' <IntegralCast>
+// CHECK-NEXT:  |         `-ImplicitCastExpr {{.*}} <col:34> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  |           `-DeclRefExpr {{.*}} <col:34> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  |-NamespaceDecl {{.*}} <line:10:1, line:15:1> line:10:11 B
+// CHECK-NEXT:  | |-EnumDecl {{.*}} <line:11:1, col:27> col:6 referenced E 'bool'
+// CHECK-NEXT:  | | |-EnumConstantDecl {{.*}} <col:17> col:17 Zero 'dr2338::B::E'
+// CHECK-NEXT:  | | `-EnumConstantDecl {{.*}} <col:23> col:23 One 'dr2338::B::E'
+// CHECK-NEXT:  | |-FunctionDecl {{.*}} <line:12:1, col:40> col:3 a 'dr2338::B::E (int)'
+// CHECK-NEXT:  | | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:  | | `-CompoundStmt {{.*}} <col:12, col:40>
+// CHECK-NEXT:  | |   `-ReturnStmt {{.*}} <col:14, col:37>
+// CHECK-NEXT:  | |     `-CXXStaticCastExpr {{.*}} <col:21, col:37> 'dr2338::B::E' static_cast<enum dr2338::B::E> <IntegralToBoolean>
+// CHECK-NEXT:  | |       `-ImplicitCastExpr {{.*}} <col:36> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  | |         `-DeclRefExpr {{.*}} <col:36> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  | |-FunctionDecl {{.*}} <line:13:1, col:27> col:3 b 'dr2338::B::E (int)'
+// CHECK-NEXT:  | | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:  | | `-CompoundStmt {{.*}} <col:12, col:27>
+// CHECK-NEXT:  | |   `-ReturnStmt {{.*}} <col:14, col:24>
+// CHECK-NEXT:  | |     `-CStyleCastExpr {{.*}} <col:21, col:24> 'dr2338::B::E' <IntegralToBoolean>
+// CHECK-NEXT:  | |       `-ImplicitCastExpr {{.*}} <col:24> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  | |         `-DeclRefExpr {{.*}} <col:24> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  | `-FunctionDecl {{.*}} <line:14:1, col:37> col:13 consteval c 'dr2338::B::E (int)'
+// CHECK-NEXT:  |   |-ParmVarDecl {{.*}} <col:15, col:19> col:19 used x 'int'
+// CHECK-NEXT:  |   `-CompoundStmt {{.*}} <col:22, col:37>
+// CHECK-NEXT:  |     `-ReturnStmt {{.*}} <col:24, col:34>
+// CHECK-NEXT:  |       `-CStyleCastExpr {{.*}} <col:31, col:34> 'dr2338::B::E' <IntegralToBoolean>
+// CHECK-NEXT:  |         `-ImplicitCastExpr {{.*}} <col:34> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  |           `-DeclRefExpr {{.*}} <col:34> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  |-NamespaceDecl {{.*}} <line:16:1, line:21:1> line:16:11 C
+// CHECK-NEXT:  | |-EnumDecl {{.*}} <line:17:1, col:26> col:12 referenced class E 'int'
+// CHECK-NEXT:  | | |-EnumConstantDecl {{.*}} <col:16> col:16 Zero 'dr2338::C::E'
+// CHECK-NEXT:  | | `-EnumConstantDecl {{.*}} <col:22> col:22 One 'dr2338::C::E'
+// CHECK-NEXT:  | |-FunctionDecl {{.*}} <line:18:1, col:40> col:3 a 'dr2338::C::E (int)'
+// CHECK-NEXT:  | | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:  | | `-CompoundStmt {{.*}} <col:12, col:40>
+// CHECK-NEXT:  | |   `-ReturnStmt {{.*}} <col:14, col:37>
+// CHECK-NEXT:  | |     `-CXXStaticCastExpr {{.*}} <col:21, col:37> 'dr2338::C::E' static_cast<enum dr2338::C::E> <IntegralCast>
+// CHECK-NEXT:  | |       `-ImplicitCastExpr {{.*}} <col:36> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  | |         `-DeclRefExpr {{.*}} <col:36> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  | |-FunctionDecl {{.*}} <line:19:1, col:27> col:3 b 'dr2338::C::E (int)'
+// CHECK-NEXT:  | | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:  | | `-CompoundStmt {{.*}} <col:12, col:27>
+// CHECK-NEXT:  | |   `-ReturnStmt {{.*}} <col:14, col:24>
+// CHECK-NEXT:  | |     `-CStyleCastExpr {{.*}} <col:21, col:24> 'dr2338::C::E' <IntegralCast>
+// CHECK-NEXT:  | |       `-ImplicitCastExpr {{.*}} <col:24> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  | |         `-DeclRefExpr {{.*}} <col:24> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  | `-FunctionDecl {{.*}} <line:20:1, col:37> col:13 consteval c 'dr2338::C::E (int)'
+// CHECK-NEXT:  |   |-ParmVarDecl {{.*}} <col:15, col:19> col:19 used x 'int'
+// CHECK-NEXT:  |   `-CompoundStmt {{.*}} <col:22, col:37>
+// CHECK-NEXT:  |     `-ReturnStmt {{.*}} <col:24, col:34>
+// CHECK-NEXT:  |       `-CStyleCastExpr {{.*}} <col:31, col:34> 'dr2338::C::E' <IntegralCast>
+// CHECK-NEXT:  |         `-ImplicitCastExpr {{.*}} <col:34> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:  |           `-DeclRefExpr {{.*}} <col:34> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:  `-NamespaceDecl {{.*}} <line:22:1, line:27:1> line:22:11 D
+// CHECK-NEXT:    |-EnumDecl {{.*}} <line:23:1, col:33> col:12 referenced class E 'bool'
+// CHECK-NEXT:    | |-EnumConstantDecl {{.*}} <col:23> col:23 Zero 'dr2338::D::E'
+// CHECK-NEXT:    | `-EnumConstantDecl {{.*}} <col:29> col:29 One 'dr2338::D::E'
+// CHECK-NEXT:    |-FunctionDecl {{.*}} <line:24:1, col:40> col:3 a 'dr2338::D::E (int)'
+// CHECK-NEXT:    | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:    | `-CompoundStmt {{.*}} <col:12, col:40>
+// CHECK-NEXT:    |   `-ReturnStmt {{.*}} <col:14, col:37>
+// CHECK-NEXT:    |     `-CXXStaticCastExpr {{.*}} <col:21, col:37> 'dr2338::D::E' static_cast<enum dr2338::D::E> <IntegralToBoolean>
+// CHECK-NEXT:    |       `-ImplicitCastExpr {{.*}} <col:36> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:    |         `-DeclRefExpr {{.*}} <col:36> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:    |-FunctionDecl {{.*}} <line:25:1, col:27> col:3 b 'dr2338::D::E (int)'
+// CHECK-NEXT:    | |-ParmVarDecl {{.*}} <col:5, col:9> col:9 used x 'int'
+// CHECK-NEXT:    | `-CompoundStmt {{.*}} <col:12, col:27>
+// CHECK-NEXT:    |   `-ReturnStmt {{.*}} <col:14, col:24>
+// CHECK-NEXT:    |     `-CStyleCastExpr {{.*}} <col:21, col:24> 'dr2338::D::E' <IntegralToBoolean>
+// CHECK-NEXT:    |       `-ImplicitCastExpr {{.*}} <col:24> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:    |         `-DeclRefExpr {{.*}} <col:24> 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT:    `-FunctionDecl {{.*}} <line:26:1, col:37> col:13 consteval c 'dr2338::D::E (int)'
+// CHECK-NEXT:      |-ParmVarDecl {{.*}} <col:15, col:19> col:19 used x 'int'
+// CHECK-NEXT:      `-CompoundStmt {{.*}} <col:22, col:37>
+// CHECK-NEXT:        `-ReturnStmt {{.*}} <col:24, col:34>
+// CHECK-NEXT:          `-CStyleCastExpr {{.*}} <col:31, col:34> 'dr2338::D::E' <IntegralToBoolean>
+// CHECK-NEXT:            `-ImplicitCastExpr {{.*}} <col:34> 'int' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT:              `-DeclRefExpr {{.*}} <col:34> 'int' lvalue ParmVar {{.*}} 'x' 'int'
Index: clang/lib/Sema/SemaCast.cpp
===================================================================
--- clang/lib/Sema/SemaCast.cpp
+++ clang/lib/Sema/SemaCast.cpp
@@ -1243,7 +1243,13 @@
       return TC_Failed;
     }
     if (SrcType->isIntegralOrEnumerationType()) {
-      Kind = CK_IntegralCast;
+      // [expr.static.cast]p10 If the enumeration type has a fixed underlying
+      // type, the value is first converted to that type by integral conversion
+      const EnumType *Enum = DestType->getAs<EnumType>();
+      Kind = Enum->getDecl()->isFixed() &&
+                     Enum->getDecl()->getIntegerType()->isBooleanType()
+                 ? CK_IntegralToBoolean
+                 : CK_IntegralCast;
       return TC_Success;
     } else if (SrcType->isRealFloatingType())   {
       Kind = CK_FloatingToIntegral;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to