From: Jakub Jelinek Date: Wed, 21 Dec 2016 22:15:59 +0000 (+0100) Subject: re PR bootstrap/78817 (stage2 bootstrap failure in vec.h:1613:5: error: argument... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0dba79602a7e3fb62bebee58b2cd7c24115b4faf;p=gcc.git re PR bootstrap/78817 (stage2 bootstrap failure in vec.h:1613:5: error: argument 1 null where non-null expected after r243661) 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1454cce9c5d..e9ce90d530c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2016-12-21 Jakub Jelinek + + 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 PR rtl-optimization/11488 diff --git a/gcc/builtins.c b/gcc/builtins.c index ca038cdcc7c..216d9261b23 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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)); diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 13ba2f314a9..acdedc8e024 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,14 @@ +2016-12-21 Jakub Jelinek + + 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 * c.opt (-fnew-ttp-matching): New flag. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index b690afb5e04..81dc888e9b3 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -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) /* 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 diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index a23193ee9db..b9131e3e958 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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), diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 65eb93db4df..7a5e7411890 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,5 +1,9 @@ 2016-12-21 Jakub Jelinek + 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. diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c134280325d..a269682d4ed 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3110,15 +3110,15 @@ build_function_call_vec (location_t loc, vec 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 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 diff --git a/gcc/calls.c b/gcc/calls.c index 84664273fd4..bc3cbd599fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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. diff --git a/gcc/calls.h b/gcc/calls.h index 9d2084c1c81..3b0726345af 100644 --- a/gcc/calls.h +++ b/gcc/calls.h @@ -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 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 180a0fbbd71..e493fd1fa52 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,10 @@ 2016-12-21 Jakub Jelinek + 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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index b7aa97cc947..894f98e5752 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 68fe19eeadb..21282c7f048 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3654,10 +3654,18 @@ cp_build_function_call_vec (tree function, vec **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); diff --git a/gcc/passes.def b/gcc/passes.def index 7b12a419547..99ae3f4c9ce 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -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); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 8befebe17b1..6a8bcc5c655 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -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); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index fb90d02e996..24a9fc12487 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -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); +} diff --git a/gcc/tree.c b/gcc/tree.c index 2a603866522..3a6e6d10787 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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 { diff --git a/gcc/tree.h b/gcc/tree.h index 62cd7bb19c3..e3192027575 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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. */