]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Underline argument in -Wnonnull and in C++ extend warning to the this pointer [PR...
authorMartin Sebor <msebor@redhat.com>
Sun, 28 Jun 2020 20:22:14 +0000 (14:22 -0600)
committerMartin Sebor <msebor@redhat.com>
Sun, 28 Jun 2020 20:24:52 +0000 (14:24 -0600)
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.

16 files changed:
gcc/c-family/c-common.c
gcc/calls.c
gcc/testsuite/c-c++-common/pr28656.c
gcc/testsuite/c-c++-common/pr66208.c
gcc/testsuite/g++.dg/cpp0x/nullptr22.C
gcc/testsuite/g++.dg/ext/attr-nonnull.C
gcc/testsuite/g++.dg/ext/attrib49.C
gcc/testsuite/g++.dg/pr71973-2.C
gcc/testsuite/g++.dg/warn/Wnonnull3.C
gcc/testsuite/g++.dg/warn/Wnonnull4.C
gcc/testsuite/g++.dg/warn/Wnonnull5.C [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm
gcc/testsuite/objc.dg/attributes/method-nonnull-1.m
gcc/tree-ssa-ccp.c
gcc/tree.c
gcc/var-tracking.c

index a9fa0d123cfcd396359013e38aeb9eda5a5e52ba..cfd12c0177ffc4699a320418785cd8776b001c64 100644 (file)
@@ -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.  */
 
index d1c9c0b159a89d06d59dd63581d479ead7421283..72f8901158436af5a995cd7916ce851df2f3b2e6 100644 (file)
@@ -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 "
index 903d7e51f1dd966342700385e9253227dac58f62..ed97f6c4cb3f3a9196cde268714511a2fcbe9ffc 100644 (file)
@@ -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 } */
 }
index d394c42b76db549583f2db22ef7ffd725529a721..fd67373042baca4991494090ee099da74b67d624 100644 (file)
@@ -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)
 {
index 5fbd124b32c4abb9490e48b3cd230ec5644c1695..0b326fbb71542d43308299aed37b1904a28bbdc5 100644 (file)
@@ -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);
 }
index 5ef754ee37737538a83c8afafc121c6b5477ef4c..c448bb07971f57b669a4470d243f45992dcbf85c 100644 (file)
@@ -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 }
 }
index 99c6154f1a55b785fb74164d1455ff562786b314..d0ba738494a4e8cbf89937c2e266042b737f1557 100644 (file)
@@ -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" }
 }
index d8271b1d87416680cb139e1e44fa1e469e32ec8f..b0719b6a5a2823df184b336bed79da4419cff532 100644 (file)
@@ -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 }
 }
 
index d1918ef8e90014a08e92cc10a2f4997e68ff7fcf..cebf36d581d565e730669f0b8708fb355d520146 100644 (file)
@@ -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" }
 }
index d07a4452ddb595537be42d2dd2f8a7c8d9be659e..215781613b25ddb20e215149b9d530cf8c65f9bf 100644 (file)
@@ -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 (file)
index 0000000..8b25d2d
--- /dev/null
@@ -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" }
+}
index 917416d74a1aba112186a791489432997d11f118..83f918c5a3fb8938e2801ed380c9aebae3058b95 100644 (file)
@@ -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" } */
 }
index e1974aa3caeba84cab23edcbcd6089a34dc2ab02..fe5f885b2d4617b1a05947714c6bbda39097efa6 100644 (file)
 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" } */
 }
index f7a27952ce4feeabcfe2cce3cc92ac280ed4ae79..e8333ac27d9e6657d66f110d2a9f5a201b589f00 100644 (file)
@@ -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;
index 805f669a94575eb2833bd30982cfe57c26592e00..342da55bba7efd2bbf0c129ff224062a7a780bb3 100644 (file)
@@ -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
index fc861a0d8ce0e389e8680f83f12acdfb4ab80de6..899a5c0290dd200a0b2ee4e9402fe0c1280f36fc 100644 (file)
@@ -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))
     {