From 75ff24e1920ea6b198350a2961e23175e6108e75 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sun, 28 Jun 2020 14:22:14 -0600 Subject: [PATCH] Underline argument in -Wnonnull and in C++ extend warning to the this pointer [PR c++/86568]. Resolves: PR c++/86568 - -Wnonnull warnings should highlight the relevant argument not the closing parenthesis gcc/c-family/ChangeLog: PR c++/86568 * c-common.c (struct nonnull_arg_ctx): Add members. (check_function_nonnull): Use nonnull_arg_ctx as argument. Handle C++ member functions specially. Consider the this pointer implicitly nonnull. (check_nonnull_arg): Use location of argument when available. (check_function_arguments): Use nonnull_arg_ctx as argument. gcc/ChangeLog: PR c++/86568 * calls.c (maybe_warn_rdwr_sizes): Use location of argument if available. * tree-ssa-ccp.c (pass_post_ipa_warn::execute): Same. Adjust indentation. * tree.c (get_nonnull_args): Consider the this pointer implicitly nonnull. * var-tracking.c (deps_vec): New type. (var_loc_dep_vec): New function. (VAR_LOC_DEP_VEC): Use it. gcc/testsuite/ChangeLog: PR c++/86568 * g++.dg/warn/Wnonnull5.C: New test. * c-c++-common/pr28656.c: Adjust text of expected warning. * c-c++-common/pr66208.c: Same. * g++.dg/cpp0x/nullptr22.C: Same. * g++.dg/ext/attr-nonnull.C: Same. * g++.dg/ext/attrib49.C: Same. * g++.dg/pr71973-2.C: Same. * g++.dg/warn/Wnonnull3.C: Same. * g++.dg/warn/Wnonnull4.C: Same. * obj-c++.dg/attributes/method-nonnull-1.mm: Same. * objc.dg/attributes/method-nonnull-1.m: Same. --- gcc/c-family/c-common.c | 83 ++++++++++---- gcc/calls.c | 4 +- gcc/testsuite/c-c++-common/pr28656.c | 12 +- gcc/testsuite/c-c++-common/pr66208.c | 2 +- gcc/testsuite/g++.dg/cpp0x/nullptr22.C | 4 +- gcc/testsuite/g++.dg/ext/attr-nonnull.C | 8 +- gcc/testsuite/g++.dg/ext/attrib49.C | 4 +- gcc/testsuite/g++.dg/pr71973-2.C | 2 +- gcc/testsuite/g++.dg/warn/Wnonnull3.C | 4 +- gcc/testsuite/g++.dg/warn/Wnonnull4.C | 4 +- gcc/testsuite/g++.dg/warn/Wnonnull5.C | 108 ++++++++++++++++++ .../obj-c++.dg/attributes/method-nonnull-1.mm | 8 +- .../objc.dg/attributes/method-nonnull-1.m | 8 +- gcc/tree-ssa-ccp.c | 81 +++++++------ gcc/tree.c | 13 ++- gcc/var-tracking.c | 19 ++- 16 files changed, 273 insertions(+), 91 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wnonnull5.C diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index a9fa0d123cfc..cfd12c0177ff 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5288,26 +5288,39 @@ c_determine_visibility (tree decl) struct nonnull_arg_ctx { + /* Location of the call. */ location_t loc; + /* The function whose arguments are being checked and its type (used + for calls through function pointers). */ + const_tree fndecl, fntype; + /* True if a warning has been issued. */ bool warned_p; }; -/* Check the argument list of a function call for null in argument slots - that are marked as requiring a non-null pointer argument. The NARGS - arguments are passed in the array ARGARRAY. Return true if we have - warned. */ +/* Check the argument list of a function call to CTX.FNDECL of CTX.FNTYPE + for null in argument slots that are marked as requiring a non-null + pointer argument. The NARGS arguments are passed in the array ARGARRAY. + Return true if we have warned. */ static bool -check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray) +check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray) { - tree a; - int i; + int firstarg = 0; + if (TREE_CODE (ctx.fntype) == METHOD_TYPE) + { + /* In calls to C++ non-static member functions check the this + pointer regardless of whether the function is declared with + attribute nonnull. */ + firstarg = 1; + check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[0], + firstarg); + } - attrs = lookup_attribute ("nonnull", attrs); + tree attrs = lookup_attribute ("nonnull", TYPE_ATTRIBUTES (ctx.fntype)); if (attrs == NULL_TREE) - return false; + return ctx.warned_p; - a = attrs; + tree a = attrs; /* See if any of the nonnull attributes has no arguments. If so, then every pointer argument is checked (in which case the check for pointer type is done in check_nonnull_arg). */ @@ -5316,16 +5329,15 @@ check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray) a = lookup_attribute ("nonnull", TREE_CHAIN (a)); while (a != NULL_TREE && TREE_VALUE (a) != NULL_TREE); - struct nonnull_arg_ctx ctx = { loc, false }; if (a != NULL_TREE) - for (i = 0; i < nargs; i++) + for (int i = firstarg; i < nargs; i++) check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[i], i + 1); else { /* Walk the argument list. If we encounter an argument number we should check for non-null, do it. */ - for (i = 0; i < nargs; i++) + for (int i = firstarg; i < nargs; i++) { for (a = attrs; ; a = TREE_CHAIN (a)) { @@ -5495,12 +5507,39 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num) return; /* Diagnose the simple cases of null arguments. */ - if (integer_zerop (fold_for_warn (param))) + if (!integer_zerop (fold_for_warn (param))) + return; + + auto_diagnostic_group adg; + + const location_t loc = EXPR_LOC_OR_LOC (param, pctx->loc); + + if (TREE_CODE (pctx->fntype) == METHOD_TYPE) + --param_num; + + bool warned; + if (param_num == 0) + { + warned = warning_at (loc, OPT_Wnonnull, + "%qs pointer null", "this"); + if (pctx->fndecl) + inform (DECL_SOURCE_LOCATION (pctx->fndecl), + "in a call to non-static member function %qD", + pctx->fndecl); + } + else { - warning_at (pctx->loc, OPT_Wnonnull, "null argument where non-null " - "required (argument %lu)", (unsigned long) param_num); - pctx->warned_p = true; + warned = warning_at (loc, OPT_Wnonnull, + "argument %u null where non-null expected", + (unsigned) param_num); + if (pctx->fndecl) + inform (DECL_SOURCE_LOCATION (pctx->fndecl), + "in a call to function %qD declared %qs", + pctx->fndecl, "nonnull"); } + + if (warned) + pctx->warned_p = true; } /* Helper for attribute handling; fetch the operand number from @@ -5717,11 +5756,13 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype, bool warned_p = false; /* Check for null being passed in a pointer argument that must be - non-null. We also need to do this if format checking is enabled. */ - + non-null. In C++, this includes the this pointer. We also need + to do this if format checking is enabled. */ if (warn_nonnull) - warned_p = check_function_nonnull (loc, TYPE_ATTRIBUTES (fntype), - nargs, argarray); + { + nonnull_arg_ctx ctx = { loc, fndecl, fntype, false }; + warned_p = check_function_nonnull (ctx, nargs, argarray); + } /* Check for errors in format strings. */ diff --git a/gcc/calls.c b/gcc/calls.c index d1c9c0b159a8..72f890115843 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1938,6 +1938,8 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp) if (!fntype) return; + auto_diagnostic_group adg; + /* A string describing the attributes that the warnings issued by this function apply to. Used to print one informational note per function call, rather than one per warning. That reduces clutter. */ @@ -2036,7 +2038,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp) attribute nonnull when the function accepts null pointers only when the corresponding size is zero. */ bool warned = false; - location_t loc = EXPR_LOCATION (exp); + const location_t loc = EXPR_LOC_OR_LOC (ptr, EXPR_LOCATION (exp)); if (tree_int_cst_equal (sizrng[0], sizrng[1])) warned = warning_at (loc, OPT_Wnonnull, "%Kargument %i is null but the corresponding " diff --git a/gcc/testsuite/c-c++-common/pr28656.c b/gcc/testsuite/c-c++-common/pr28656.c index 903d7e51f1dd..ed97f6c4cb3f 100644 --- a/gcc/testsuite/c-c++-common/pr28656.c +++ b/gcc/testsuite/c-c++-common/pr28656.c @@ -18,12 +18,12 @@ void foo (void) { memcpy (0, 0, 0); - /* { dg-warning "null argument where non-null required\[^\n\r\]*argument 1" "" { target *-*-* } .-1 } */ - /* { dg-warning "null argument where non-null required\[^\n\r\]*argument 2" "" { target *-*-* } .-2 } */ + /* { dg-warning "argument 1 null where non-null expected" "" { target *-*-* } .-1 } */ + /* { dg-warning "argument 2 null where non-null expected" "" { target *-*-* } .-2 } */ bar (0, 0, 0, 0, 0); - /* { dg-warning "null argument where non-null required\[^\n\r\]*argument 1" "" { target *-*-* } .-1 } */ - /* { dg-warning "null argument where non-null required\[^\n\r\]*argument 3" "" { target *-*-* } .-2 } */ - /* { dg-warning "null argument where non-null required\[^\n\r\]*argument 4" "" { target *-*-* } .-3 } */ - /* { dg-warning "null argument where non-null required\[^\n\r\]*argument 5" "" { target *-*-* } .-4 } */ + /* { dg-warning "argument 1 null where non-null expected" "" { target *-*-* } .-1 } */ + /* { dg-warning "argument 3 null where non-null expected" "" { target *-*-* } .-2 } */ + /* { dg-warning "argument 4 null where non-null expected" "" { target *-*-* } .-3 } */ + /* { dg-warning "argument 5 null where non-null expected" "" { target *-*-* } .-4 } */ } diff --git a/gcc/testsuite/c-c++-common/pr66208.c b/gcc/testsuite/c-c++-common/pr66208.c index d394c42b76db..fd67373042ba 100644 --- a/gcc/testsuite/c-c++-common/pr66208.c +++ b/gcc/testsuite/c-c++-common/pr66208.c @@ -2,7 +2,7 @@ /* { dg-options "-Wnonnull" } */ void foox (char*, ...) __attribute__ ((nonnull (1))); -#define foo(p) foox (p, "p is null") /* { dg-warning "null argument" } */ +#define foo(p) foox (p, "p is null") /* { dg-warning "argument 1 null" } */ void baz (void) { diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr22.C b/gcc/testsuite/g++.dg/cpp0x/nullptr22.C index 5fbd124b32c4..0b326fbb7154 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nullptr22.C +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr22.C @@ -10,11 +10,11 @@ void f3(const char*, ...) __attribute__((sentinel)); void f() { f1("%p", nullptr); - f2(nullptr); // { dg-warning "null argument where non-null required " } + f2(nullptr); // { dg-warning "argument 1 null where non-null expected " } f3("x", "y", __null); // { dg-warning "missing sentinel in function call" } f3("x", "y", nullptr); decltype(nullptr) mynull = 0; f1("%p", mynull); - f2(mynull); // { dg-warning "null argument where non-null required " } + f2(mynull); // { dg-warning "argument 1 null where non-null expected " } f3("x", "y", mynull); } diff --git a/gcc/testsuite/g++.dg/ext/attr-nonnull.C b/gcc/testsuite/g++.dg/ext/attr-nonnull.C index 5ef754ee3773..c448bb07971f 100644 --- a/gcc/testsuite/g++.dg/ext/attr-nonnull.C +++ b/gcc/testsuite/g++.dg/ext/attr-nonnull.C @@ -21,11 +21,11 @@ f(float*, float*, float*); void test_nonnull (void) { - f(0, 0, 0); // { dg-warning "null argument where non-null required \\\(argument 1\\\)" } + f(0, 0, 0); // { dg-warning "argument 1 null where non-null expected" } - f(0, 0, 0); // { dg-bogus "null argument" } + f(0, 0, 0); // { dg-bogus "null" } f(0, 0, 0); - // { dg-bogus "null argument where non-null required \\\(argument 1\\\)" "" { target *-*-* } .-1 } - // { dg-warning "null argument where non-null required \\\(argument 3\\\)" "" { target *-*-* } .-2 } + // { dg-bogus "argument 1 null where non-null expected" "" { target *-*-* } .-1 } + // { dg-warning "argument 3 null where non-null expected" "" { target *-*-* } .-2 } } diff --git a/gcc/testsuite/g++.dg/ext/attrib49.C b/gcc/testsuite/g++.dg/ext/attrib49.C index 99c6154f1a55..d0ba738494a4 100644 --- a/gcc/testsuite/g++.dg/ext/attrib49.C +++ b/gcc/testsuite/g++.dg/ext/attrib49.C @@ -10,11 +10,11 @@ void (foo::*g) (int *) __attribute__ ((nonnull (2))); void fun1 (void (foo::*f) (int *) __attribute__ ((nonnull (2)))) { - (x.*f) ((int *) 0); // { dg-warning "null argument" } + (x.*f) ((int *) 0); // { dg-warning "argument 1 null" } } void fun2 (void (foo::*f) () __attribute__ ((nonnull, unused))) // { dg-bogus "unused" } { - (x.*g) ((int *) 0); // { dg-warning "null argument" } + (x.*g) ((int *) 0); // { dg-warning "argument 1 null" } } diff --git a/gcc/testsuite/g++.dg/pr71973-2.C b/gcc/testsuite/g++.dg/pr71973-2.C index d8271b1d8741..b0719b6a5a28 100644 --- a/gcc/testsuite/g++.dg/pr71973-2.C +++ b/gcc/testsuite/g++.dg/pr71973-2.C @@ -10,7 +10,7 @@ __attribute__ ((__nothrow__)); void foo () throw () { - strftime (0,0,0,0); // { dg-warning "null argument where non-null required" } + strftime (0,0,0,0); // { dg-warning "argument \(1|3|4\) null where non-null expected" } // { dg-warning "too many arguments for format" "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull3.C b/gcc/testsuite/g++.dg/warn/Wnonnull3.C index d1918ef8e900..cebf36d581d5 100644 --- a/gcc/testsuite/g++.dg/warn/Wnonnull3.C +++ b/gcc/testsuite/g++.dg/warn/Wnonnull3.C @@ -10,6 +10,6 @@ struct S2 { static const int i = 1; typedef void* U; }; void g () { - f(0); // { dg-warning "null argument where non-null required" } - f(0); // { dg-warning "null argument where non-null required" } + f(0); // { dg-warning "argument 1 null where non-null expected" } + f(0); // { dg-warning "argument 1 null where non-null expected" } } diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull4.C b/gcc/testsuite/g++.dg/warn/Wnonnull4.C index d07a4452ddb5..215781613b25 100644 --- a/gcc/testsuite/g++.dg/warn/Wnonnull4.C +++ b/gcc/testsuite/g++.dg/warn/Wnonnull4.C @@ -10,8 +10,8 @@ int main () { int *const p = 0; - declared_not_defined (p); // { dg-warning "null argument where non-null required" } - declared_and_defined (p); // { dg-warning "null argument where non-null required" } + declared_not_defined (p); // { dg-warning "argument 1 null where non-null expected" } + declared_and_defined (p); // { dg-warning "argument 1 null where non-null expected" } } void * diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull5.C b/gcc/testsuite/g++.dg/warn/Wnonnull5.C new file mode 100644 index 000000000000..8b25d2d9f86a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnonnull5.C @@ -0,0 +1,108 @@ +/* PR c++/86568 - -Wnonnull warnings should highlight the relevant argument + not the closing parenthesis. + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +#define NONNULL __attribute__ ((nonnull)) + +#if __cplusplus < 201103L +# define nullptr __null +#endif + +struct S +{ + void + f0 (const void*) const; // { dg-message "in a call to non-static member function 'void S::f0\\(const void\\*\\) const'" } + + void + f1 (const void*) const; // { dg-message "in a call to non-static member function 'void S::f1\\(const void\\*\\) const'" } + + void + f2 (const void*) const; // { dg-message "in a call to non-static member function 'void S::f2\\(const void\\*\\) const'" } + + NONNULL void + f3 (const void*, const void*); // { dg-message "in a call to function 'void S::f3\\(const void\\*, const void\\*\\)' declared 'nonnull'" } + + NONNULL void + f4 (const void*, const void*); // { dg-message "in a call to function 'void S::f4\\(const void\\*, const void\\*\\)' declared 'nonnull'" } + + NONNULL void + f5 (const void*, const void*); // { dg-message "in a call to function 'void S::f5\\\(const void\\*, const void\\*\\)' declared 'nonnull'" } + + NONNULL void + f6 (const void*, const void*); // { dg-message "in a call to function 'void S::f6\\\(const void\\*, const void\\*\\)' declared 'nonnull'" } +}; + +void warn_nullptr_this () +{ + ((S*)nullptr)->f0 (""); // { dg-warning "3:'this' pointer null" "pr86568" { xfail *-*-* } } + // { dg-warning "this' pointer null" "pr86568" { target *-*-* } .-1 } +} + +void warn_null_this_cst () +{ + S* const null = 0; + null->f1 (""); // { dg-warning "3:'this' pointer null" } +} + +void warn_null_this_var () +{ + S* null = 0; + null->f2 (&null); // { dg-warning "3:'this' pointer null" "pr86568" { xfail *-*-* } } + // { dg-warning "'this' pointer null" "pr86568" { target *-*-* } .-1 } +} + +void warn_nullptr (S s) +{ + s.f3 (nullptr, &s); // { dg-warning "9:argument 1 null where non-null expected" "pr86568" { xfail *-*-* } } + // { dg-warning "argument 1 null where non-null expected" "pr86568" { target *-*-* } .-1 } + s.f3 (&s, nullptr); // { dg-warning "13:argument 2 null where non-null expected" "pr86568" { xfail *-*-* } } + // { dg-warning "argument 2 null where non-null expected" "pr86568" { target *-*-* } .-1 } +} + + +void warn_null_cst (S s) +{ + void* const null = 0; + s.f4 (null, &s); // { dg-warning "9:argument 1 null where non-null expected" } + s.f4 (&s, null); // { dg-warning "13:argument 2 null where non-null expected" } +} + +void warn_null_var (S s) +{ + void* null = 0; + s.f5 (null, &s); // { dg-warning "9:argument 1 null where non-null expected" "pr86568" { xfail *-*-* } } + // { dg-warning "argument 1 null where non-null expected" "pr86568" { target *-*-* } .-1 } + s.f5 (&s, null); // { dg-warning "16:argument 2 null where non-null expected" "pr86568" { xfail *-*-* } } + // { dg-warning "argument 2 null where non-null expected" "pr86568" { target *-*-* } .-1 } +} + +void warn_null_cond (S s, void *null) +{ + if (null) + return; + + s.f6 (null, &s); // { dg-warning "9:argument 1 null where non-null expected" "pr86568" { xfail *-*-* } } + // { dg-warning "argument 1 null where non-null expected" "pr86568" { target *-*-* } .-1 } + s.f6 (&s, null); // { dg-warning "13:argument 2 null where non-null expected" "pr86568" { xfail *-*-* } } + // { dg-warning "argument 2 null where non-null expected" "pr86568" { target *-*-* } .-1 } +} + + +typedef NONNULL void Fvp (const void*, const void*); + +void warn_fptr_null_cst (Fvp *p) +{ + void* const null = 0; + p (null, ""); // { dg-warning "6:argument 1 null where non-null expected" } + p ("", null); // { dg-warning "10:argument 2 null where non-null expected" } +} + +typedef NONNULL void (S::*SMemFvp) (const void*, const void*); + +void warn_memfptr_null_cst (S *p, SMemFvp pmf) +{ + void* const null = 0; + (p->*pmf) (null, ""); // { dg-warning "14:argument 1 null where non-null expected" } + (p->*pmf) ("", null); // { dg-warning "18:argument 2 null where non-null expected" } +} diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm index 917416d74a1a..83f918c5a3fb 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm @@ -39,12 +39,12 @@ typedef __SIZE_TYPE__ my_size_t; void test (MyArray *object) { [object addObject: object]; - [object addObject: nil]; /* { dg-warning "null argument where non-null required" } */ + [object addObject: nil]; /* { dg-warning "\\\[-Wnonnull" } */ [object insertObject: object atIndex: 4]; - [object insertObject: nil atIndex: 4]; /* { dg-warning "null argument where non-null required" } */ + [object insertObject: nil atIndex: 4]; /* { dg-warning "\\\[-Wnonnull" } */ [object insertObject: object atIndex: 2 andObject: object atIndex: 3]; - [object insertObject: nil atIndex: 2 andObject: object atIndex: 3]; /* { dg-warning "null argument where non-null required" } */ - [object insertObject: object atIndex: 2 andObject: nil atIndex: 3]; /* { dg-warning "null argument where non-null required" } */ + [object insertObject: nil atIndex: 2 andObject: object atIndex: 3]; /* { dg-warning "\\\[-Wnonnull" } */ + [object insertObject: object atIndex: 2 andObject: nil atIndex: 3]; /* { dg-warning "\\\[-Wnonnull" } */ } diff --git a/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m b/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m index e1974aa3caeb..fe5f885b2d46 100644 --- a/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m +++ b/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m @@ -35,12 +35,12 @@ void test (MyArray *object) { [object addObject: object]; - [object addObject: nil]; /* { dg-warning "null argument where non-null required" } */ + [object addObject: nil]; /* { dg-warning "\\\[-Wnonnull" } */ [object insertObject: object atIndex: 4]; - [object insertObject: nil atIndex: 4]; /* { dg-warning "null argument where non-null required" } */ + [object insertObject: nil atIndex: 4]; /* { dg-warning "\\\[-Wnonnull" } */ [object insertObject: object atIndex: 2 andObject: object atIndex: 3]; - [object insertObject: nil atIndex: 2 andObject: object atIndex: 3]; /* { dg-warning "null argument where non-null required" } */ - [object insertObject: object atIndex: 2 andObject: nil atIndex: 3]; /* { dg-warning "null argument where non-null required" } */ + [object insertObject: nil atIndex: 2 andObject: object atIndex: 3]; /* { dg-warning "\\\[-Wnonnull" } */ + [object insertObject: object atIndex: 2 andObject: nil atIndex: 3]; /* { dg-warning "\\\[-Wnonnull" } */ } diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index f7a27952ce4f..e8333ac27d9e 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -3540,43 +3540,58 @@ pass_post_ipa_warn::execute (function *fun) if (!is_gimple_call (stmt) || gimple_no_warning_p (stmt)) continue; - if (warn_nonnull) + tree fntype = gimple_call_fntype (stmt); + bitmap nonnullargs = get_nonnull_args (fntype); + if (!nonnullargs) + continue; + + tree fndecl = gimple_call_fndecl (stmt); + + for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) { - bitmap nonnullargs - = get_nonnull_args (gimple_call_fntype (stmt)); - if (nonnullargs) + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) + continue; + if (!integer_zerop (arg)) + continue; + if (!bitmap_empty_p (nonnullargs) + && !bitmap_bit_p (nonnullargs, i)) + continue; + + /* In C++ non-static member functions argument 0 refers + to the implicit this pointer. Use the same one-based + numbering for ordinary arguments. */ + unsigned argno = TREE_CODE (fntype) == METHOD_TYPE ? i : i + 1; + location_t loc = (EXPR_HAS_LOCATION (arg) + ? EXPR_LOCATION (arg) + : gimple_location (stmt)); + auto_diagnostic_group d; + if (argno == 0) { - for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) - { - tree arg = gimple_call_arg (stmt, i); - if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) - continue; - if (!integer_zerop (arg)) - continue; - if (!bitmap_empty_p (nonnullargs) - && !bitmap_bit_p (nonnullargs, i)) - continue; - - location_t loc = gimple_location (stmt); - auto_diagnostic_group d; - if (warning_at (loc, OPT_Wnonnull, - "%Gargument %u null where non-null " - "expected", stmt, i + 1)) - { - tree fndecl = gimple_call_fndecl (stmt); - if (fndecl && DECL_IS_BUILTIN (fndecl)) - inform (loc, "in a call to built-in function %qD", - fndecl); - else if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD declared here", - fndecl); - - } - } - BITMAP_FREE (nonnullargs); + if (warning_at (loc, OPT_Wnonnull, + "%G%qs pointer null", stmt, "this") + && fndecl) + inform (DECL_SOURCE_LOCATION (fndecl), + "in a call to non-static member function %qD", + fndecl); + continue; } + + if (!warning_at (loc, OPT_Wnonnull, + "%Gargument %u null where non-null " + "expected", stmt, argno)) + continue; + + tree fndecl = gimple_call_fndecl (stmt); + if (fndecl && DECL_IS_BUILTIN (fndecl)) + inform (loc, "in a call to built-in function %qD", + fndecl); + else if (fndecl) + inform (DECL_SOURCE_LOCATION (fndecl), + "in a call to function %qD declared %qs", + fndecl, "nonnull"); } + BITMAP_FREE (nonnullargs); } } return 0; diff --git a/gcc/tree.c b/gcc/tree.c index 805f669a9457..342da55bba7e 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -14965,11 +14965,18 @@ get_nonnull_args (const_tree fntype) if (fntype == NULL_TREE) return NULL; + bitmap argmap = NULL; + if (TREE_CODE (fntype) == METHOD_TYPE) + { + /* The this pointer in C++ non-static member functions is + implicitly nonnull whether or not it's declared as such. */ + argmap = BITMAP_ALLOC (NULL); + bitmap_set_bit (argmap, 0); + } + tree attrs = TYPE_ATTRIBUTES (fntype); if (!attrs) - return NULL; - - bitmap argmap = NULL; + return argmap; /* A function declaration can specify multiple attribute nonnull, each with zero or more arguments. The loop below creates a bitmap diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index fc861a0d8ce0..899a5c0290dd 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -305,6 +305,9 @@ struct expand_depth int entryvals; }; +/* Type for dependencies actively used when expand FROM into cur_loc. */ +typedef vec deps_vec; + /* This data structure is allocated for one-part variables at the time of emitting notes. */ struct onepart_aux @@ -325,7 +328,7 @@ struct onepart_aux /* The depth of the cur_loc expression. */ expand_depth depth; /* Dependencies actively used when expand FROM into cur_loc. */ - vec deps; + deps_vec deps; }; /* Structure describing one part of variable. */ @@ -434,10 +437,16 @@ int_mem_offset (const_rtx mem) : NULL) #define VAR_LOC_FROM(var) (VAR_LOC_1PAUX (var)->from) #define VAR_LOC_DEPTH(var) (VAR_LOC_1PAUX (var)->depth) -#define VAR_LOC_DEP_VEC(var) (VAR_LOC_1PAUX (var) \ - ? &VAR_LOC_1PAUX (var)->deps \ - : NULL) +#define VAR_LOC_DEP_VEC(var) var_loc_dep_vec (var) + +/* Implements the VAR_LOC_DEP_VEC above as a function to work around + a bogus -Wnonnull (PR c/95554). */ +static inline deps_vec* +var_loc_dep_vec (variable *var) +{ + return VAR_LOC_1PAUX (var) ? &VAR_LOC_1PAUX (var)->deps : NULL; +} typedef unsigned int dvuid; @@ -8112,7 +8121,7 @@ loc_exp_dep_alloc (variable *var, int count) return; allocsize = offsetof (struct onepart_aux, deps) - + vec::embedded_size (count); + + deps_vec::embedded_size (count); if (VAR_LOC_1PAUX (var)) { -- 2.39.2