+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
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);
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)
{
/* 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;
}
}
/* 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));
+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.
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;
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,
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
{
}
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
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
/* 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
\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. */
if (warn_format)
check_function_sentinel (fntype, nargs, argarray);
+ return warned_p;
}
/* Generic argument checking recursion routine. PARAM is the argument to
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),
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.
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);
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
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.
/* 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++)
{
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. */
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.
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
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
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
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))
/* 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;
}
/* 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);
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);
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);
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);
#include "optabs-query.h"
#include "tree-ssa-ccp.h"
#include "tree-dfa.h"
+#include "diagnostic-core.h"
/* Possible lattice values. */
typedef enum
{
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);
+}
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 {
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. */