diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index a274102ceb11e..f1a8b98e5efdc 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -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. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 61b7c166239f2..61bb1f053ce2e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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 diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1e838fd751305..a10b7cd764827 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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, diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp index 52129844c4188..d55427f5de8cb 100644 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -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 diff --git a/clang/test/CXX/drs/dr6xx.cpp b/clang/test/CXX/drs/dr6xx.cpp index 7a0adb5fe406b..4c4ed7767ecd2 100644 --- a/clang/test/CXX/drs/dr6xx.cpp +++ b/clang/test/CXX/drs/dr6xx.cpp @@ -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}} diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp index 731e0c312fa13..8daca7a565f31 100644 --- a/clang/test/CXX/expr/expr.const/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp @@ -95,7 +95,7 @@ Val 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'. diff --git a/clang/test/CodeGenCXX/nullptr.cpp b/clang/test/CodeGenCXX/nullptr.cpp index 823c0d7d18a73..ab47282569fd6 100644 --- a/clang/test/CodeGenCXX/nullptr.cpp +++ b/clang/test/CodeGenCXX/nullptr.cpp @@ -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 diff --git a/clang/test/SemaCXX/conversion.cpp b/clang/test/SemaCXX/conversion.cpp index dcd64fa2ec8ae..67bfdf5532b5d 100644 --- a/clang/test/SemaCXX/conversion.cpp +++ b/clang/test/SemaCXX/conversion.cpp @@ -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 @@ -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) \ diff --git a/clang/test/SemaCXX/nullptr.cpp b/clang/test/SemaCXX/nullptr.cpp index 9a092910b6f97..23ea383c3e87c 100644 --- a/clang/test/SemaCXX/nullptr.cpp +++ b/clang/test/SemaCXX/nullptr.cpp @@ -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}} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index d4c6175a8c1b5..3e9210f861abf 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -1504,7 +1504,7 @@

C++ defect report implementation status

244 CD1 Destructor lookup - Partial + Clang 11 245 @@ -3967,7 +3967,7 @@

C++ defect report implementation status

654 CD1 Conversions to and from nullptr_t - Yes + Superseded by 1423 655 @@ -8353,7 +8353,7 @@

C++ defect report implementation status

1423 CD3 Convertibility of nullptr to bool - Unknown + Clang 11 1424