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