diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 123 |
1 files changed, 54 insertions, 69 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 8d321a292f5..6ea3800be8d 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -554,7 +554,7 @@ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, bool *); static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); -static void check_function_nonnull (tree, tree); +static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); @@ -5710,13 +5710,15 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), } /* Check the argument list of a function call for null in argument slots - that are marked as requiring a non-null pointer argument. */ + that are marked as requiring a non-null pointer argument. The NARGS + arguments are passed in the array ARGARRAY. +*/ static void -check_function_nonnull (tree attrs, tree params) +check_function_nonnull (tree attrs, int nargs, tree *argarray) { - tree a, args, param; - int param_num; + tree a, args; + int i; for (a = attrs; a; a = TREE_CHAIN (a)) { @@ -5728,85 +5730,65 @@ check_function_nonnull (tree attrs, tree params) should check for non-null, do it. If the attribute has no args, then every pointer argument is checked (in which case the check for pointer type is done in check_nonnull_arg). */ - for (param = params, param_num = 1; ; - param_num++, param = TREE_CHAIN (param)) + for (i = 0; i < nargs; i++) { - if (!param) - break; - if (!args || nonnull_check_p (args, param_num)) + if (!args || nonnull_check_p (args, i + 1)) check_function_arguments_recurse (check_nonnull_arg, NULL, - TREE_VALUE (param), - param_num); + argarray[i], + i + 1); } } } } /* Check that the Nth argument of a function call (counting backwards - from the end) is a (pointer)0. */ + from the end) is a (pointer)0. The NARGS arguments are passed in the + array ARGARRAY. */ static void -check_function_sentinel (tree attrs, tree params, tree typelist) +check_function_sentinel (tree attrs, int nargs, tree *argarray, tree typelist) { tree attr = lookup_attribute ("sentinel", attrs); if (attr) { - /* Skip over the named arguments. */ - while (typelist && params) - { - typelist = TREE_CHAIN (typelist); - params = TREE_CHAIN (params); - } + int len = 0; + int pos = 0; + tree sentinel; - if (typelist || !params) - warning (OPT_Wformat, - "not enough variable arguments to fit a sentinel"); - else + /* Skip over the named arguments. */ + while (typelist && len < nargs) { - tree sentinel, end; - unsigned pos = 0; - - if (TREE_VALUE (attr)) - { - tree p = TREE_VALUE (TREE_VALUE (attr)); - pos = TREE_INT_CST_LOW (p); - } - - sentinel = end = params; - - /* Advance `end' ahead of `sentinel' by `pos' positions. */ - while (pos > 0 && TREE_CHAIN (end)) - { - pos--; - end = TREE_CHAIN (end); - } - if (pos > 0) - { - warning (OPT_Wformat, - "not enough variable arguments to fit a sentinel"); - return; - } + typelist = TREE_CHAIN (typelist); + len++; + } - /* Now advance both until we find the last parameter. */ - while (TREE_CHAIN (end)) - { - end = TREE_CHAIN (end); - sentinel = TREE_CHAIN (sentinel); - } + if (TREE_VALUE (attr)) + { + tree p = TREE_VALUE (TREE_VALUE (attr)); + pos = TREE_INT_CST_LOW (p); + } - /* Validate the sentinel. */ - if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel))) - || !integer_zerop (TREE_VALUE (sentinel))) - /* Although __null (in C++) is only an integer we allow it - nevertheless, as we are guaranteed that it's exactly - as wide as a pointer, and we don't want to force - users to cast the NULL they have written there. - We warn with -Wstrict-null-sentinel, though. */ - && (warn_strict_null_sentinel - || null_node != TREE_VALUE (sentinel))) - warning (OPT_Wformat, "missing sentinel in function call"); + /* The sentinel must be one of the varargs, i.e. + in position >= the number of fixed arguments. */ + if ((nargs - 1 - pos) < len) + { + warning (OPT_Wformat, + "not enough variable arguments to fit a sentinel"); + return; } + + /* Validate the sentinel. */ + sentinel = argarray[nargs - 1 - pos]; + if ((!POINTER_TYPE_P (TREE_TYPE (sentinel)) + || !integer_zerop (sentinel)) + /* Although __null (in C++) is only an integer we allow it + nevertheless, as we are guaranteed that it's exactly + as wide as a pointer, and we don't want to force + users to cast the NULL they have written there. + We warn with -Wstrict-null-sentinel, though. */ + && (warn_strict_null_sentinel || null_node != sentinel)) + warning (OPT_Wformat, "missing sentinel in function call"); } } @@ -5996,23 +5978,26 @@ handle_sentinel_attribute (tree *node, tree name, tree args, return NULL_TREE; } -/* Check for valid arguments being passed to a function. */ +/* Check for valid arguments being passed to a function. + ATTRS is a list of attributes. There are NARGS arguments in the array + ARGARRAY. TYPELIST is the list of argument types for the function. + */ void -check_function_arguments (tree attrs, tree params, tree typelist) +check_function_arguments (tree attrs, int nargs, tree *argarray, tree typelist) { /* 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 (attrs, params); + check_function_nonnull (attrs, nargs, argarray); /* Check for errors in format strings. */ if (warn_format || warn_missing_format_attribute) - check_function_format (attrs, params); + check_function_format (attrs, nargs, argarray); if (warn_format) - check_function_sentinel (attrs, params, typelist); + check_function_sentinel (attrs, nargs, argarray, typelist); } /* Generic argument checking recursion routine. PARAM is the argument to |