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
This commit is contained in:
Ismail Pazarbasi 2016-09-07 18:24:54 +00:00
parent f100d4e93d
commit 4a00774e59
3 changed files with 29 additions and 5 deletions

View File

@ -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:

View File

@ -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 {

View File

@ -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