Commit 9ce6dc98 authored by Richard Smith's avatar Richard Smith
Browse files

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).
parent 7ef45f45
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -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.
+21 −4
Original line number Diff line number Diff line
@@ -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
+12 −3
Original line number Diff line number Diff line
@@ -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,
+9 −0
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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}}
Loading