The caret location C++ -Wnonnull warnings is in the wrong place:
either under the closing parenthesis of a call to a function
declared nonnull, or under the whole call (when issued from
the middle end). In addition, for member functions, the one-based
argument number mentioned in the warning starts with the implicit
this pointer, while in non-members it starts with the first argument.
That makes it difficult to tell which argument the warning is
complaining about (see the test + output below).
The attached patch improves things in a few minor ways:
1) by using the argument location when it has one to underline it
(the location isn't always available at this point but that
can be improved in a followup)
2) by using 1 for the first explicit argument, and by mentioning
'this' for the this pointer
3) by changing the message issued by the front-end (and the C++
member function handling) to match the corresponding message
(and handling) in the middle end.
Finally, the patch also arranges to treat the C++ this pointer
as implicitly nonnull, regardless of whether the member function
is declared with the attribute.
Tested on x86_64-linux.
Martin
PS For this test case:
__attribute__ ((nonnull)) void f (const char*);
struct S
{
__attribute__ ((nonnull)) void g (const char*) const;
};
void g (void)
{
{
const char* const null = 0;
f (null);
}
{
const S* const null = 0;
null->g ("");
}
}
GCC trunk outputs:
t.C: In function ‘void g()’:
t.C:12:12: warning: null argument where non-null required (argument 1)
[-Wnonnull]
12 | f (null);
| ^
t.C:17:16: warning: null argument where non-null required (argument 1)
[-Wnonnull]
17 | null->g ("");
| ^
With the patch the output is:
t.C: In function ‘void g()’:
t.C:12:8: warning: argument 1 null where non-null expected [-Wnonnull]
12 | f (null);
| ^~~~
t.C:1:32: note: in a call to function ‘void f(const char*)’ declared
‘nonnull’
1 | __attribute__ ((nonnull)) void f (const char*);
| ^
t.C:17:5: warning: ‘this’ pointer null [-Wnonnull]
17 | null->g ("");
| ^~~~
t.C:5:34: note: in a call to non-static member function ‘void S::g(const
char*) const’
5 | __attribute__ ((nonnull)) void g (const char*) const;
| ^
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.
* gcc/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.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index b1379faa412..8bedd9dc910 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,38 @@ 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;
+
+ location_t loc
+ = EXPR_HAS_LOCATION (param) ? EXPR_LOCATION (param) : pctx->loc;
+
+ if (TREE_CODE (pctx->fntype) == METHOD_TYPE)
+ --param_num;
+
+ bool warned;
+ if (param_num == 0)
{
- 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,
+ "%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
+ {
+ 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 +5755,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 d1c9c0b159a..3c6d32d5db9 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -2036,7 +2036,8 @@ 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);
+ location_t loc = (EXPR_HAS_LOCATION (ptr)
+ ? EXPR_LOCATION (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 903d7e51f1d..ed97f6c4cb3 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 d394c42b76d..fd67373042b 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 5fbd124b32c..0b326fbb715 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 5ef754ee377..c448bb07971 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*, float*);
void test_nonnull (void)
{
- f<void>(0, 0, 0); // { dg-warning "null argument where non-null required \\\(argument 1\\\)" }
+ f<void>(0, 0, 0); // { dg-warning "argument 1 null where non-null expected" }
- f<int>(0, 0, 0); // { dg-bogus "null argument" }
+ f<int>(0, 0, 0); // { dg-bogus "null" }
f<float>(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 99c6154f1a5..d0ba738494a 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 d8271b1d874..b0719b6a5a2 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 d1918ef8e90..cebf36d581d 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<S1>(0); // { dg-warning "null argument where non-null required" }
- f<S2>(0); // { dg-warning "null argument where non-null required" }
+ f<S1>(0); // { dg-warning "argument 1 null where non-null expected" }
+ f<S2>(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 d07a4452ddb..215781613b2 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/obj-c++.dg/attributes/method-nonnull-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm
index 917416d74a1..83f918c5a3f 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 e1974aa3cae..fe5f885b2d4 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 e9d2f4bc27a..fc259f4eb5e 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 7197b4720ce..1877e8f1fcd 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -14959,11 +14959,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 fc861a0d8ce..899a5c0290d 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<loc_exp_dep, va_heap, vl_embed> 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<loc_exp_dep, va_heap, vl_embed> 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<loc_exp_dep, va_heap, vl_embed>::embedded_size (count);
+ + deps_vec::embedded_size (count);
if (VAR_LOC_1PAUX (var))
{
--- /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" }
+}