Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2933,6 +2933,8 @@ def warn_attribute_nonnull_parm_no_args : Warning< "'nonnull' attribute when used on parameters takes no arguments">, InGroup; +def note_declared_nonnull : Note< + "declared %select{'returns_nonnull'|'nonnull'}0 here">; def warn_attribute_sentinel_named_arguments : Warning< "'sentinel' attribute requires named arguments">, InGroup; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -8460,7 +8460,8 @@ } } - auto ComplainAboutNonnullParamOrCall = [&](bool IsParam) { + auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) { + bool IsParam = isa(NonnullAttr); std::string Str; llvm::raw_string_ostream S(Str); E->printPretty(S, nullptr, getPrintingPolicy()); @@ -8468,13 +8469,14 @@ : diag::warn_cast_nonnull_to_bool; Diag(E->getExprLoc(), DiagID) << IsParam << S.str() << E->getSourceRange() << Range << IsEqual; + Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam; }; // If we have a CallExpr that is tagged with returns_nonnull, we can complain. if (auto *Call = dyn_cast(E->IgnoreParenImpCasts())) { if (auto *Callee = Call->getDirectCallee()) { - if (Callee->hasAttr()) { - ComplainAboutNonnullParamOrCall(false); + if (const Attr *A = Callee->getAttr()) { + ComplainAboutNonnullParamOrCall(A); return; } } @@ -8496,8 +8498,8 @@ if (const auto* PV = dyn_cast(D)) { if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV)) { - if (PV->hasAttr()) { - ComplainAboutNonnullParamOrCall(true); + if (const Attr *A = PV->getAttr()) { + ComplainAboutNonnullParamOrCall(A); return; } @@ -8508,13 +8510,13 @@ for (const auto *NonNull : FD->specific_attrs()) { if (!NonNull->args_size()) { - ComplainAboutNonnullParamOrCall(true); + ComplainAboutNonnullParamOrCall(NonNull); return; } for (unsigned ArgNo : NonNull->args()) { if (ArgNo == ParamNo) { - ComplainAboutNonnullParamOrCall(true); + ComplainAboutNonnullParamOrCall(NonNull); return; } } Index: test/Sema/nonnull.c =================================================================== --- test/Sema/nonnull.c +++ test/Sema/nonnull.c @@ -86,7 +86,7 @@ // rdar://18712242 #define NULL (void*)0 -__attribute__((__nonnull__)) +__attribute__((__nonnull__)) // expected-note 2{{declared 'nonnull' here}} int evil_nonnull_func(int* pointer, void * pv) { if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is 'false' on first encounter}} @@ -105,7 +105,7 @@ } void set_param_to_null(int**); -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) __attribute__((nonnull(1, 3))); // expected-note 2{{declared 'nonnull' here}} 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 'false' on first encounter}} return 0; @@ -127,7 +127,7 @@ extern void FEE(); extern void *pv; -__attribute__((__nonnull__)) +__attribute__((__nonnull__)) // expected-note {{declared 'nonnull' here}} void yet_another_evil_nonnull_func(int* pointer) { while (pv) { @@ -141,7 +141,7 @@ } } -void pr21668_1(__attribute__((nonnull)) const char *p, const char *s) { +void pr21668_1(__attribute__((nonnull)) const char *p, const char *s) { // expected-note {{declared 'nonnull' here}} if (p) // expected-warning {{nonnull parameter 'p' will evaluate to 'true' on first encounter}} ; if (s) // No warning @@ -154,7 +154,7 @@ ; } -__attribute__((returns_nonnull)) void *returns_nonnull_whee(); +__attribute__((returns_nonnull)) void *returns_nonnull_whee(); // expected-note 6{{declared 'returns_nonnull' here}} void returns_nonnull_warning_tests() { if (returns_nonnull_whee() == NULL) {} // expected-warning {{comparison of nonnull function call 'returns_nonnull_whee()' equal to a null pointer is 'false' on first encounter}}