re PR bootstrap/78817 (stage2 bootstrap failure in vec.h:1613:5: error: argument...
authorJakub Jelinek <jakub@redhat.com>
Wed, 21 Dec 2016 22:15:59 +0000 (23:15 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 21 Dec 2016 22:15:59 +0000 (23:15 +0100)
PR bootstrap/78817
* tree-pass.h (make_pass_post_ipa_warn): Declare.
* builtins.c (validate_arglist): Adjust get_nonnull_args call.
Check for NULL pointer argument to nonnull arg here.
(validate_arg): Revert 2016-12-14 changes.
* calls.h (get_nonnull_args): Remove declaration.
* tree-ssa-ccp.c: Include diagnostic-core.h.
(pass_data_post_ipa_warn): New variable.
(pass_post_ipa_warn): New class.
(pass_post_ipa_warn::execute): New method.
(make_pass_post_ipa_warn): New function.
* tree.h (get_nonnull_args): Declare.
* tree.c (get_nonnull_args): New function.
* calls.c (maybe_warn_null_arg): Removed.
(maybe_warn_null_arg): Removed.
(initialize_argument_information): Revert 2016-12-14 changes.
* passes.def: Add pass_post_ipa_warn after first ccp after IPA.
c-family/
* c-common.c (struct nonnull_arg_ctx): New type.
(check_function_nonnull): Return bool instead of void.  Use
nonnull_arg_ctx as context rather than just location_t.
(check_nonnull_arg): Adjust for the new context type, set
warned_p to true if a warning has been diagnosed.
(check_function_arguments): Return bool instead of void.
* c-common.h (check_function_arguments): Adjust prototype.
c/
* c-typeck.c (build_function_call_vec): If check_function_arguments
returns true, set TREE_NO_WARNING on CALL_EXPR.
cp/
* typeck.c (cp_build_function_call_vec): If check_function_arguments
returns true, set TREE_NO_WARNING on CALL_EXPR.
* call.c (build_over_call): Likewise.

From-SVN: r243874

17 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/calls.c
gcc/calls.h
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/typeck.c
gcc/passes.def
gcc/tree-pass.h
gcc/tree-ssa-ccp.c
gcc/tree.c
gcc/tree.h

index 1454cce9c5d3b42ad66b0cd973b0657f5a5d2cb7..e9ce90d530cce97d2e5235d1bf88f0fe0fe66461 100644 (file)
@@ -1,3 +1,23 @@
+2016-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR bootstrap/78817
+       * tree-pass.h (make_pass_post_ipa_warn): Declare.
+       * builtins.c (validate_arglist): Adjust get_nonnull_args call.
+       Check for NULL pointer argument to nonnull arg here.
+       (validate_arg): Revert 2016-12-14 changes.
+       * calls.h (get_nonnull_args): Remove declaration.
+       * tree-ssa-ccp.c: Include diagnostic-core.h.
+       (pass_data_post_ipa_warn): New variable.
+       (pass_post_ipa_warn): New class.
+       (pass_post_ipa_warn::execute): New method.
+       (make_pass_post_ipa_warn): New function.
+       * tree.h (get_nonnull_args): Declare.
+       * tree.c (get_nonnull_args): New function.
+       * calls.c (maybe_warn_null_arg): Removed.
+       (maybe_warn_null_arg): Removed.
+       (initialize_argument_information): Revert 2016-12-14 changes.
+       * passes.def: Add pass_post_ipa_warn after first ccp after IPA.
+
 2016-12-21  Pat Haugen  <pthaugen@us.ibm.com>
 
        PR rtl-optimization/11488
index ca038cdcc7cc44d8aa30e3ec67114f45b9ed5b22..216d9261b237337867ccb06cdb0723e0b4469d83 100644 (file)
@@ -147,7 +147,7 @@ static tree fold_builtin_classify_type (tree);
 static tree fold_builtin_strlen (location_t, tree, tree);
 static tree fold_builtin_inf (location_t, tree, int);
 static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
-static bool validate_arg (const_tree, enum tree_code code, bool = false);
+static bool validate_arg (const_tree, enum tree_code code);
 static rtx expand_builtin_fabs (tree, rtx, rtx);
 static rtx expand_builtin_signbit (tree, rtx);
 static tree fold_builtin_memcmp (location_t, tree, tree, tree);
@@ -1050,12 +1050,12 @@ validate_arglist (const_tree callexpr, ...)
   init_const_call_expr_arg_iterator (callexpr, &iter);
 
   /* Get a bitmap of pointer argument numbers declared attribute nonnull.  */
-  bitmap argmap = get_nonnull_args (callexpr);
+  tree fn = CALL_EXPR_FN (callexpr);
+  bitmap argmap = get_nonnull_args (TREE_TYPE (TREE_TYPE (fn)));
 
   for (unsigned argno = 1; ; ++argno)
     {
       code = (enum tree_code) va_arg (ap, int);
-      bool nonnull = false;
 
       switch (code)
        {
@@ -1072,15 +1072,21 @@ validate_arglist (const_tree callexpr, ...)
          /* The actual argument must be nonnull when either the whole
             called function has been declared nonnull, or when the formal
             argument corresponding to the actual argument has been.  */
-         if (argmap)
-           nonnull = bitmap_empty_p (argmap) || bitmap_bit_p (argmap, argno);
+         if (argmap
+             && (bitmap_empty_p (argmap) || bitmap_bit_p (argmap, argno)))
+           {
+             arg = next_const_call_expr_arg (&iter);
+             if (!validate_arg (arg, code) || integer_zerop (arg))
+               goto end;
+             break;
+           }
          /* FALLTHRU */
        default:
          /* If no parameters remain or the parameter's code does not
             match the specified code, return false.  Otherwise continue
             checking any remaining arguments.  */
          arg = next_const_call_expr_arg (&iter);
-         if (!validate_arg (arg, code, nonnull))
+         if (!validate_arg (arg, code))
            goto end;
          break;
        }
@@ -9134,17 +9140,15 @@ rewrite_call_expr (location_t loc, tree exp, int skip, tree fndecl, int n, ...)
 }
 
 /* Validate a single argument ARG against a tree code CODE representing
-   a type.  When NONNULL is true consider a pointer argument valid only
-   if it's non-null.  Return true when argument is valid.  */
+   a type.  Return true when argument is valid.  */
 
 static bool
-validate_arg (const_tree arg, enum tree_code code, bool nonnull /*= false*/)
+validate_arg (const_tree arg, enum tree_code code)
 {
   if (!arg)
     return false;
   else if (code == POINTER_TYPE)
-    return POINTER_TYPE_P (TREE_TYPE (arg))
-      && (!nonnull || !integer_zerop (arg));
+    return POINTER_TYPE_P (TREE_TYPE (arg));
   else if (code == INTEGER_TYPE)
     return INTEGRAL_TYPE_P (TREE_TYPE (arg));
   return code == TREE_CODE (TREE_TYPE (arg));
index 13ba2f314a94aea915212edc1e67500e48ff3474..acdedc8e024bb608ac61ecbbdf9385898cfdcb13 100644 (file)
@@ -1,3 +1,14 @@
+2016-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR bootstrap/78817
+       * c-common.c (struct nonnull_arg_ctx): New type.
+       (check_function_nonnull): Return bool instead of void.  Use
+       nonnull_arg_ctx as context rather than just location_t.
+       (check_nonnull_arg): Adjust for the new context type, set
+       warned_p to true if a warning has been diagnosed.
+       (check_function_arguments): Return bool instead of void.
+       * c-common.h (check_function_arguments): Adjust prototype.
+
 2016-12-21  Jason Merrill  <jason@redhat.com>
 
        * c.opt (-fnew-ttp-matching): New flag.
index b690afb5e04eaaf576e582d522c17fb3c1a9b67b..81dc888e9b327b58c6d460bec944b70aab4a4e34 100644 (file)
@@ -5250,11 +5250,21 @@ c_determine_visibility (tree decl)
   return false;
 }
 
+/* Data to communicate through check_function_arguments_recurse between
+   check_function_nonnull and check_nonnull_arg.  */
+
+struct nonnull_arg_ctx
+{
+  location_t loc;
+  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.  */
+   arguments are passed in the array ARGARRAY.  Return true if we have
+   warned.  */
 
-static void
+static bool
 check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
 {
   tree a;
@@ -5262,7 +5272,7 @@ check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
 
   attrs = lookup_attribute ("nonnull", attrs);
   if (attrs == NULL_TREE)
-    return;
+    return false;
 
   a = attrs;
   /* See if any of the nonnull attributes has no arguments.  If so,
@@ -5273,9 +5283,10 @@ 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++)
-      check_function_arguments_recurse (check_nonnull_arg, &loc, argarray[i],
+      check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[i],
                                        i + 1);
   else
     {
@@ -5291,10 +5302,11 @@ check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
            }
 
          if (a != NULL_TREE)
-           check_function_arguments_recurse (check_nonnull_arg, &loc,
+           check_function_arguments_recurse (check_nonnull_arg, &ctx,
                                              argarray[i], i + 1);
        }
     }
+  return ctx.warned_p;
 }
 
 /* Check that the Nth argument of a function call (counting backwards
@@ -5379,7 +5391,7 @@ nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num)
 static void
 check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
 {
-  location_t *ploc = (location_t *) ctx;
+  struct nonnull_arg_ctx *pctx = (struct nonnull_arg_ctx *) ctx;
 
   /* Just skip checking the argument if it's not a pointer.  This can
      happen if the "nonnull" attribute was given without an operand
@@ -5391,9 +5403,12 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
   /* When not optimizing diagnose the simple cases of null arguments.
      When optimization is enabled defer the checking until expansion
      when more cases can be detected.  */
-  if (!optimize && integer_zerop (param))
-    warning_at (*ploc, OPT_Wnonnull, "null argument where non-null required "
-               "(argument %lu)", (unsigned long) param_num);
+  if (integer_zerop (param))
+    {
+      warning_at (pctx->loc, OPT_Wnonnull, "null argument where non-null "
+                 "required (argument %lu)", (unsigned long) param_num);
+      pctx->warned_p = true;
+    }
 }
 
 /* Helper for nonnull attribute handling; fetch the operand number
@@ -5587,16 +5602,19 @@ attribute_fallthrough_p (tree attr)
 \f
 /* Check for valid arguments being passed to a function with FNTYPE.
    There are NARGS arguments in the array ARGARRAY.  LOC should be used for
-   diagnostics.  */
-void
+   diagnostics.  Return true if -Wnonnull warning has been diagnosed.  */
+bool
 check_function_arguments (location_t loc, const_tree fntype, int nargs,
                          tree *argarray)
 {
+  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.  */
 
   if (warn_nonnull)
-    check_function_nonnull (loc, TYPE_ATTRIBUTES (fntype), nargs, argarray);
+    warned_p = check_function_nonnull (loc, TYPE_ATTRIBUTES (fntype),
+                                      nargs, argarray);
 
   /* Check for errors in format strings.  */
 
@@ -5605,6 +5623,7 @@ check_function_arguments (location_t loc, const_tree fntype, int nargs,
 
   if (warn_format)
     check_function_sentinel (fntype, nargs, argarray);
+  return warned_p;
 }
 
 /* Generic argument checking recursion routine.  PARAM is the argument to
index a23193ee9db9dfbac6946e0c359f3bc0b28ab6cf..b9131e3e9581935a801f53ec34d6bf5dda814a88 100644 (file)
@@ -804,7 +804,7 @@ extern const char *fname_as_string (int);
 extern tree fname_decl (location_t, unsigned, tree);
 
 extern int check_user_alignment (const_tree, bool);
-extern void check_function_arguments (location_t loc, const_tree, int, tree *);
+extern bool check_function_arguments (location_t loc, const_tree, int, tree *);
 extern void check_function_arguments_recurse (void (*)
                                              (void *, tree,
                                               unsigned HOST_WIDE_INT),
index 65eb93db4df85bd52a8679ca57eb6af437e60f8c..7a5e741189081b9defd6e76503501b0612855b78 100644 (file)
@@ -1,5 +1,9 @@
 2016-12-21  Jakub Jelinek  <jakub@redhat.com>
 
+       PR bootstrap/78817
+       * c-typeck.c (build_function_call_vec): If check_function_arguments
+       returns true, set TREE_NO_WARNING on CALL_EXPR.
+
        PR c/77767
        * c-decl.c (grokdeclarator): If *expr is non-NULL, append expression
        to *expr instead of overwriting it.
index c134280325dab079a61bdd15b38295cecc7d32ba..a269682d4ed98da960139d8e0c47d698ae7720b2 100644 (file)
@@ -3110,15 +3110,15 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
     return error_mark_node;
 
   /* Check that the arguments to the function are valid.  */
-  check_function_arguments (loc, fntype, nargs, argarray);
+  bool warned_p = check_function_arguments (loc, fntype, nargs, argarray);
 
   if (name != NULL_TREE
       && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
     {
       if (require_constant_value)
-       result =
-         fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
-                                                function, nargs, argarray);
+       result
+         fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
+                                                  function, nargs, argarray);
       else
        result = fold_build_call_array_loc (loc, TREE_TYPE (fntype),
                                            function, nargs, argarray);
@@ -3129,6 +3129,10 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   else
     result = build_call_array_loc (loc, TREE_TYPE (fntype),
                                   function, nargs, argarray);
+  /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again
+     later.  */
+  if (warned_p && TREE_CODE (result) == CALL_EXPR)
+    TREE_NO_WARNING (result) = 1;
 
   /* In this improbable scenario, a nested function returns a VM type.
      Create a TARGET_EXPR so that the call always has a LHS, much as
index 84664273fd4f55f8bf6c9157230c7ec56b40fbe6..bc3cbd599fc321a5422a2a7b214952eb14aded71 100644 (file)
@@ -1501,91 +1501,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason)
   error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason);
 }
 
-/* Return a bitmap with a bit set corresponding to each argument in
-   a function call expression CALLEXPR declared with attribute nonnull,
-   or null if none of the function's argument are nonnull.  The caller
-   must free the bitmap.  */
-
-bitmap
-get_nonnull_args (const_tree callexpr)
-{
-  tree fn = CALL_EXPR_FN (callexpr);
-  if (!fn || TREE_CODE (fn) != ADDR_EXPR)
-    return NULL;
-
-  tree fndecl = TREE_OPERAND (fn, 0);
-  tree fntype = TREE_TYPE (fndecl);
-  tree attrs = TYPE_ATTRIBUTES (fntype);
-  if (!attrs)
-    return NULL;
-
-  bitmap argmap = NULL;
-
-  /* A function declaration can specify multiple attribute nonnull,
-     each with zero or more arguments.  The loop below creates a bitmap
-     representing a union of all the arguments.  An empty (but non-null)
-     bitmap means that all arguments have been declaraed nonnull.  */
-  for ( ; attrs; attrs = TREE_CHAIN (attrs))
-    {
-      attrs = lookup_attribute ("nonnull", attrs);
-      if (!attrs)
-       break;
-
-      if (!argmap)
-       argmap = BITMAP_ALLOC (NULL);
-
-      if (!TREE_VALUE (attrs))
-       {
-         /* Clear the bitmap in case a previous attribute nonnull
-            set it and this one overrides it for all arguments.  */
-         bitmap_clear (argmap);
-         return argmap;
-       }
-
-      /* Iterate over the indices of the format arguments declared nonnull
-        and set a bit for each.  */
-      for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
-       {
-         unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
-         bitmap_set_bit (argmap, val);
-       }
-    }
-
-  return argmap;
-}
-
-/* In a call EXP to a function FNDECL some of whose arguments may have
-   been declared with attribute nonnull as described by NONNULLARGS,
-   check actual argument ARG at the zero-based position ARGPOS for
-   equality to null and issue a warning if it is not expected to be.  */
-
-static void
-maybe_warn_null_arg (tree fndecl, tree exp, tree arg,
-                    unsigned argpos, bitmap nonnullargs)
-{
-  if (!optimize
-      || !nonnullargs
-      || TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE
-      || !integer_zerop (arg)
-      || (!bitmap_empty_p (nonnullargs)
-         && !bitmap_bit_p (nonnullargs, argpos)))
-    return;
-
-  ++argpos;
-
-  location_t exploc EXPR_LOCATION (exp);
-
-  if (warning_at (exploc, OPT_Wnonnull,
-                 "argument %u null where non-null expected", argpos))
-    {
-      if (DECL_IS_BUILTIN (fndecl))
-       inform (exploc, "in a call to built-in function %qD", fndecl);
-      else
-       inform (DECL_SOURCE_LOCATION (fndecl),
-               "in a call to function %qD declared here", fndecl);
-    }
-}
-
 /* Fill in ARGS_SIZE and ARGS array based on the parameters found in
    CALL_EXPR EXP.
 
@@ -1769,9 +1684,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
   /* Array for up to the two attribute alloc_size arguments.  */
   tree alloc_args[] = { NULL_TREE, NULL_TREE };
 
-  /* Get a bitmap of pointer argument numbers declared attribute nonnull.  */
-  bitmap nonnullargs = get_nonnull_args (exp);
-
   /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */
   for (argpos = 0; argpos < num_actuals; i--, argpos++)
     {
@@ -2003,11 +1915,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
       if (args[i].locate.size.var)
        ADD_PARM_SIZE (*args_size, args[i].locate.size.var);
 
-      /* Check pointer argument for equality to NULL that is being passed
-        to arguments declared with attribute nonnull and warn.  */
-      maybe_warn_null_arg (fndecl, exp, args[i].tree_value, argpos,
-                          nonnullargs);
-
       /* Increment ARGS_SO_FAR, which has info about which arg-registers
         have been used, etc.  */
 
@@ -2028,8 +1935,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
         alloc_size.  */
       maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx);
     }
-
-  BITMAP_FREE (nonnullargs);
 }
 
 /* Update ARGS_SIZE to contain the total size for the argument block.
index 9d2084c1c816c42c67cd552d0a861c1b9deddfd4..3b0726345afb98430d380531b1c8bb757c67f61d 100644 (file)
@@ -38,6 +38,5 @@ extern bool pass_by_reference (CUMULATIVE_ARGS *, machine_mode,
 extern bool reference_callee_copied (CUMULATIVE_ARGS *, machine_mode,
                                     tree, bool);
 extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]);
-extern bitmap get_nonnull_args (const_tree);
 
 #endif // GCC_CALLS_H
index 180a0fbbd71c77a790057cce101fa2c4c9bf0f5b..e493fd1fa52be44a68489a8dbbb72359b6ce83b1 100644 (file)
@@ -1,5 +1,10 @@
 2016-12-21  Jakub Jelinek  <jakub@redhat.com>
 
+       PR bootstrap/78817
+       * typeck.c (cp_build_function_call_vec): If check_function_arguments
+       returns true, set TREE_NO_WARNING on CALL_EXPR.
+       * call.c (build_over_call): Likewise.
+
        PR c++/77830
        * constexpr.c (cxx_eval_array_reference): Perform out of bounds
        verification even if lval is true, just allow one past the last
index b7aa97cc947e8fa80dd99aef7cf2e8a89b861c43..894f98e5752f62c95de93d6a7bbbadb40f03d5f6 100644 (file)
@@ -7881,6 +7881,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
      nonnull are disabled.  Just in case that at least one of them is active
      the check_function_arguments function might warn about something.  */
 
+  bool warned_p = false;
   if (warn_nonnull || warn_format || warn_suggest_attribute_format)
     {
       tree *fargs = (!nargs ? argarray
@@ -7888,7 +7889,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       for (j = 0; j < nargs; j++)
        fargs[j] = maybe_constant_value (argarray[j]);
 
-      check_function_arguments (input_location, TREE_TYPE (fn), nargs, fargs);
+      warned_p = check_function_arguments (input_location, TREE_TYPE (fn),
+                                          nargs, fargs);
     }
 
   if (DECL_INHERITED_CTOR (fn))
@@ -8107,6 +8109,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       /* build_new_op_1 will clear this when appropriate.  */
       CALL_EXPR_ORDERED_ARGS (c) = true;
     }
+  if (warned_p)
+    {
+      tree c = extract_call_expr (call);
+      if (TREE_CODE (c) == CALL_EXPR)
+       TREE_NO_WARNING (c) = 1;
+    }
   return call;
 }
 
index 68fe19eeadb93232ecebc42cc13bd5843628ff0e..21282c7f048fa75c3feae50b62acd6154f94a789 100644 (file)
@@ -3654,10 +3654,18 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
 
   /* Check for errors in format strings and inappropriately
      null parameters.  */
-  check_function_arguments (input_location, fntype, nargs, argarray);
+  bool warned_p = check_function_arguments (input_location, fntype,
+                                           nargs, argarray);
 
   ret = build_cxx_call (function, nargs, argarray, complain);
 
+  if (warned_p)
+    {
+      tree c = extract_call_expr (ret);
+      if (TREE_CODE (c) == CALL_EXPR)
+       TREE_NO_WARNING (c) = 1;
+    }
+
   if (allocated != NULL)
     release_tree_vector (allocated);
 
index 7b12a419547ca97ad7d533af803ab3dedbc5be0d..99ae3f4c9ceb4189d40c0b624bff761507ff0331 100644 (file)
@@ -193,6 +193,7 @@ along with GCC; see the file COPYING3.  If not see
         They ensure memory accesses are not indirect wherever possible.  */
       NEXT_PASS (pass_strip_predict_hints);
       NEXT_PASS (pass_ccp, true /* nonzero_p */);
+      NEXT_PASS (pass_post_ipa_warn);
       /* After CCP we rewrite no longer addressed locals into SSA
         form if possible.  */
       NEXT_PASS (pass_complete_unrolli);
@@ -360,6 +361,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_lower_vector_ssa);
       /* Perform simple scalar cleanup which is constant/copy propagation.  */
       NEXT_PASS (pass_ccp, true /* nonzero_p */);
