Skip to content

Commit 9ce6dc9

Browse files
committed
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).
1 parent 7ef45f4 commit 9ce6dc9

File tree

10 files changed

+75
-24
lines changed

10 files changed

+75
-24
lines changed

clang/include/clang/Sema/Overload.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,24 @@ class Sema;
677677
StdInitializerListElement = V;
678678
}
679679

680+
/// Form an "implicit" conversion sequence from nullptr_t to bool, for a
681+
/// direct-initialization of a bool object from nullptr_t.
682+
static ImplicitConversionSequence getNullptrToBool(QualType SourceType,
683+
QualType DestType,
684+
bool NeedLValToRVal) {
685+
ImplicitConversionSequence ICS;
686+
ICS.setStandard();
687+
ICS.Standard.setAsIdentityConversion();
688+
ICS.Standard.setFromType(SourceType);
689+
if (NeedLValToRVal)
690+
ICS.Standard.First = ICK_Lvalue_To_Rvalue;
691+
ICS.Standard.setToType(0, SourceType);
692+
ICS.Standard.Second = ICK_Boolean_Conversion;
693+
ICS.Standard.setToType(1, DestType);
694+
ICS.Standard.setToType(2, DestType);
695+
return ICS;
696+
}
697+
680698
// The result of a comparison between implicit conversion
681699
// sequences. Use Sema::CompareImplicitConversionSequences to
682700
// actually perform the comparison.

