From 4055de40abf5536e4b88b399ca89274a1eec8869 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 13 Jun 2013 02:46:14 +0000 Subject: [PATCH] Implement core issue 903: only integer literals with value 0 and prvalues of type std::nullptr_t are null pointer constants from C++11 onwards. llvm-svn: 183883 --- clang/lib/AST/Expr.cpp | 17 +++++++------- .../SemaCXX/constant-expression-cxx11.cpp | 19 ++++++++++----- clang/test/SemaCXX/lambda-expressions.cpp | 23 +++++++++++-------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index ecd147aebe34..aaf80207920f 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3024,7 +3024,7 @@ bool Expr::hasNonTrivialCall(ASTContext &Ctx) { Expr::NullPointerConstantKind Expr::isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const { - if (isValueDependent()) { + if (isValueDependent() && !Ctx.getLangOpts().CPlusPlus11) { switch (NPC) { case NPC_NeverValueDependent: llvm_unreachable("Unexpected value dependent expression!"); @@ -3085,7 +3085,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) - if (UT && UT->getDecl()->hasAttr()) + if (!Ctx.getLangOpts().CPlusPlus11 && + UT && UT->getDecl()->hasAttr()) if (const CompoundLiteralExpr *CLE = dyn_cast(this)){ const Expr *InitExpr = CLE->getInitializer(); if (const InitListExpr *ILE = dyn_cast(InitExpr)) @@ -3096,14 +3097,14 @@ Expr::isNullPointerConstant(ASTContext &Ctx, (Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType())) return NPCK_NotNull; - // If we have an integer constant expression, we need to *evaluate* it and - // test for the value 0. Don't use the C++11 constant expression semantics - // for this, for now; once the dust settles on core issue 903, we might only - // allow a literal 0 here in C++11 mode. if (Ctx.getLangOpts().CPlusPlus11) { - if (!isCXX98IntegralConstantExpr(Ctx)) - return NPCK_NotNull; + // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with + // value zero or a prvalue of type std::nullptr_t. + const IntegerLiteral *Lit = dyn_cast(this); + return (Lit && !Lit->getValue()) ? NPCK_ZeroLiteral : NPCK_NotNull; } else { + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. if (!isIntegerConstantExpr(Ctx)) return NPCK_NotNull; } diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index e4db1b3405a3..173172a3abfb 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -769,15 +769,22 @@ static_assert(&ok2 == pok2, ""); static_assert((Base2*)(Derived*)(Base*)pb1 == pok2, ""); static_assert((Derived*)(Base*)pb1 == (Derived*)pok2, ""); -constexpr Base *nullB = 42 - 6 * 7; // expected-warning {{expression which evaluates to zero treated as a null pointer constant of type 'Class::Base *const'}} +// Core issue 903: we do not perform constant evaluation when checking for a +// null pointer in C++11. Just check for an integer literal with value 0. +constexpr Base *nullB = 42 - 6 * 7; // expected-error {{cannot initialize a variable of type 'Class::Base *const' with an rvalue of type 'int'}} +constexpr Base *nullB1 = 0; static_assert((Bottom*)nullB == 0, ""); static_assert((Derived*)nullB == 0, ""); static_assert((void*)(Bottom*)nullB == (void*)(Derived*)nullB, ""); -Base * nullB2 = '\0'; // expected-warning {{expression which evaluates to zero treated as a null pointer constant of type 'Class::Base *'}} -Base * nullB3 = (0); -// We suppress the warning in unevaluated contexts to workaround some gtest -// behavior. Once this becomes an error this isn't a problem anymore. -static_assert(nullB == (1 - 1), ""); +Base *nullB2 = '\0'; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'char'}} +Base *nullB3 = (0); +Base *nullB4 = false; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'bool'}} +Base *nullB5 = ((0ULL)); +Base *nullB6 = 0.; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'double'}} +enum Null { kNull }; +Base *nullB7 = kNull; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'Class::Null'}} +static_assert(nullB1 == (1 - 1), ""); // expected-error {{comparison between pointer and integer}} + namespace ConversionOperators { diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index a333f38530b3..83c5215d7453 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -109,27 +109,30 @@ namespace PR12031 { } } -namespace NullPtr { +namespace Array { int &f(int *p); char &f(...); void g() { - int n = 0; + int n = -1; [=] { - char &k = f(n); // not a null pointer constant + int arr[n]; // VLA } (); - const int m = 0; - [=] { - int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} + const int m = -1; + [] { + int arr[m]; // expected-error{{negative size}} } (); - [=] () -> bool { - int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} - return &m == 0; + [&] { + int arr[m]; // expected-error{{negative size}} + } (); + + [=] { + int arr[m]; // expected-error{{negative size}} } (); [m] { - int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} + int arr[m]; // expected-error{{negative size}} } (); } }