forked from OSchip/llvm-project
CWG1423: don't permit implicit conversion of nullptr_t to bool.
The C++ rules briefly allowed this, but the rule changed nearly 10 years ago and we never updated our implementation to match. However, we've warned on this by default for a long time, and no other compiler accepts (even as an extension).
This commit is contained in:
parent
7ef45f45f6
commit
9ce6dc9872
|
@ -677,6 +677,24 @@ class Sema;
|
|||
StdInitializerListElement = V;
|
||||
}
|
||||
|
||||
/// Form an "implicit" conversion sequence from nullptr_t to bool, for a
|
||||
/// direct-initialization of a bool object from nullptr_t.
|
||||
static ImplicitConversionSequence getNullptrToBool(QualType SourceType,
|
||||
QualType DestType,
|
||||
bool NeedLValToRVal) {
|
||||
ImplicitConversionSequence ICS;
|
||||
ICS.setStandard();
|
||||
ICS.Standard.setAsIdentityConversion();
|
||||
ICS.Standard.setFromType(SourceType);
|
||||
if (NeedLValToRVal)
|
||||
ICS.Standard.First = ICK_Lvalue_To_Rvalue;
|
||||
ICS.Standard.setToType(0, SourceType);
|
||||
ICS.Standard.Second = ICK_Boolean_Conversion;
|
||||
ICS.Standard.setToType(1, DestType);
|
||||
ICS.Standard.setToType(2, DestType);
|
||||
return ICS;
|
||||
}
|
||||
|
||||
// The result of a comparison between implicit conversion
|
||||
// sequences. Use Sema::CompareImplicitConversionSequences to
|
||||
// actually perform the comparison.
|
||||
|
|
|
@ -4420,16 +4420,20 @@ static void TryListInitialization(Sema &S,
|
|||
// direct-list-initialization and copy-initialization otherwise.
|
||||
// We can't use InitListChecker for this, because it always performs
|
||||
// copy-initialization. This only matters if we might use an 'explicit'
|
||||
// conversion operator, so we only need to handle the cases where the source
|
||||
// is of record type.
|
||||
if (InitList->getInit(0)->getType()->isRecordType()) {
|
||||
// conversion operator, or for the special case conversion of nullptr_t to
|
||||
// bool, so we only need to handle those cases.
|
||||
//
|
||||
// FIXME: Why not do this in all cases?
|
||||
Expr *Init = InitList->getInit(0);
|
||||
if (Init->getType()->isRecordType() ||
|
||||
(Init->getType()->isNullPtrType() && DestType->isBooleanType())) {
|
||||
InitializationKind SubKind =
|
||||
Kind.getKind() == InitializationKind::IK_DirectList
|
||||
? InitializationKind::CreateDirect(Kind.getLocation(),
|
||||
InitList->getLBraceLoc(),
|
||||
InitList->getRBraceLoc())
|
||||
: Kind;
|
||||
Expr *SubInit[1] = { InitList->getInit(0) };
|
||||
Expr *SubInit[1] = { Init };
|
||||
Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
|
||||
/*TopLevelOfInitList*/true,
|
||||
TreatUnavailableAsInvalid);
|
||||
|
@ -5854,6 +5858,19 @@ void InitializationSequence::InitializeFrom(Sema &S,
|
|||
return;
|
||||
}
|
||||
|
||||
// - Otherwise, if the initialization is direct-initialization, the source
|
||||
// type is std::nullptr_t, and the destination type is bool, the initial
|
||||
// value of the object being initialized is false.
|
||||
if (!SourceType.isNull() && SourceType->isNullPtrType() &&
|
||||
DestType->isBooleanType() &&
|
||||
Kind.getKind() == InitializationKind::IK_Direct) {
|
||||
AddConversionSequenceStep(
|
||||
ImplicitConversionSequence::getNullptrToBool(SourceType, DestType,
|
||||
Initializer->isGLValue()),
|
||||
DestType);
|
||||
return;
|
||||
}
|
||||
|
||||
// - Otherwise, the initial value of the object being initialized is the
|
||||
// (possibly converted) value of the initializer expression. Standard
|
||||
// conversions (Clause 4) will be used, if necessary, to convert the
|
||||
|
|
|
@ -230,7 +230,6 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
|
|||
getFromType()->isMemberPointerType() ||
|
||||
getFromType()->isObjCObjectPointerType() ||
|
||||
getFromType()->isBlockPointerType() ||
|
||||
getFromType()->isNullPtrType() ||
|
||||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
|
||||
return true;
|
||||
|
||||
|
@ -1847,8 +1846,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
|||
(FromType->isArithmeticType() ||
|
||||
FromType->isAnyPointerType() ||
|
||||
FromType->isBlockPointerType() ||
|
||||
FromType->isMemberPointerType() ||
|
||||
FromType->isNullPtrType())) {
|
||||
FromType->isMemberPointerType())) {
|
||||
// Boolean conversions (C++ 4.12).
|
||||
SCS.Second = ICK_Boolean_Conversion;
|
||||
FromType = S.Context.BoolTy;
|
||||
|
@ -5437,6 +5435,17 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
|
|||
/// expression From to bool (C++0x [conv]p3).
|
||||
static ImplicitConversionSequence
|
||||
TryContextuallyConvertToBool(Sema &S, Expr *From) {
|
||||
// C++ [dcl.init]/17.8:
|
||||
// - Otherwise, if the initialization is direct-initialization, the source
|
||||
// type is std::nullptr_t, and the destination type is bool, the initial
|
||||
// value of the object being initialized is false.
|
||||
if (From->getType()->isNullPtrType())
|
||||
return ImplicitConversionSequence::getNullptrToBool(From->getType(),
|
||||
S.Context.BoolTy,
|
||||
From->isGLValue());
|
||||
|
||||
// All other direct-initialization of bool is equivalent to an implicit
|
||||
// conversion to bool in which explicit conversions are permitted.
|
||||
return TryImplicitConversion(S, From, S.Context.BoolTy,
|
||||
/*SuppressUserConversions=*/false,
|
||||
AllowedExplicit::Conversions,
|
||||
|
|
|
@ -8,6 +8,15 @@
|
|||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
namespace dr1423 { // dr1423: 11
|
||||
#if __cplusplus >= 201103L
|
||||
bool b1 = nullptr; // expected-error {{cannot initialize}}
|
||||
bool b2(nullptr); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
bool b3 = {nullptr}; // expected-error {{cannot initialize}}
|
||||
bool b4{nullptr}; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
#endif
|
||||
}
|
||||
|
||||
// dr1425: na abi
|
||||
|
||||
namespace dr1460 { // dr1460: 3.5
|
||||
|
|
|
@ -585,10 +585,10 @@ namespace dr652 { // dr652: yes
|
|||
// dr653 FIXME: add codegen test
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
namespace dr654 { // dr654: yes
|
||||
namespace dr654 { // dr654: sup 1423
|
||||
void f() {
|
||||
if (nullptr) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
bool b = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
bool b = nullptr; // expected-error {{cannot initialize a variable of type 'bool' with an rvalue of type 'nullptr_t'}}
|
||||
if (nullptr == 0) {}
|
||||
if (nullptr != 0) {}
|
||||
if (nullptr <= 0) {} // expected-error {{invalid operands}}
|
||||
|
|
|
@ -95,7 +95,7 @@ Val<decltype(&noexcept_true), &noexcept_false> add_noexcept;
|
|||
using Int = A<1.0>; // expected-error {{conversion from 'double' to 'unsigned char' is not allowed in a converted constant expression}}
|
||||
enum B : bool {
|
||||
True = &a, // expected-error {{conversion from 'bool (*)(int)' to 'bool' is not allowed in a converted constant expression}}
|
||||
False = nullptr // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}}
|
||||
False = 0.0, // expected-error {{conversion from 'double' to 'bool' is not allowed in a converted constant expression}}
|
||||
};
|
||||
void c() {
|
||||
// Note, promoted type of switch is 'int'.
|
||||
|
|
|
@ -32,7 +32,7 @@ union U {
|
|||
// CHECK: load
|
||||
// CHECK-NOT: load
|
||||
// CHECK: ret i1 false
|
||||
bool pr23833_a(U &u) { return u.b; }
|
||||
bool pr23833_a(U &u) { return bool(u.b); }
|
||||
|
||||
// CHECK-LABEL: define {{.*}}pr23833_b
|
||||
// CHECK: store
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 %s 2>&1 | FileCheck %s
|
||||
// RUN: not %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 %s 2>&1 | FileCheck %s
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -129,9 +129,9 @@ namespace test6 {
|
|||
|
||||
namespace test7 {
|
||||
bool fun() {
|
||||
bool x = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
bool x = nullptr; // expected-error {{cannot initialize}}
|
||||
if (nullptr) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
return nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
|
||||
return nullptr; // expected-error {{cannot initialize}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,14 +198,12 @@ namespace test8 {
|
|||
}
|
||||
}
|
||||
|
||||
// Don't warn on a nullptr to bool conversion when the nullptr is the return
|
||||
// type of a function.
|
||||
namespace test9 {
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
nullptr_t EXIT();
|
||||
|
||||
bool test() {
|
||||
return EXIT();
|
||||
return EXIT(); // expected-error {{cannot initialize}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,10 +271,10 @@ void function1(const char* str) {
|
|||
CHECK13(check_str_null_13(str));
|
||||
}
|
||||
|
||||
bool some_bool_function(bool);
|
||||
bool some_bool_function(bool); // expected-note {{no known conversion}}
|
||||
void function2() {
|
||||
CHECK13(some_bool_function(nullptr)); // expected-warning{{implicit conversion of nullptr constant to 'bool'}}
|
||||
CHECK13(some_bool_function(NULL)); // expected-warning{{implicit conversion of NULL constant to 'bool'}}
|
||||
CHECK13(some_bool_function(nullptr)); // expected-error {{no matching function}}
|
||||
CHECK13(some_bool_function(NULL)); // expected-warning {{implicit conversion of NULL constant to 'bool'}}
|
||||
}
|
||||
|
||||
#define run_check_nullptr_13(str) \
|
||||
|
|
|
@ -25,7 +25,7 @@ nullptr_t f(nullptr_t null)
|
|||
pf = null;
|
||||
void (A::*pmf)() = nullptr;
|
||||
pmf = null;
|
||||
bool b = nullptr;
|
||||
bool b = nullptr; // expected-error {{cannot initialize}}
|
||||
|
||||
// Can't convert nullptr to integral implicitly.
|
||||
uintptr_t i = nullptr; // expected-error {{cannot initialize}}
|
||||
|
|
|
@ -1504,7 +1504,7 @@ accessible?</td>
|
|||
<td><a href="https://wg21.link/cwg244">244</a></td>
|
||||
<td>CD1</td>
|
||||
<td>Destructor lookup</td>
|
||||
<td class="partial" align="center">Partial</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
</tr>
|
||||
<tr id="245">
|
||||
<td><a href="https://wg21.link/cwg245">245</a></td>
|
||||
|
@ -3967,7 +3967,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg654">654</a></td>
|
||||
<td>CD1</td>
|
||||
<td>Conversions to and from <TT>nullptr_t</TT></td>
|
||||
<td class="full" align="center">Yes</td>
|
||||
<td class="unreleased" align="center">Superseded by <a href="#1423">1423</a></td>
|
||||
</tr>
|
||||
<tr id="655">
|
||||
<td><a href="https://wg21.link/cwg655">655</a></td>
|
||||
|
@ -8353,7 +8353,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg1423">1423</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Convertibility of <TT>nullptr</TT> to <TT>bool</TT></td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
</tr>
|
||||
<tr id="1424">
|
||||
<td><a href="https://wg21.link/cwg1424">1424</a></td>
|
||||
|
|
Loading…
Reference in New Issue