+      NEXT_PASS (pass_post_ipa_warn);
       NEXT_PASS (pass_object_sizes);
       /* Fold remaining builtins.  */
       NEXT_PASS (pass_fold_builtins);
index 8befebe17b17c99fe3b51e46db0a78f064750dfd..6a8bcc5c6556c682286a9923980419b424a8d1e3 100644 (file)
@@ -422,6 +422,7 @@ extern gimple_opt_pass *make_pass_omp_device_lower (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_object_sizes (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_fold_builtins (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_post_ipa_warn (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_stdarg (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_early_warn_uninitialized (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_late_warn_uninitialized (gcc::context *ctxt);
index fb90d02e9962da458065d12272dcf4f845c8496c..24a9fc1248781e338b6aae901e49d2ffb74d0ec2 100644 (file)
@@ -144,6 +144,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "optabs-query.h"
 #include "tree-ssa-ccp.h"
 #include "tree-dfa.h"
+#include "diagnostic-core.h"
 
 /* Possible lattice values.  */
 typedef enum
@@ -3316,3 +3317,97 @@ make_pass_fold_builtins (gcc::context *ctxt)
 {
   return new pass_fold_builtins (ctxt);
 }
+
+/* A simple pass that emits some warnings post IPA.  */
+
+namespace {
+
+const pass_data pass_data_post_ipa_warn =
+{
+  GIMPLE_PASS, /* type */
+  "post_ipa_warn", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_post_ipa_warn : public gimple_opt_pass
+{
+public:
+  pass_post_ipa_warn (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_post_ipa_warn, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_post_ipa_warn (m_ctxt); }
+  virtual bool gate (function *) { return warn_nonnull != 0; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_fold_builtins
+
+unsigned int
+pass_post_ipa_warn::execute (function *fun)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      gimple_stmt_iterator gsi;
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple *stmt = gsi_stmt (gsi);
+         if (!is_gimple_call (stmt) || gimple_no_warning_p (stmt))
+           continue;
+
+         if (warn_nonnull)
+           {
+             bitmap nonnullargs
+               = get_nonnull_args (gimple_call_fntype (stmt));
+             if (nonnullargs)
+               {
+                 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);
+                     if (warning_at (loc, OPT_Wnonnull,
+                                     "argument %u null where non-null "
+                                     "expected", 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);
+               }
+           }
+       }
+    }
+  return 0;
+}
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_post_ipa_warn (gcc::context *ctxt)
+{
+  return new pass_post_ipa_warn (ctxt);
+}
index 2a60386652277bcc037cfe6d0b5d29aa0c59ac8d..3a6e6d10787a6497e759ea37ee327dfa380c20ee 100644 (file)
@@ -14313,6 +14313,56 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+/* Return a bitmap with a bit set corresponding to each argument in
+   a function call type FNTYPE declared with attribute nonnull,
+   or null if none of the function's argument are nonnull.  The caller
+   must free the bitmap.  */
+
+bitmap
+get_nonnull_args (const_tree fntype)
+{
+  if (fntype == NULL_TREE)
+    return NULL;
+
+  tree attrs = TYPE_ATTRIBUTES (fntype);
+  if (!attrs)
+    return NULL;
+
+  bitmap argmap = NULL;
+
+  /* A function declaration can specify multiple attribute nonnull,
+     each with zero or more arguments.  The loop below creates a bitmap
+     representing a union of all the arguments.  An empty (but non-null)
+     bitmap means that all arguments have been declaraed nonnull.  */
+  for ( ; attrs; attrs = TREE_CHAIN (attrs))
+    {
+      attrs = lookup_attribute ("nonnull", attrs);
+      if (!attrs)
+       break;
+
+      if (!argmap)
+       argmap = BITMAP_ALLOC (NULL);
+
+      if (!TREE_VALUE (attrs))
+       {
+         /* Clear the bitmap in case a previous attribute nonnull
+            set it and this one overrides it for all arguments.  */
+         bitmap_clear (argmap);
+         return argmap;
+       }
+
+      /* Iterate over the indices of the format arguments declared nonnull
+        and set a bit for each.  */
+      for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
+       {
+         unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
+         bitmap_set_bit (argmap, val);
+       }
+    }
+
+  return argmap;
+}
+
 #if CHECKING_P
 
 namespace selftest {
index 62cd7bb19c3a2ae41b13568b0020eaabac3e5cbb..e3192027575cdb1dbd834c589c6d7a9b8af53b3e 100644 (file)
@@ -4855,6 +4855,7 @@ extern void DEBUG_FUNCTION verify_type (const_tree t);
 extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
                                                 bool trust_type_canonical = true);
 extern bool type_with_interoperable_signedness (const_tree);
+extern bitmap get_nonnull_args (const_tree);
 
 /* Return simplified tree code of type that is used for canonical type
    merging.  */