diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 32 | ||||
-rw-r--r-- | clang/test/Sema/nonnull.c | 25 |
3 files changed, 64 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e6ad4b54bd1..8197f7d69e0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2500,6 +2500,10 @@ def warn_impcast_pointer_to_bool : Warning< "address of%select{| function| array}0 '%1' will always evaluate to " "'true'">, InGroup<PointerBoolConversion>; +def warn_cast_nonnull_to_bool : Warning< + "nonnull parameter '%0' will always evaluate to " + "'true'">, + InGroup<PointerBoolConversion>; def warn_this_bool_conversion : Warning< "'this' pointer cannot be null in well-defined C++ code; pointer may be " "assumed to always convert to true">, InGroup<UndefinedBoolConversion>; @@ -2512,6 +2516,10 @@ def warn_null_pointer_compare : Warning< "comparison of %select{address of|function|array}0 '%1' %select{not |}2" "equal to a null pointer is always %select{true|false}2">, InGroup<TautologicalPointerCompare>; +def warn_nonnull_parameter_compare : Warning< + "comparison of nonnull parameter '%0' %select{not |}1" + "equal to a null pointer is always %select{true|false}1">, + InGroup<TautologicalPointerCompare>; def warn_this_null_compare : Warning< "'this' pointer cannot be null in well-defined C++ code; comparison may be " "assumed to always evaluate to %select{true|false}0">, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index fd2fa0c3f36..495fa3253e6 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6678,7 +6678,37 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, // Weak Decls can be null. if (!D || D->isWeak()) return; - + // Check for parameter decl with nonnull attribute + if (ParmVarDecl* PV = dyn_cast<ParmVarDecl>(D)) { + if (FunctionDecl* FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { + unsigned NumArgs = FD->getNumParams(); + llvm::SmallBitVector AttrNonNull(NumArgs); + for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) { + if (!NonNull->args_size()) { + AttrNonNull.set(0, NumArgs); + break; + } + for (unsigned Val : NonNull->args()) { + if (Val >= NumArgs) + continue; + AttrNonNull.set(Val); + } + } + if (!AttrNonNull.empty()) + for (unsigned i = 0; i < NumArgs; ++i) + if (FD->getParamDecl(i) == PV && AttrNonNull[i]) { + std::string Str; + llvm::raw_string_ostream S(Str); + E->printPretty(S, nullptr, getPrintingPolicy()); + unsigned DiagID = IsCompare ? diag::warn_nonnull_parameter_compare + : diag::warn_cast_nonnull_to_bool; + Diag(E->getExprLoc(), DiagID) << S.str() << E->getSourceRange() + << Range << IsEqual; + return; + } + } + } + QualType T = D->getType(); const bool IsArray = T->isArrayType(); const bool IsFunction = T->isFunctionType(); diff --git a/clang/test/Sema/nonnull.c b/clang/test/Sema/nonnull.c index 3b654a88907..53f94dd3a45 100644 --- a/clang/test/Sema/nonnull.c +++ b/clang/test/Sema/nonnull.c @@ -83,3 +83,28 @@ void redecl_test(void *p) { redecl(p, 0); // expected-warning{{null passed}} redecl(0, p); // expected-warning{{null passed}} } + +// rdar://18712242 +#define NULL (void*)0 +__attribute__((__nonnull__)) +int evil_nonnull_func(int* pointer, void * pv) +{ + if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is always false}} + return 0; + } else { + return *pointer; + } + + if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is always false}} +} + +int another_evil_nonnull_func(int* pointer, char ch, void * pv) __attribute__((nonnull(1, 3))); +int another_evil_nonnull_func(int* pointer, char ch, void * pv) { + if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is always false}} + return 0; + } else { + return *pointer; + } + + if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is always false}} +} |