From 4a00774e59c71864e8d65b5dbdb42b3cb84e77b5 Mon Sep 17 00:00:00 2001 From: Ismail Pazarbasi Date: Wed, 7 Sep 2016 18:24:54 +0000 Subject: [PATCH] Try contextually converting condition of constexpr if to Boolean value Summary: C++1z 6.4.1/p2: If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool [...] C++1z 5.20/p4: [...] A contextually converted constant expression of type bool is an expression, contextually converted to bool (Clause4), where the converted expression is a constant expression and the conversion sequence contains only the conversions above. [...] Contextually converting result of an expression `e` to a Boolean value requires `bool t(e)` to be well-formed. An explicit conversion function is only considered as a user-defined conversion for direct-initialization, which is essentially what //contextually converted to bool// requires. Also, fixes PR28470. Reviewers: rsmith Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D24158 llvm-svn: 280838 --- clang/lib/Sema/SemaOverload.cpp | 16 +++++++++++----- clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp | 5 +++++ clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp | 13 +++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 37552b5..183fdf4 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5164,12 +5164,18 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, // implicitly converted to type T, where the converted // expression is a constant expression and the implicit conversion // sequence contains only [... list of conversions ...]. + // C++1z [stmt.if]p2: + // If the if statement is of the form if constexpr, the value of the + // condition shall be a contextually converted constant expression of type + // bool. ImplicitConversionSequence ICS = - TryCopyInitialization(S, From, T, - /*SuppressUserConversions=*/false, - /*InOverloadResolution=*/false, - /*AllowObjcWritebackConversion=*/false, - /*AllowExplicit=*/false); + CCE == Sema::CCEK_ConstexprIf + ? TryContextuallyConvertToBool(S, From) + : TryCopyInitialization(S, From, T, + /*SuppressUserConversions=*/false, + /*InOverloadResolution=*/false, + /*AllowObjcWritebackConversion=*/false, + /*AllowExplicit=*/false); StandardConversionSequence *SCS = nullptr; switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: diff --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp index d6a2169..c33bf0e 100644 --- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp @@ -46,6 +46,11 @@ namespace ccce { if constexpr (N) {} // expected-error {{cannot be narrowed}} } template void g<5>(); // expected-note {{instantiation of}} + void h() { + if constexpr (4.3) {} // expected-error{{conversion from 'double' to 'bool' is not allowed in a converted constant expression}} + constexpr void *p = nullptr; + if constexpr (p) {} // expected-error{{conversion from 'void *const' to 'bool' is not allowed in a converted constant expression}} + } } namespace generic_lambda { diff --git a/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp b/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp index 80a397f..1469536 100644 --- a/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp +++ b/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp @@ -2,7 +2,15 @@ void should_be_used_1(); void should_be_used_2(); +void should_be_used_3(); void should_not_be_used(); + +struct A { + constexpr explicit operator bool() const { + return true; + } +}; + void f() { if constexpr (false) should_not_be_used(); @@ -15,7 +23,12 @@ void f() { goto foo; foo: should_not_be_used(); } + if constexpr (A()) + should_be_used_3(); + else + should_not_be_used(); } // CHECK: should_be_used_1 // CHECK: should_be_used_2 +// CHECK: should_be_used_3 -- 2.7.4