diff options
-rw-r--r-- | include/clang/AST/Expr.h | 11 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 18 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/lambda-expressions.cpp | 6 | ||||
-rw-r--r-- | test/SemaTemplate/explicit-instantiation.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-member-class.cpp | 7 |
10 files changed, 53 insertions, 22 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 29e3649a27..89c003c8f6 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -541,8 +541,15 @@ public: /// \brief Expression is not a Null pointer constant. NPCK_NotNull = 0, - /// \brief Expression is a Null pointer constant built from a zero integer. - NPCK_ZeroInteger, + /// \brief Expression is a Null pointer constant built from a zero integer + /// expression that is not a simple, possibly parenthesized, zero literal. + /// C++ Core Issue 903 will classify these expressions as "not pointers" + /// once it is adopted. + /// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903 + NPCK_ZeroExpression, + + /// \brief Expression is a Null pointer constant built from a literal zero. + NPCK_ZeroLiteral, /// \brief Expression is a C++0X nullptr. NPCK_CXX0X_nullptr, diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 8811e6aa36..b95a90bd21 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -33,6 +33,7 @@ def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; def BoolConversion : DiagGroup<"bool-conversion">; def IntConversion : DiagGroup<"int-conversion">; +def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">; def NullConversion : DiagGroup<"null-conversion">; def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">; def CXXCompat: DiagGroup<"c++-compat">; @@ -314,7 +315,8 @@ def Conversion : DiagGroup<"conversion", StringConversion, SignConversion, BoolConversion, - NullConversion, + NullConversion, // NULL->non-pointer + NonLiteralNullConversion, // (1-1)->pointer (etc) IntConversion]>, DiagCategory<"Value Conversion Issue">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 566a8f01fa..7b3cd0fb77 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1896,6 +1896,9 @@ def warn_impcast_different_enum_types : Warning< def warn_impcast_bool_to_null_pointer : Warning< "initialization of pointer of type %0 to null from a constant boolean " "expression">, InGroup<BoolConversion>; +def warn_non_literal_null_pointer : Warning< + "expression which evaluates to zero treated as a null pointer constant of " + "type %0">, InGroup<NonLiteralNullConversion>; def warn_impcast_null_pointer_to_integer : Warning< "implicit conversion of NULL constant to %0">, InGroup<NullConversion>; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 9df850d6bd..d3aff2455c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2903,7 +2903,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx, llvm_unreachable("Unexpected value dependent expression!"); case NPC_ValueDependentIsNull: if (isTypeDependent() || getType()->isIntegralType(Ctx)) - return NPCK_ZeroInteger; + return NPCK_ZeroExpression; else return NPCK_NotNull; @@ -2977,7 +2977,12 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_NotNull; } - return (EvaluateKnownConstInt(Ctx) == 0) ? NPCK_ZeroInteger : NPCK_NotNull; + if (EvaluateKnownConstInt(Ctx) != 0) + return NPCK_NotNull; + + if (isa<IntegerLiteral>(this)) + return NPCK_ZeroLiteral; + return NPCK_ZeroExpression; } /// \brief If this expression is an l-value for an Objective C diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index bfe72423e1..6a503ee2d9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4632,7 +4632,10 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, if (NullKind == Expr::NPCK_NotNull) return false; - if (NullKind == Expr::NPCK_ZeroInteger) { + if (NullKind == Expr::NPCK_ZeroExpression) + return false; + + if (NullKind == Expr::NPCK_ZeroLiteral) { // In this case, check to make sure that we got here from a "NULL" // string in the source code. NullExpr = NullExpr->IgnoreParenImpCasts(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 7fac1c6ec4..a8744899d7 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2562,13 +2562,17 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, Kind = CK_BitCast; - if (!IsCStyleOrFunctionalCast && - Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy) && - From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(From->getExprLoc(), From, - PDiag(diag::warn_impcast_bool_to_null_pointer) - << ToType << From->getSourceRange()); - + if (!IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() && + From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) == + Expr::NPCK_ZeroExpression) { + if (Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy)) + DiagRuntimeBehavior(From->getExprLoc(), From, + PDiag(diag::warn_impcast_bool_to_null_pointer) + << ToType << From->getSourceRange()); + else if (!isUnevaluatedContext()) + Diag(From->getExprLoc(), diag::warn_non_literal_null_pointer) + << ToType << From->getSourceRange(); + } if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) { QualType FromPointeeType = FromPtrType->getPointeeType(), diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 0b7a6555e0..a3ead79a84 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -710,10 +710,16 @@ static_assert(&ok2 == pok2, ""); static_assert((Base2*)(Derived*)(Base*)pb1 == pok2, ""); static_assert((Derived*)(Base*)pb1 == (Derived*)pok2, ""); -constexpr Base *nullB = 42 - 6 * 7; +constexpr Base *nullB = 42 - 6 * 7; // expected-warning {{expression which evaluates to zero treated as a null pointer constant of type 'Class::Base *const'}} 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), ""); + namespace ConversionOperators { diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index 198f8cf1fe..0fd634502b 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -117,16 +117,16 @@ namespace NullPtr { const int m = 0; [=] { - int &k = f(m); // a null pointer constant + int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} } (); [=] () -> bool { - int &k = f(m); // a null pointer constant + int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} return &m == 0; } (); [m] { - int &k = f(m); // a null pointer constant + int &k = f(m); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} } (); } } diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp index 13d76befe2..e3e77d0828 100644 --- a/test/SemaTemplate/explicit-instantiation.cpp +++ b/test/SemaTemplate/explicit-instantiation.cpp @@ -14,7 +14,7 @@ struct X0 { T f0(T x) { return x + 1; // expected-error{{invalid operands}} } - T* f0(T*, T*) { return T(); } + T* f0(T*, T*) { return T(); } // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} template<typename U> T f0(T, U) { return T(); } @@ -32,7 +32,7 @@ struct NotDefaultConstructible { // expected-note{{candidate constructor (the im template NotDefaultConstructible X0<NotDefaultConstructible>::value; // expected-note{{instantiation}} template int X0<int>::f0(int); -template int* X0<int>::f0(int*, int*); +template int* X0<int>::f0(int*, int*); // expected-note{{in instantiation of member function 'X0<int>::f0' requested here}} template int X0<int>::f0(int, float); template int X0<int>::f0(int) const; // expected-error{{does not refer}} diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp index bb6427670c..7b42a27d6b 100644 --- a/test/SemaTemplate/instantiate-member-class.cpp +++ b/test/SemaTemplate/instantiate-member-class.cpp @@ -124,19 +124,20 @@ namespace rdar10397846 { { struct B { - struct C { C() { int *ptr = I; } }; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} + struct C { C() { int *ptr = I; } }; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \ + expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} }; }; template<int N> void foo() { - class A<N>::B::C X; // expected-note{{in instantiation of member function}} + class A<N>::B::C X; // expected-note 2 {{in instantiation of member function}} int A<N+1>::B::C::*member = 0; } void bar() { - foo<0>(); + foo<0>(); // expected-note{{in instantiation of function template}} foo<1>(); // expected-note{{in instantiation of function template}} } } |