From fef26071240711e8f7305715b5f22cfc7ad04bfe Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 16 Aug 2020 18:40:08 +0200 Subject: [PATCH] [Sema] Use the proper cast for a fixed bool enum. When casting an enumerate with a fixed bool type the casting should use an IntegralToBoolean instead of an IntegralCast as is required per Core Issue 2338. Fixes PR47055: Incorrect codegen for enum with bool underlying type Differential Revision: https://reviews.llvm.org/D85612 --- clang/lib/Sema/SemaCast.cpp | 8 ++++++- clang/test/CXX/drs/dr23xx.cpp | 13 +++++++++++ clang/test/CodeGen/enum-bool.cpp | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/enum-bool.cpp diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 9375276..726900c 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -1243,7 +1243,13 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, 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; diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp index c265ebb..a7ff2a5 100644 --- a/clang/test/CXX/drs/dr23xx.cpp +++ b/clang/test/CXX/drs/dr23xx.cpp @@ -4,6 +4,19 @@ // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s // RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s +#if __cplusplus >= 201103L +namespace dr2338 { // dr2338: 12 +namespace B { +enum E : bool { Zero, One }; +static_assert((int)(E)2 == 1, ""); +} // namespace B +namespace D { +enum class E : bool { Zero, One }; +static_assert((int)(E)2 == 1, ""); +} // namespace D +} // namespace dr2338 +#endif + namespace dr2346 { // dr2346: 11 void test() { const int i2 = 0; diff --git a/clang/test/CodeGen/enum-bool.cpp b/clang/test/CodeGen/enum-bool.cpp new file mode 100644 index 0000000..220baa3 --- /dev/null +++ b/clang/test/CodeGen/enum-bool.cpp @@ -0,0 +1,49 @@ +// 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-LABEL: define i32 @_ZN6dr23381A1aEi +// CHECK: ret i32 %0 + +E b(int x) { return (E)x; } +// CHECK-LABEL: define i32 @_ZN6dr23381A1bEi +// CHECK: ret i32 %0 + +} // namespace A +namespace B { +enum E : bool { Zero, One }; +E a(int x) { return static_cast(x); } +// CHECK-LABEL: define zeroext i1 @_ZN6dr23381B1aEi +// CHECK: ret i1 %tobool + +E b(int x) { return (E)x; } +// CHECK-LABEL: define zeroext i1 @_ZN6dr23381B1bEi +// CHECK: ret i1 %tobool + +} // namespace B +namespace C { +enum class E { Zero, One }; +E a(int x) { return static_cast(x); } +// CHECK-LABEL: define i32 @_ZN6dr23381C1aEi +// CHECK: ret i32 %0 + +E b(int x) { return (E)x; } +// CHECK-LABEL: define i32 @_ZN6dr23381C1bEi +// CHECK: ret i32 %0 + +} // namespace C +namespace D { +enum class E : bool { Zero, One }; +E a(int x) { return static_cast(x); } +// CHECK-LABEL: define zeroext i1 @_ZN6dr23381D1aEi +// CHECK: ret i1 %tobool + +E b(int x) { return (E)x; } + +// CHECK-LABEL: define zeroext i1 @_ZN6dr23381D1bEi +// CHECK: ret i1 %tobool + +} // namespace D +} // namespace dr2338 -- 2.7.4