clang/lib/Sema/SemaInit.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4420,16 +4420,20 @@ static void TryListInitialization(Sema &S,
44204420
// direct-list-initialization and copy-initialization otherwise.
44214421
// We can't use InitListChecker for this, because it always performs
44224422
// copy-initialization. This only matters if we might use an 'explicit'
4423-
// conversion operator, so we only need to handle the cases where the source
4424-
// is of record type.
4425-
if (InitList->getInit(0)->getType()->isRecordType()) {
4423+
// conversion operator, or for the special case conversion of nullptr_t to
4424+
// bool, so we only need to handle those cases.
4425+
//
4426+
// FIXME: Why not do this in all cases?
4427+
Expr *Init = InitList->getInit(0);
4428+
if (Init->getType()->isRecordType() ||
4429+
(Init->getType()->isNullPtrType() && DestType->isBooleanType())) {
44264430
InitializationKind SubKind =
44274431
Kind.getKind() == InitializationKind::IK_DirectList
44284432
? InitializationKind::CreateDirect(Kind.getLocation(),
44294433
InitList->getLBraceLoc(),
44304434
InitList->getRBraceLoc())
44314435
: Kind;
4432-
Expr *SubInit[1] = { InitList->getInit(0) };
4436+
Expr *SubInit[1] = { Init };
44334437
Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
44344438
/*TopLevelOfInitList*/true,
44354439
TreatUnavailableAsInvalid);
@@ -5854,6 +5858,19 @@ void InitializationSequence::InitializeFrom(Sema &S,
58545858
return;
58555859
}
58565860

5861+
// - Otherwise, if the initialization is direct-initialization, the source
5862+
// type is std::nullptr_t, and the destination type is bool, the initial
5863+
// value of the object being initialized is false.
5864+
if (!SourceType.isNull() && SourceType->isNullPtrType() &&
5865+
DestType->isBooleanType() &&
5866+
Kind.getKind() == InitializationKind::IK_Direct) {
5867+
AddConversionSequenceStep(
5868+
ImplicitConversionSequence::getNullptrToBool(SourceType, DestType,
5869+
Initializer->isGLValue()),
5870+
DestType);
5871+
return;
5872+
}
5873+
58575874
// - Otherwise, the initial value of the object being initialized is the
58585875
// (possibly converted) value of the initializer expression. Standard
58595876
// conversions (Clause 4) will be used, if necessary, to convert the

clang/lib/Sema/SemaOverload.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
230230
getFromType()->isMemberPointerType() ||
231231
getFromType()->isObjCObjectPointerType() ||
232232
getFromType()->isBlockPointerType() ||
233-
getFromType()->isNullPtrType() ||
234233
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
235234
return true;
236235

@@ -1847,8 +1846,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
18471846
(FromType->isArithmeticType() ||
18481847
FromType->isAnyPointerType() ||
18491848
FromType->isBlockPointerType() ||
1850-
FromType->isMemberPointerType() ||
1851-
FromType->isNullPtrType())) {
1849+
FromType->isMemberPointerType())) {
18521850
// Boolean conversions (C++ 4.12).
18531851
SCS.Second = ICK_Boolean_Conversion;
18541852
FromType = S.Context.BoolTy;
@@ -5437,6 +5435,17 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
54375435
/// expression From to bool (C++0x [conv]p3).
54385436
static ImplicitConversionSequence
54395437
TryContextuallyConvertToBool(Sema &S, Expr *From) {
5438+
// C++ [dcl.init]/17.8:
5439+
// - Otherwise, if the initialization is direct-initialization, the source
5440+
// type is std::nullptr_t, and the destination type is bool, the initial
5441+
// value of the object being initialized is false.
5442+
if (From->getType()->isNullPtrType())
5443+
return ImplicitConversionSequence::getNullptrToBool(From->getType(),
5444+
S.Context.BoolTy,
5445+
From->isGLValue());
5446+
5447+
// All other direct-initialization of bool is equivalent to an implicit
5448+
// conversion to bool in which explicit conversions are permitted.
54405449
return TryImplicitConversion(S, From, S.Context.BoolTy,
54415450
/*SuppressUserConversions=*/false,
54425451
AllowedExplicit::Conversions,

clang/test/CXX/drs/dr14xx.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
// expected-no-diagnostics
99
#endif
1010

11+
namespace dr1423 { // dr1423: 11
12+
#if __cplusplus >= 201103L
13+
bool b1 = nullptr; // expected-error {{cannot initialize}}
14+
bool b2(nullptr); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
15+
bool b3 = {nullptr}; // expected-error {{cannot initialize}}
16+
bool b4{nullptr}; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
17+
#endif
18+
}
19+
1120
// dr1425: na abi
1221

1322
namespace dr1460 { // dr1460: 3.5

clang/test/CXX/drs/dr6xx.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,10 +585,10 @@ namespace dr652 { // dr652: yes
585585
// dr653 FIXME: add codegen test
586586

587587
#if __cplusplus >= 201103L
588-
namespace dr654 { // dr654: yes
588+
namespace dr654 { // dr654: sup 1423
589589
void f() {
590590
if (nullptr) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
591-
bool b = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
591+
bool b = nullptr; // expected-error {{cannot initialize a variable of type 'bool' with an rvalue of type 'nullptr_t'}}
592592
if (nullptr == 0) {}
593593
if (nullptr != 0) {}
594594
if (nullptr <= 0) {} // expected-error {{invalid operands}}

clang/test/CXX/expr/expr.const/p3-0x.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Val<decltype(&noexcept_true), &noexcept_false> add_noexcept;
9595
using Int = A<1.0>; // expected-error {{conversion from 'double' to 'unsigned char' is not allowed in a converted constant expression}}
9696
enum B : bool {
9797
True = &a, // expected-error {{conversion from 'bool (*)(int)' to 'bool' is not allowed in a converted constant expression}}
98-
False = nullptr // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}}
98+
False = 0.0, // expected-error {{conversion from 'double' to 'bool' is not allowed in a converted constant expression}}
9999
};
100100
void c() {
101101
// Note, promoted type of switch is 'int'.

clang/test/CodeGenCXX/nullptr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ union U {
3232
// CHECK: load
3333
// CHECK-NOT: load
3434
// CHECK: ret i1 false
35-
bool pr23833_a(U &u) { return u.b; }
35+
bool pr23833_a(U &u) { return bool(u.b); }
3636

3737
// CHECK-LABEL: define {{.*}}pr23833_b
3838
// CHECK: store

clang/test/SemaCXX/conversion.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 -verify %s
2-
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 %s 2>&1 | FileCheck %s
2+
// RUN: not %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 %s 2>&1 | FileCheck %s
33

44
#include <stddef.h>
55

@@ -129,9 +129,9 @@ namespace test6 {
129129

130130
namespace test7 {
131131
bool fun() {
132-
bool x = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
132+
bool x = nullptr; // expected-error {{cannot initialize}}
133133
if (nullptr) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
134-
return nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
134+
return nullptr; // expected-error {{cannot initialize}}
135135
}
136136
}
137137

@@ -198,14 +198,12 @@ namespace test8 {
198198
}
199199
}
200200

201-
// Don't warn on a nullptr to bool conversion when the nullptr is the return
202-
// type of a function.
203201
namespace test9 {
204202
typedef decltype(nullptr) nullptr_t;
205203
nullptr_t EXIT();
206204

207205
bool test() {
208-
return EXIT();
206+
return EXIT(); // expected-error {{cannot initialize}}
209207
}
210208
}
211209

@@ -273,10 +271,10 @@ void function1(const char* str) {
273271
CHECK13(check_str_null_13(str));
274272
}
275273

276-
bool some_bool_function(bool);
274+
bool some_bool_function(bool); // expected-note {{no known conversion}}
277275
void function2() {
278-
CHECK13(some_bool_function(nullptr)); // expected-warning{{implicit conversion of nullptr constant to 'bool'}}
279-
CHECK13(some_bool_function(NULL)); // expected-warning{{implicit conversion of NULL constant to 'bool'}}
276+
CHECK13(some_bool_function(nullptr)); // expected-error {{no matching function}}
277+
CHECK13(some_bool_function(NULL)); // expected-warning {{implicit conversion of NULL constant to 'bool'}}
280278
}
281279

282280
#define run_check_nullptr_13(str) \

clang/test/SemaCXX/nullptr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ nullptr_t f(nullptr_t null)
2525
pf = null;
2626
void (A::*pmf)() = nullptr;
2727
pmf = null;
28-
bool b = nullptr;
28+
bool b = nullptr; // expected-error {{cannot initialize}}
2929

3030
// Can't convert nullptr to integral implicitly.
3131
uintptr_t i = nullptr; // expected-error {{cannot initialize}}

clang/www/cxx_dr_status.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,7 +1504,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
15041504
<td><a href="https://wg21.link/cwg244">244</a></td>
15051505
<td>CD1</td>
15061506
<td>Destructor lookup</td>
1507-
<td class="partial" align="center">Partial</td>
1507+
<td class="unreleased" align="center">Clang 11</td>
15081508
</tr>
15091509
<tr id="245">
15101510
<td><a href="https://wg21.link/cwg245">245</a></td>
@@ -3967,7 +3967,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
39673967
<td><a href="https://wg21.link/cwg654">654</a></td>
39683968
<td>CD1</td>
39693969
<td>Conversions to and from <TT>nullptr_t</TT></td>
3970-
<td class="full" align="center">Yes</td>
3970+
<td class="unreleased" align="center">Superseded by <a href="#1423">1423</a></td>
39713971
</tr>
39723972
<tr id="655">
39733973
<td><a href="https://wg21.link/cwg655">655</a></td>
@@ -8353,7 +8353,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
83538353
<td><a href="https://wg21.link/cwg1423">1423</a></td>
83548354
<td>CD3</td>
83558355
<td>Convertibility of <TT>nullptr</TT> to <TT>bool</TT></td>
8356-
<td class="none" align="center">Unknown</td>
8356+
<td class="unreleased" align="center">Clang 11</td>
83578357
</tr>
83588358
<tr id="1424">
83598359
<td><a href="https://wg21.link/cwg1424">1424</a></td>

0 commit comments

Comments
 (0)