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(); + Kind = Enum->getDecl()->isFixed() && + Enum->getDecl()->getIntegerType()->isBooleanType() + ? CK_IntegralToBoolean + : CK_IntegralCast; return TC_Success; } else if (SrcType->isRealFloatingType()) { Kind = CK_FloatingToIntegral; 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(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(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(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(x); } +E b(int x) { return (E)x; } +consteval E c(int x) { return (E)x; } +} // namespace D +} // namespace dr2338 + +// CHECK:TranslationUnitDecl {{.*}} <> +// CHECK:`-NamespaceDecl {{.*}} <{{.*}}ast-dump-enum-bool.cpp:3:1, line:28:1> line:3:11 dr2338 +// CHECK-NEXT: |-NamespaceDecl {{.*}} line:4:11 A +// CHECK-NEXT: | |-EnumDecl {{.*}} col:6 referenced E +// CHECK-NEXT: | | |-EnumConstantDecl {{.*}} col:10 Zero 'dr2338::A::E' +// CHECK-NEXT: | | `-EnumConstantDecl {{.*}} col:16 One 'dr2338::A::E' +// CHECK-NEXT: | |-FunctionDecl {{.*}} col:3 a 'dr2338::A::E (int)' +// CHECK-NEXT: | | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | `-CXXStaticCastExpr {{.*}} 'dr2338::A::E' static_cast +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: | |-FunctionDecl {{.*}} col:3 b 'dr2338::A::E (int)' +// CHECK-NEXT: | | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | `-CStyleCastExpr {{.*}} 'dr2338::A::E' +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: | `-FunctionDecl {{.*}} col:13 consteval c 'dr2338::A::E (int)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} col:19 used x 'int' +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-CStyleCastExpr {{.*}} 'dr2338::A::E' +// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: |-NamespaceDecl {{.*}} line:10:11 B +// CHECK-NEXT: | |-EnumDecl {{.*}} col:6 referenced E 'bool' +// CHECK-NEXT: | | |-EnumConstantDecl {{.*}} col:17 Zero 'dr2338::B::E' +// CHECK-NEXT: | | `-EnumConstantDecl {{.*}} col:23 One 'dr2338::B::E' +// CHECK-NEXT: | |-FunctionDecl {{.*}} col:3 a 'dr2338::B::E (int)' +// CHECK-NEXT: | | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | `-CXXStaticCastExpr {{.*}} 'dr2338::B::E' static_cast +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: | |-FunctionDecl {{.*}} col:3 b 'dr2338::B::E (int)' +// CHECK-NEXT: | | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | `-CStyleCastExpr {{.*}} 'dr2338::B::E' +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: | `-FunctionDecl {{.*}} col:13 consteval c 'dr2338::B::E (int)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} col:19 used x 'int' +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-CStyleCastExpr {{.*}} 'dr2338::B::E' +// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: |-NamespaceDecl {{.*}} line:16:11 C +// CHECK-NEXT: | |-EnumDecl {{.*}} col:12 referenced class E 'int' +// CHECK-NEXT: | | |-EnumConstantDecl {{.*}} col:16 Zero 'dr2338::C::E' +// CHECK-NEXT: | | `-EnumConstantDecl {{.*}} col:22 One 'dr2338::C::E' +// CHECK-NEXT: | |-FunctionDecl {{.*}} col:3 a 'dr2338::C::E (int)' +// CHECK-NEXT: | | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | `-CXXStaticCastExpr {{.*}} 'dr2338::C::E' static_cast +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: | |-FunctionDecl {{.*}} col:3 b 'dr2338::C::E (int)' +// CHECK-NEXT: | | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | `-CStyleCastExpr {{.*}} 'dr2338::C::E' +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: | `-FunctionDecl {{.*}} col:13 consteval c 'dr2338::C::E (int)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} col:19 used x 'int' +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-CStyleCastExpr {{.*}} 'dr2338::C::E' +// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: `-NamespaceDecl {{.*}} line:22:11 D +// CHECK-NEXT: |-EnumDecl {{.*}} col:12 referenced class E 'bool' +// CHECK-NEXT: | |-EnumConstantDecl {{.*}} col:23 Zero 'dr2338::D::E' +// CHECK-NEXT: | `-EnumConstantDecl {{.*}} col:29 One 'dr2338::D::E' +// CHECK-NEXT: |-FunctionDecl {{.*}} col:3 a 'dr2338::D::E (int)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-CXXStaticCastExpr {{.*}} 'dr2338::D::E' static_cast +// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: |-FunctionDecl {{.*}} col:3 b 'dr2338::D::E (int)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} col:9 used x 'int' +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-CStyleCastExpr {{.*}} 'dr2338::D::E' +// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' +// CHECK-NEXT: `-FunctionDecl {{.*}} col:13 consteval c 'dr2338::D::E (int)' +// CHECK-NEXT: |-ParmVarDecl {{.*}} col:19 used x 'int' +// CHECK-NEXT: `-CompoundStmt {{.*}} +// CHECK-NEXT: `-ReturnStmt {{.*}} +// CHECK-NEXT: `-CStyleCastExpr {{.*}} 'dr2338::D::E' +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' part_of_explicit_cast +// CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' 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(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(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(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(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/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(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(c(2)) == 1); +} // namespace D +} // namespace dr2338