unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < gimple_call_num_args (stmt)
- && idx2 < gimple_call_num_args (stmt))
+ && idx2 < gimple_call_num_args (stmt)
+ && idx3 < gimple_call_num_args (stmt))
{
tree arg = gimple_call_arg (stmt, idx);
tree arg2 = gimple_call_arg (stmt, idx2);
+ tree arg3 = gimple_call_arg (stmt, idx3);
if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE
|| !INTEGRAL_TYPE_P (TREE_TYPE (arg2))
- || integer_zerop (arg2))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (arg3))
+ || integer_zerop (arg2)
+ || integer_zerop (arg3))
continue;
- if (integer_nonzerop (arg2))
+ if (integer_nonzerop (arg2) && integer_nonzerop (arg3))
;
else
- /* FIXME: Use ranger here to query arg2 range? */
+ /* FIXME: Use ranger here to query arg2 and arg3
+ ranges? */
continue;
handle_nonnull (sm_ctxt, node, stmt, fndecl, arg, idx);
}
DEF_LIST_INT_INT (5,6)
#undef DEF_LIST_INT_INT
+/* Construct a tree for a list of three integers. */
+#define DEF_LIST_INT_INT_INT(VALUE1, VALUE2, VALUE3) \
+ DEF_ATTR_TREE_LIST (ATTR_LIST_##VALUE1##_##VALUE2##_##VALUE3, \
+ ATTR_NULL, ATTR_##VALUE1, \
+ ATTR_LIST_##VALUE2##_##VALUE3)
+DEF_LIST_INT_INT_INT (1,2,3)
+#undef DEF_LIST_INT_INT_INT
+
/* Construct trees for identifiers used in built-in function attributes.
The construction contributes to startup costs so only attributes that
are used to define built-ins should be defined here. */
DEF_ATTR_TREE_LIST (ATTR_NONNULL_2, ATTR_NONNULL, ATTR_LIST_2, ATTR_NULL)
/* Functions whose third parameter is a nonnull pointer. */
DEF_ATTR_TREE_LIST (ATTR_NONNULL_3, ATTR_NONNULL, ATTR_LIST_3, ATTR_NULL)
+/* Functions whose selected pointer parameter(s) are conditionally
+ nonnull. */
+DEF_ATTR_TREE_LIST (ATTR_NONNULL_IF123_LIST, ATTR_NONNULL_IF_NONZERO, \
+ ATTR_LIST_1_2_3, ATTR_NULL)
+DEF_ATTR_TREE_LIST (ATTR_NONNULL_4_IF123_LIST, ATTR_NONNULL, \
+ ATTR_LIST_4, ATTR_NONNULL_IF123_LIST)
/* Nothrow functions with the sentinel(1) attribute. */
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_SENTINEL_1, ATTR_SENTINEL, ATTR_LIST_1, \
ATTR_NOTHROW_LIST)
unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < (unsigned) call_expr_nargs (callexpr)
&& idx2 < (unsigned) call_expr_nargs (callexpr)
+ && idx3 < (unsigned) call_expr_nargs (callexpr)
&& POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (callexpr, idx)))
&& integer_zerop (CALL_EXPR_ARG (callexpr, idx))
&& INTEGRAL_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (callexpr, idx2)))
- && integer_nonzerop (CALL_EXPR_ARG (callexpr, idx2)))
+ && integer_nonzerop (CALL_EXPR_ARG (callexpr, idx2))
+ && INTEGRAL_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (callexpr, idx3)))
+ && integer_nonzerop (CALL_EXPR_ARG (callexpr, idx3)))
return false;
}
DEF_LIB_BUILTIN (BUILT_IN_FPUTS, "fputs", BT_FN_INT_CONST_STRING_FILEPTR, ATTR_NONNULL_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FPUTS_UNLOCKED, "fputs_unlocked", BT_FN_INT_CONST_STRING_FILEPTR, ATTR_NONNULL_LIST)
DEF_LIB_BUILTIN (BUILT_IN_FSCANF, "fscanf", BT_FN_INT_FILEPTR_CONST_STRING_VAR, ATTR_FORMAT_SCANF_2_3)
-DEF_LIB_BUILTIN (BUILT_IN_FWRITE, "fwrite", BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, ATTR_NONNULL_LIST)
-DEF_EXT_LIB_BUILTIN (BUILT_IN_FWRITE_UNLOCKED, "fwrite_unlocked", BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, ATTR_NONNULL_LIST)
+DEF_LIB_BUILTIN (BUILT_IN_FWRITE, "fwrite", BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, ATTR_NONNULL_4_IF123_LIST)
+DEF_EXT_LIB_BUILTIN (BUILT_IN_FWRITE_UNLOCKED, "fwrite_unlocked", BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, ATTR_NONNULL_4_IF123_LIST)
DEF_LIB_BUILTIN (BUILT_IN_PRINTF, "printf", BT_FN_INT_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_1_2)
DEF_EXT_LIB_BUILTIN (BUILT_IN_PRINTF_UNLOCKED, "printf_unlocked", BT_FN_INT_CONST_STRING_VAR, ATTR_NONNULL_1_FORMAT_PRINTF_1_2)
DEF_LIB_BUILTIN (BUILT_IN_PUTCHAR, "putchar", BT_FN_INT_INT, ATTR_NULL)
handle_tls_model_attribute, NULL },
{ "nonnull", 0, -1, false, true, true, false,
handle_nonnull_attribute, NULL },
- { "nonnull_if_nonzero", 2, 2, false, true, true, false,
+ { "nonnull_if_nonzero", 2, 3, false, true, true, false,
handle_nonnull_if_nonzero_attribute, NULL },
{ "nonstring", 0, 0, true, false, false, false,
handle_nonstring_attribute, NULL },
tree type = *node;
tree pos = TREE_VALUE (args);
tree pos2 = TREE_VALUE (TREE_CHAIN (args));
+ tree chain2 = TREE_CHAIN (TREE_CHAIN (args));
+ tree pos3 = NULL_TREE;
+ if (chain2)
+ pos3 = TREE_VALUE (chain2);
tree val = positional_argument (type, name, pos, POINTER_TYPE, 1);
tree val2 = positional_argument (type, name, pos2, INTEGER_TYPE, 2);
- if (val && val2)
+ tree val3 = NULL_TREE;
+ if (chain2)
+ val3 = positional_argument (type, name, pos3, INTEGER_TYPE, 3);
+ if (val && val2 && (!chain2 || val3))
{
TREE_VALUE (args) = val;
TREE_VALUE (TREE_CHAIN (args)) = val2;
+ if (chain2)
+ TREE_VALUE (chain2) = val3;
}
else
*no_add_attrs = true;
/* The function whose arguments are being checked and its type (used
for calls through function pointers). */
const_tree fndecl, fntype;
- /* For nonnull_if_nonzero, index of the other argument. */
- unsigned HOST_WIDE_INT other;
+ /* For nonnull_if_nonzero, index of the other arguments. */
+ unsigned HOST_WIDE_INT other1, other2;
/* True if a warning has been issued. */
bool warned_p;
};
check_function_arguments_recurse (check_nonnull_arg, &ctx,
argarray[i], i + 1,
OPT_Wnonnull);
+ a = NULL_TREE;
}
}
if (a == NULL_TREE)
unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < (unsigned) nargs - firstarg
&& idx2 < (unsigned) nargs - firstarg
+ && idx3 < (unsigned) nargs - firstarg
&& INTEGRAL_TYPE_P (TREE_TYPE (argarray[firstarg + idx2]))
- && integer_nonzerop (argarray[firstarg + idx2]))
+ && integer_nonzerop (argarray[firstarg + idx2])
+ && INTEGRAL_TYPE_P (TREE_TYPE (argarray[firstarg + idx3]))
+ && integer_nonzerop (argarray[firstarg + idx3]))
{
- ctx.other = firstarg + idx2 + 1;
+ ctx.other1 = firstarg + idx2 + 1;
+ ctx.other2 = firstarg + idx3 + 1;
check_function_arguments_recurse (check_nonnull_arg, &ctx,
argarray[firstarg + idx],
firstarg + idx + 1,
OPT_Wnonnull);
- ctx.other = 0;
+ ctx.other1 = 0;
+ ctx.other2 = 0;
}
}
return ctx.warned_p;
}
else
{
- if (pctx->other)
+ if (pctx->other1 && pctx->other2 != pctx->other1)
+ warned = warning_at (loc, OPT_Wnonnull,
+ "argument %u null where non-null expected "
+ "because arguments %u and %u are nonzero",
+ (unsigned) param_num,
+ TREE_CODE (pctx->fntype) == METHOD_TYPE
+ ? (unsigned) pctx->other1 - 1
+ : (unsigned) pctx->other1,
+ TREE_CODE (pctx->fntype) == METHOD_TYPE
+ ? (unsigned) pctx->other2 - 1
+ : (unsigned) pctx->other2);
+ else if (pctx->other1)
warned = warning_at (loc, OPT_Wnonnull,
"argument %u null where non-null expected "
"because argument %u is nonzero",
(unsigned) param_num,
TREE_CODE (pctx->fntype) == METHOD_TYPE
- ? (unsigned) pctx->other - 1
- : (unsigned) pctx->other);
+ ? (unsigned) pctx->other1 - 1
+ : (unsigned) pctx->other1);
else
warned = warning_at (loc, OPT_Wnonnull,
"argument %u null where non-null expected",
inform (DECL_SOURCE_LOCATION (pctx->fndecl),
"in a call to function %qD declared %qs",
pctx->fndecl,
- pctx->other ? "nonnull_if_nonzero" : "nonnull");
+ pctx->other1 ? "nonnull_if_nonzero" : "nonnull");
}
if (warned)
to do this if format checking is enabled. */
if (warn_nonnull)
{
- nonnull_arg_ctx ctx = { loc, fndecl, fntype, 0, false };
+ nonnull_arg_ctx ctx = { loc, fndecl, fntype, 0, 0, false };
warned_p = check_function_nonnull (ctx, nargs, argarray);
}
@cindex @code{nonnull_if_nonzero} function attribute
@item nonnull_if_nonzero
@itemx nonnull_if_nonzero (@var{arg-index}, @var{arg2-index})
+@itemx nonnull_if_nonzero (@var{arg-index}, @var{arg2-index}, @var{arg3-index})
The @code{nonnull_if_nonzero} attribute is a conditional version of the
-@code{nonnull} attribute. It has two arguments, the first argument
+@code{nonnull} attribute. It has two or three arguments, the first argument
shall be argument index of a pointer argument which must be in some
cases non-null and the second argument shall be argument index of an
integral argument (other than boolean). If the integral argument is
zero, the pointer argument can be null, if it is non-zero, the pointer
-argument must not be null.
+argument must not be null. If three arguments are provided, the third
+argument shall be argument index of another integral argument (other than
+boolean) and the pointer argument can be null if either of the integral
+arguments are zero and if both are non-zero, the pointer argument must not
+be null.
@smallexample
extern void *
my_memcpy2 (void *dest, const void *src, size_t len)
__attribute__((nonnull_if_nonzero (1, 3),
nonnull_if_nonzero (2, 3)));
+extern size_t
+my_fread (void *buf, size_t size, size_t count, FILE *stream)
+ __attribute__((nonnull (4),
+ nonnull_if_nonzero (1, 2, 3)));
@end smallexample
With these declarations, it is invalid to call
@code{my_memcpy (NULL, NULL, 0);} or to
-call @code{my_memcpy2 (NULL, NULL, 4);} but it is valid
-to call @code{my_memcpy2 (NULL, NULL, 0);}. This attribute should be
+call @code{my_memcpy2 (NULL, NULL, 4);} or to call
+@code{my_fread(@var{buf}, 0, 0, NULL);} or to call
+@code{my_fread(NULL, 1, 1, @var{stream});} but it is valid
+to call @code{my_memcpy2 (NULL, NULL, 0);} or
+@code{my_fread(NULL, 0, 0, @var{stream});} or
+@code{my_fread(NULL, 0, 1, @var{stream});} or
+@code{my_fread(NULL, 1, 0, @var{stream});}. This attribute should be
used on declarations which have e.g.@: an exception for zero sizes,
in which case null may be passed.
unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < gimple_call_num_args (s)
- && idx2 < gimple_call_num_args (s))
+ && idx2 < gimple_call_num_args (s)
+ && idx3 < gimple_call_num_args (s))
{
tree arg = gimple_call_arg (s, idx);
tree arg2 = gimple_call_arg (s, idx2);
+ tree arg3 = gimple_call_arg (s, idx3);
if (!POINTER_TYPE_P (TREE_TYPE (arg))
|| !INTEGRAL_TYPE_P (TREE_TYPE (arg2))
- || integer_zerop (arg2))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (arg3))
+ || integer_zerop (arg2)
+ || integer_zerop (arg3))
continue;
- if (integer_nonzerop (arg2))
+ if (integer_nonzerop (arg2) && integer_nonzerop (arg3))
add_nonzero (arg);
else
{
value_range r (TREE_TYPE (arg2));
if (q->range_of_expr (r, arg2, s)
&& !r.contains_p (build_zero_cst (TREE_TYPE (arg2))))
- add_nonzero (arg);
+ {
+ if (idx2 == idx3)
+ add_nonzero (arg);
+ else
+ {
+ value_range r2 (TREE_TYPE (arg3));
+ tree zero3 = build_zero_cst (TREE_TYPE (arg3));
+ if (q->range_of_expr (r2, arg3, s)
+ && !r2.contains_p (zero3))
+ add_nonzero (arg);
+ }
+ }
}
}
}
}
/* Return true if OP can be inferred to be a non-NULL after STMT
- executes by using attributes. If OP2 is non-NULL and nonnull_if_nonzero
- is the only attribute implying OP being non-NULL and the corresponding
- argument isn't non-zero INTEGER_CST, set *OP2 to the corresponding
- argument and return true (in that case returning true doesn't mean
- OP can be unconditionally inferred to be non-NULL, but conditionally). */
+ executes by using attributes. If OP2 and OP3 are non-NULL and
+ nonnull_if_nonzero is the only attribute implying OP being non-NULL
+ and the corresponding argument(s) aren't non-zero INTEGER_CST, set *OP2
+ and *OP3 to the corresponding arguments and return true (in that case
+ returning true doesn't mean OP can be unconditionally inferred to be
+ non-NULL, but conditionally). */
bool
-infer_nonnull_range_by_attribute (gimple *stmt, tree op, tree *op2)
+infer_nonnull_range_by_attribute (gimple *stmt, tree op, tree *op2, tree *op3)
{
if (op2)
- *op2 = NULL_TREE;
+ {
+ *op2 = NULL_TREE;
+ *op3 = NULL_TREE;
+ }
/* We can only assume that a pointer dereference will yield
non-NULL if -fdelete-null-pointer-checks is enabled. */
unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < gimple_call_num_args (stmt)
&& idx2 < gimple_call_num_args (stmt)
+ && idx3 < gimple_call_num_args (stmt)
&& operand_equal_p (op, gimple_call_arg (stmt, idx), 0))
{
tree arg2 = gimple_call_arg (stmt, idx2);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
+ tree arg3 = gimple_call_arg (stmt, idx3);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (arg3)))
return false;
- if (integer_nonzerop (arg2))
+ if (integer_nonzerop (arg2) && integer_nonzerop (arg3))
return true;
- if (integer_zerop (arg2))
+ if (integer_zerop (arg2) || integer_zerop (arg3))
return false;
if (op2)
{
/* This case is meant for ubsan instrumentation.
- The caller can check at runtime if *OP2 is
+ The caller can check at runtime if *OP2 and *OP3 are
non-zero and OP is null. */
*op2 = arg2;
+ *op3 = arg3;
return true;
}
- return tree_expr_nonzero_p (arg2);
+ return tree_expr_nonzero_p (arg2) && tree_expr_nonzero_p (arg3);
}
}
}
extern bool nonbarrier_call_p (gimple *);
extern bool infer_nonnull_range (gimple *, tree);
extern bool infer_nonnull_range_by_dereference (gimple *, tree);
-extern bool infer_nonnull_range_by_attribute (gimple *, tree, tree * = NULL);
+extern bool infer_nonnull_range_by_attribute (gimple *, tree, tree * = NULL,
+ tree * = NULL);
extern void sort_case_labels (vec<tree> &);
extern void preprocess_case_label_vec_for_gimple (vec<tree> &, tree, tree *);
extern void gimple_seq_set_location (gimple_seq, location_t);
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-fsanitize=undefined -fno-sanitize-recover=undefined" } */
+
+__attribute__((noipa, nonnull_if_nonzero (1, 4, 7)))
+__attribute__((nonnull (3), nonnull_if_nonzero (5, 2, 6))) void
+foo (void *a, unsigned long b, void *c, int d, void *e, unsigned long f, int g)
+{
+ (void) a;
+ (void) b;
+ (void) c;
+ (void) d;
+ (void) e;
+ (void) f;
+ (void) g;
+}
+
+__attribute__((noipa))
+void
+bar (void *a, unsigned long b, void *c, int d, void *e, unsigned long f, int g)
+{
+ foo (a, b, c, d, e, f, g);
+}
+
+int
+main ()
+{
+ char x;
+ bar (&x, 42, &x, 1, &x, 2, 3);
+ bar (0, 0, &x, 0, 0, 0, 0);
+ bar (0, 5, &x, 4, 0, 0, 0);
+ bar (0, 0, &x, 0, 0, 6, 7);
+}
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-fsanitize=nonnull-attribute" } */
+
+__attribute__((noipa, nonnull_if_nonzero (1, 4, 7)))
+__attribute__((nonnull (3), nonnull_if_nonzero (5, 2, 6))) void
+foo (void *a, unsigned long b, void *c, int d, void *e, unsigned long f, int g)
+{
+ (void) a;
+ (void) b;
+ (void) c;
+ (void) d;
+ (void) e;
+ (void) f;
+ (void) g;
+}
+
+__attribute__((noipa))
+void
+bar (void *a, unsigned long b, void *c, int d, void *e, unsigned long f, int g)
+{
+ foo (a, b, c, d, e, f, g);
+}
+
+int
+main ()
+{
+ char x;
+ bar (&x, 42, 0, 1, &x, 17, 18);
+ bar (0, 25, &x, 7, &x, 0, 8);
+ bar (&x, -82, &x, 68, 0, 9, 0);
+ foo (&x, 42, 0, 1, &x, 17, 18);
+ foo (0, 25, &x, 7, &x, 0, 8);
+ foo (&x, -82, &x, 68, 0, 9, 0);
+}
+
+/* { dg-output "\.c:21:\[0-9]*:\[^\n\r]*null pointer passed as argument 3, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:21:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:21:\[0-9]*:\[^\n\r]*null pointer passed as argument 5, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:31:\[0-9]*:\[^\n\r]*null pointer passed as argument 3, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:32:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:33:\[0-9]*:\[^\n\r]*null pointer passed as argument 5, which is declared to never be null" } */
--- /dev/null
+/* Test for the "nonnull_if_nonzero" function attribute. */
+/* { dg-do compile } */
+/* { dg-options "-Wnonnull" } */
+
+#include <stddef.h>
+
+extern void func1 (char *, char *, int, int)
+ __attribute__((nonnull_if_nonzero (1, 3, 4), nonnull_if_nonzero (2, 3, 4)));
+
+extern void func2 (char *, char *, unsigned long, unsigned long)
+ __attribute__((nonnull_if_nonzero (1, 3, 4)));
+
+enum E { E0 = 0, E1 = 1, E2 = __INT_MAX__ };
+extern void func3 (char *, int, char *, enum E, int, enum E)
+ __attribute__((nonnull_if_nonzero (1, 4, 6), nonnull_if_nonzero (3, 2, 5)));
+
+extern void func4 (long, char *, char *, long, long, long)
+ __attribute__((nonnull_if_nonzero (2, 1, 5)))
+ __attribute__((nonnull_if_nonzero (3, 4, 6)));
+
+void
+foo (int i1, int i2, int i3, char *cp1, char *cp2, char *cp3)
+{
+ func1 (cp1, cp2, i1, i2);
+ func1 (cp1, cp2, 0, 0);
+ func1 (cp1, cp2, 42, 42);
+ func1 (NULL, NULL, 0, 0);
+ func1 (NULL, NULL, 0, 42);
+ func1 (NULL, NULL, 42, 0);
+ func1 (NULL, NULL, i1, i2);
+
+ func1 (NULL, cp2, 42, 42); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ func1 (cp1, NULL, 1, 1); /* { dg-warning "argument 2 null where non-null expected because arguments 3 and 4 are nonzero" } */
+
+ func2 (cp1, NULL, 17, 17);
+ func2 (NULL, cp2, 0, 0);
+ func2 (NULL, cp2, 0, 17);
+ func2 (NULL, cp2, 17, 0);
+ func2 (NULL, cp1, 2, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+
+ func3 (NULL, i2, cp3, i3, i3, i2);
+ func3 (cp1, i2, NULL, i3, i3, i2);
+ func3 (NULL, i2, cp3, E0, i3, E0);
+ func3 (NULL, i2, cp3, E0, i3, E1);
+ func3 (NULL, i2, cp3, E1, i3, E0);
+ func3 (cp1, 0, NULL, E2, 0, E2);
+ func3 (cp1, 0, NULL, E2, 4, E2);
+ func3 (cp1, 4, NULL, E2, 0, E2);
+ func3 (NULL, i2, cp3, E2, i3, E2); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ func3 (cp3, 5, NULL, i3, 1, i2); /* { dg-warning "argument 3 null where non-null expected because arguments 2 and 5 are nonzero" } */
+
+ func1 (i2 ? cp1 : NULL, cp2, i3, i3);
+ func1 (i2 ? NULL : cp1, cp2, i3, i3);
+ func1 (i2 ? (i3 ? cp1 : NULL) : cp2, cp3, i1, i1);
+ func1 (i1 ? cp1 : NULL, cp2, 0, 0);
+ func1 (i1 ? cp1 : NULL, cp2, 0, 4);
+ func1 (i1 ? cp1 : NULL, cp2, 4, 0);
+ func1 (i1 ? NULL : cp1, cp2, 0, 0);
+ func1 (i1 ? NULL : cp1, cp2, 0, 2);
+ func1 (i1 ? NULL : cp1, cp2, 3, 0);
+ func1 (i1 ? (i2 ? cp1 : NULL) : cp2, cp3, 0, 0);
+ func1 (i1 ? (i2 ? cp1 : NULL) : cp2, cp3, 0, 1);
+ func1 (i1 ? (i2 ? cp1 : NULL) : cp2, cp3, 2, 0);
+ func1 (i1 ? cp1 : NULL, cp2, 1, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ func1 (i1 ? NULL : cp1, cp2, 2, 3); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ func1 (i1 ? (i2 ? cp1 : NULL) : cp2, cp3, 3, 4); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+
+ func4 (0, NULL, NULL, 0, 0, 0);
+ func4 (0, NULL, NULL, 0, 1, 2);
+ func4 (3, NULL, NULL, 4, 0, 0);
+ func4 (-1, NULL, cp1, 0, 42, 0); /* { dg-warning "argument 2 null where non-null expected because arguments 1 and 5 are nonzero" } */
+ func4 (0, cp1, NULL, 77, 0, 12); /* { dg-warning "argument 3 null where non-null expected because arguments 4 and 6 are nonzero" } */
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wnonnull" } */
+
+#define N(x, y, z) __attribute__ ((nonnull_if_nonzero (x, y, z)))
+
+void N (1, 2, 3) f1_1 (void *, int, int);
+
+void N (1, 3, 4) f2_1 (void *, void *, int, int);
+void N (1, 3, 4) N (2, 3, 4) f2_1_2 (void *, void *, int, int);
+
+void N (1, 4, 6) N (3, 5, 7) f3_1_3 (void *, void *, void *, int, int, int, int);
+
+void N (1, 5, 6) N (2, 5, 6) N (4, 5, 6) g4_1_2_4 (void *, void *, void *, void *, long, long);
+void N (1, 5, 6) N (3, 5, 6) N (4, 5, 6) g4_1_3_4 (void *, void *, void *, void *, long, long);
+void N (2, 5, 6) N (3, 5, 6) N (4, 5, 6) g4_2_3_4 (void *, void *, void *, void *, long, long);
+
+void N (1, 17, 18) N (3, 17, 18) N (5, 17, 18) N (7, 17, 18) N (11, 17, 18) N (13, 17, 18)
+g16_1_3_5_7_11_13 (void *, void *, void *, void *,
+ void *, void *, void *, void *,
+ void *, void *, void *, void *,
+ void *, void *, void *, void *, int, int);
+
+static void *null (void) { return 0; }
+
+void
+test (int t, long u, int v, long w)
+{
+ void *p0 = null ();
+ void *px = &px;
+
+ f1_1 (p0, 0, 0);
+ f1_1 (p0, 0, 4);
+ f1_1 (p0, 3, 0);
+ f1_1 (p0, t, v);
+ f1_1 (p0, t, 0);
+ f1_1 (p0, 0, v);
+ f1_1 (p0, 42, 1); /* { dg-warning "argument 1 null where non-null expected because arguments 2 and 3 are nonzero" } */
+ if (t && v)
+ f1_1 (p0, t, v); /* { dg-warning "argument 1 null where non-null expected because arguments 2 and 3 are nonzero" } */
+ f1_1 (px, 17, 17);
+
+ f2_1 (p0, px, 0, 0);
+ f2_1 (p0, px, 0, 3);
+ f2_1 (p0, px, 7, 0);
+ f2_1 (p0, px, t, v);
+ f2_1 (p0, px, t, 0);
+ f2_1 (p0, px, 0, v);
+ f2_1 (p0, px, 5, 3); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ if (t > 4 && v > 8)
+ f2_1 (p0, px, t, v); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ f2_1 (px, p0, 17, 17);
+ f2_1 (p0, p0, 0, 0);
+ f2_1 (p0, p0, 0, 4);
+ f2_1 (p0, p0, 2, 0);
+ if (t < 0 && v < -3)
+ f2_1 (p0, p0, t, v); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+
+ f2_1_2 (p0, p0, 0, 0);
+ f2_1_2 (p0, p0, 0, 1);
+ f2_1_2 (p0, p0, 2, 0);
+ f2_1_2 (p0, p0, t, v);
+ f2_1_2 (p0, p0, t, 0);
+ f2_1_2 (p0, p0, 0, v);
+ f2_1_2 (p0, px, 1, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ if (t > 8 && v >= 16)
+ f2_1_2 (p0, px, t, v); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ f2_1_2 (px, p0, -3, -4); /* { dg-warning "argument 2 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ if (t < -2 && v >= 32)
+ f2_1_2 (px, p0, t, v); /* { dg-warning "argument 2 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ f2_1_2 (p0, p0, 8, 165); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ /* { dg-warning "argument 2 null where non-null expected because arguments 3 and 4 are nonzero" "argument 2" { target *-*-* } .-1 } */
+ if (t > 7 && v < -2)
+ f2_1_2 (p0, p0, t, v); /* { dg-warning "argument 1 null where non-null expected because arguments 3 and 4 are nonzero" } */
+ /* { dg-warning "argument 2 null where non-null expected because arguments 3 and 4 are nonzero" "argument 2" { target *-*-* } .-1 } */
+
+ f3_1_3 (p0, p0, p0, 0, 0, 0, 0);
+ f3_1_3 (p0, p0, p0, 0, 5, 4, 0);
+ f3_1_3 (p0, p0, p0, 3, 0, 0, 6);
+ f3_1_3 (p0, p0, px, 0, 6, 0, 6);
+ f3_1_3 (p0, p0, px, 0, 6, 4, 6);
+ f3_1_3 (p0, p0, px, 3, 6, 0, 6);
+ f3_1_3 (px, p0, p0, 2, 0, 2, 0);
+ f3_1_3 (px, p0, p0, 2, 0, 2, 4);
+ f3_1_3 (px, p0, p0, 2, 6, 2, 0);
+ f3_1_3 (p0, p0, p0, t, t, v, v);
+ f3_1_3 (p0, p0, px, t, 6, v, 7);
+ f3_1_3 (px, p0, p0, 2, t, 3, v);
+ f3_1_3 (p0, px, px, 8, 2, 3, 5); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ if (t > 9 && v < -19)
+ f3_1_3 (p0, px, px, t, 3, v, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ f3_1_3 (px, p0, px, 9, 10, 1, 2);
+ if (t > 11 && v > 3)
+ f3_1_3 (px, p0, px, t, t, v, v);
+ f3_1_3 (px, px, p0, 10, 11, 2, 3); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 7 are nonzero" } */
+ if (t < -5 && v > 2)
+ f3_1_3 (px, px, p0, 0, t, 2, v); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 7 are nonzero" } */
+ f3_1_3 (p0, p0, px, 11, 12, 1, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ if (t > 26 && v > 88)
+ f3_1_3 (p0, p0, px, t, 3, v, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ f3_1_3 (px, p0, p0, 12, 13, 1, 2); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 7 are nonzero" } */
+ if (t > 31 && v < -1)
+ f3_1_3 (px, p0, p0, 12, t, 2, v); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 7 are nonzero" } */
+ f3_1_3 (p0, p0, p0, 13, 14, 1, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 7 are nonzero" "argument 3" { target *-*-* } .-1 } */
+ if (t > 28 && v > 42)
+ f3_1_3 (p0, p0, p0, t, t + 1, v, v + 1); /* { dg-warning "argument 1 null where non-null expected because arguments 4 and 6 are nonzero" } */
+ /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 7 are nonzero" "argument 3" { target *-*-* } .-1 } */
+
+ g4_1_2_4 (p0, px, px, px, u, w);
+ g4_1_2_4 (px, p0, px, px, u, w);
+ g4_1_2_4 (px, px, p0, px, u, w);
+ g4_1_2_4 (px, px, px, p0, u, w);
+ g4_1_2_4 (p0, px, px, px, 0, 0);
+ g4_1_2_4 (p0, px, px, px, 0, 2);
+ g4_1_2_4 (p0, px, px, px, 1, 0);
+ g4_1_2_4 (px, p0, px, px, 0, 0);
+ g4_1_2_4 (px, p0, px, px, 0, 3);
+ g4_1_2_4 (px, p0, px, px, 4, 0);
+ g4_1_2_4 (px, px, p0, px, 0, 0);
+ g4_1_2_4 (px, px, p0, px, 0, 5);
+ g4_1_2_4 (px, px, p0, px, 6, 0);
+ g4_1_2_4 (px, px, px, p0, 0, 0);
+ g4_1_2_4 (px, px, px, p0, 0, 7);
+ g4_1_2_4 (px, px, px, p0, 8, 0);
+ g4_1_2_4 (p0, px, px, px, 15, 2); /* { dg-warning "argument 1 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u && w)
+ g4_1_2_4 (p0, px, px, px, u, w); /* { dg-warning "argument 1 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ g4_1_2_4 (px, p0, px, px, 16, 2); /* { dg-warning "argument 2 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 2 && w > 3)
+ g4_1_2_4 (px, p0, px, px, u, w); /* { dg-warning "argument 2 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ g4_1_2_4 (px, px, p0, px, 17, 8);
+ if (u > 3 && w < -2)
+ g4_1_2_4 (px, px, p0, px, u, w);
+ g4_1_2_4 (px, px, px, p0, 18, 3); /* { dg-warning "argument 4 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if ((u < -2 || u > 10) && (w < -4 || w > 42))
+ g4_1_2_4 (px, px, px, p0, u, w); /* { dg-warning "argument 4 null where non-null expected because arguments 5 and 6 are nonzero" } */
+
+ g4_1_3_4 (p0, px, px, px, u, u);
+ g4_1_3_4 (px, p0, px, px, u, u);
+ g4_1_3_4 (px, px, p0, px, u, u);
+ g4_1_3_4 (px, px, px, p0, u, u);
+ g4_1_3_4 (p0, px, px, px, 0, 0);
+ g4_1_3_4 (p0, px, px, px, 0, 1);
+ g4_1_3_4 (p0, px, px, px, 2, 0);
+ g4_1_3_4 (px, p0, px, px, 0, 0);
+ g4_1_3_4 (px, p0, px, px, 0, 3);
+ g4_1_3_4 (px, p0, px, px, 4, 0);
+ g4_1_3_4 (px, px, p0, px, 0, 0);
+ g4_1_3_4 (px, px, p0, px, 0, 5);
+ g4_1_3_4 (px, px, p0, px, 6, 0);
+ g4_1_3_4 (px, px, px, p0, 0, 0);
+ g4_1_3_4 (px, px, px, p0, 0, 7);
+ g4_1_3_4 (px, px, px, p0, 8, 0);
+ g4_1_3_4 (p0, px, px, px, 20, 32); /* { dg-warning "argument 1 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 4 && w > 2)
+ g4_1_3_4 (p0, px, px, px, u, w); /* { dg-warning "argument 1 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ g4_1_3_4 (px, p0, px, px, 21, 4);
+ if ((u > 6 || u < -24) && (w > 8 || w < -5))
+ g4_1_3_4 (px, p0, px, px, u, w);
+ g4_1_3_4 (px, px, p0, px, 22, 4); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 9 && w > 13)
+ g4_1_3_4 (px, px, p0, px, u - 3, w - 8); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ g4_1_3_4 (px, px, px, p0, 23, 8); /* { dg-warning "argument 4 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 10 && w > 12)
+ g4_1_3_4 (px, px, px, p0, u, w); /* { dg-warning "argument 4 null where non-null expected because arguments 5 and 6 are nonzero" } */
+
+ g4_2_3_4 (p0, px, px, px, u, u);
+ g4_2_3_4 (px, p0, px, px, u, u);
+ g4_2_3_4 (px, px, p0, px, u, u);
+ g4_2_3_4 (px, px, px, p0, u, u);
+ g4_2_3_4 (p0, px, px, px, 0, 0);
+ g4_2_3_4 (p0, px, px, px, 0, 1);
+ g4_2_3_4 (p0, px, px, px, 2, 0);
+ g4_2_3_4 (px, p0, px, px, 0, 0);
+ g4_2_3_4 (px, p0, px, px, 0, 3);
+ g4_2_3_4 (px, p0, px, px, 4, 0);
+ g4_2_3_4 (px, px, p0, px, 0, 0);
+ g4_2_3_4 (px, px, p0, px, 0, 5);
+ g4_2_3_4 (px, px, p0, px, 6, 0);
+ g4_2_3_4 (px, px, px, p0, 0, 0);
+ g4_2_3_4 (px, px, px, p0, 0, 7);
+ g4_2_3_4 (px, px, px, p0, 8, 0);
+ g4_2_3_4 (p0, px, px, px, 1, 2);
+ if (u > 12 && w > 16)
+ g4_2_3_4 (p0, px, px, px, u, w);
+ g4_2_3_4 (px, p0, px, px, 2, 3); /* { dg-warning "argument 2 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 17 && w > 19)
+ g4_2_3_4 (px, p0, px, px, u - 3, w - 2); /* { dg-warning "argument 2 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ g4_2_3_4 (px, px, p0, px, 3, 8); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 24 && w > 22)
+ g4_2_3_4 (px, px, p0, px, u, w); /* { dg-warning "argument 3 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ g4_2_3_4 (px, px, px, p0, 4, 2); /* { dg-warning "argument 4 null where non-null expected because arguments 5 and 6 are nonzero" } */
+ if (u > 42 && w > 48)
+ g4_2_3_4 (px, px, px, p0, u, w); /* { dg-warning "argument 4 null where non-null expected because arguments 5 and 6 are nonzero" } */
+
+ g16_1_3_5_7_11_13 (px, px, px, px, px, px, px, px,
+ px, px, px, px, px, px, px, px, 17, 18);
+ g16_1_3_5_7_11_13 (p0, p0, p0, p0, p0, p0, p0, p0,
+ p0, p0, p0, p0, p0, p0, p0, p0, t, v);
+ g16_1_3_5_7_11_13 (p0, p0, p0, p0, p0, p0, p0, p0,
+ p0, p0, p0, p0, p0, p0, p0, p0, 0, 0);
+ g16_1_3_5_7_11_13 (p0, p0, p0, p0, p0, p0, p0, p0,
+ p0, p0, p0, p0, p0, p0, p0, p0, 0, 4);
+ g16_1_3_5_7_11_13 (p0, p0, p0, p0, p0, p0, p0, p0,
+ p0, p0, p0, p0, p0, p0, p0, p0, 3, 0);
+
+ g16_1_3_5_7_11_13 (px, p0, px, p0, px, p0, px, p0, p0, p0, px, p0, p0, p0, p0, p0, 2, 1); /* { dg-warning "argument 13 null where non-null expected because arguments 17 and 18 are nonzero" } */
+ if (t > 122 && v > 18)
+ g16_1_3_5_7_11_13 (px, p0, px, p0, px, p0, px, p0, p0, p0, px, p0, p0, p0, p0, p0, t, v); /* { dg-warning "argument 13 null where non-null expected because arguments 17 and 18 are nonzero" } */
+}
--- /dev/null
+/* Test for the "nonnull" function attribute on builtins. Use the
+ "__builtin_" style below so we don't need prototypes. */
+/* { dg-do compile } */
+/* { dg-options "-Wnonnull" } */
+
+#include <stddef.h>
+
+void
+foo (void *p, char *s)
+{
+ __builtin_fwrite (s, 0, 0, NULL); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite (s, 0, 2, NULL); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite (s, 1, 0, NULL); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite (NULL, 16, 0, p);
+ __builtin_fwrite (NULL, 0, 12, p);
+ __builtin_fwrite (NULL, 2, 3, p); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite_unlocked (s, 0, 0, NULL); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite_unlocked (s, 0, 2, NULL); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite_unlocked (s, 1, 0, NULL); /* { dg-warning "null" "null pointer check" } */
+ __builtin_fwrite_unlocked (NULL, 16, 0, p);
+ __builtin_fwrite_unlocked (NULL, 0, 12, p);
+ __builtin_fwrite_unlocked (NULL, 2, 3, p); /* { dg-warning "null" "null pointer check" } */
+}
/* { dg-options "-std=gnu17 -pedantic-errors" } */
extern void func1 () __attribute__((nonnull_if_nonzero)); /* { dg-error "wrong number of arguments specified for 'nonnull_if_nonzero' attribute" } */
-/* { dg-message "expected 2, found 0" "" { target *-*-* } .-1 } */
+/* { dg-message "expected between 2 and 3, found 0" "" { target *-*-* } .-1 } */
extern void func2 (char *) __attribute__((nonnull_if_nonzero(1))); /* { dg-error "wrong number of arguments specified for 'nonnull_if_nonzero' attribute" } */
-/* { dg-message "expected 2, found 1" "" { target *-*-* } .-1 } */
+/* { dg-message "expected between 2 and 3, found 1" "" { target *-*-* } .-1 } */
-extern void func3 (char *) __attribute__((nonnull_if_nonzero(1, 2, 3))); /* { dg-error "wrong number of arguments specified for 'nonnull_if_nonzero' attribute" } */
-/* { dg-message "expected 2, found 3" "" { target *-*-* } .-1 } */
+extern void func3 (char *) __attribute__((nonnull_if_nonzero(1, 2, 3, 4))); /* { dg-error "wrong number of arguments specified for 'nonnull_if_nonzero' attribute" } */
+/* { dg-message "expected between 2 and 3, found 4" "" { target *-*-* } .-1 } */
extern void func4 (char *, int) __attribute__((nonnull_if_nonzero(3, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 1 value '3' exceeds the number of function parameters 2" } */
extern void func5 (char *, int) __attribute__((nonnull_if_nonzero(1, 3))); /* { dg-warning "nonnull_if_nonzero' attribute argument 2 value '3' exceeds the number of function parameters 2" } */
-extern void func6 (char *, int) __attribute__((nonnull_if_nonzero (foo, 2))); /* { dg-warning ".nonnull_if_nonzero. attribute argument 1 is invalid" } */
+extern void func6 (char *, int) __attribute__((nonnull_if_nonzero(1, 2, 3))); /* { dg-warning "nonnull_if_nonzero' attribute argument 3 value '3' exceeds the number of function parameters 2" } */
+
+extern void func7 (char *, int) __attribute__((nonnull_if_nonzero (foo, 2))); /* { dg-warning ".nonnull_if_nonzero. attribute argument 1 is invalid" } */
/* { dg-error ".foo. undeclared" "undeclared argument" { target *-*-* } .-1 } */
-extern void func7 (char *, int) __attribute__((nonnull_if_nonzero (1, bar))); /* { dg-warning ".nonnull_if_nonzero. attribute argument 2 is invalid" } */
+extern void func8 (char *, int) __attribute__((nonnull_if_nonzero (1, bar))); /* { dg-warning ".nonnull_if_nonzero. attribute argument 2 is invalid" } */
/* { dg-error ".bar. undeclared" "undeclared argument" { target *-*-* } .-1 } */
-extern void func8 (int, int) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 1 value '1' refers to parameter type 'int'" } */
+extern void func9 (char *, int) __attribute__((nonnull_if_nonzero (1, 2, baz))); /* { dg-warning ".nonnull_if_nonzero. attribute argument 3 is invalid" } */
+/* { dg-error ".baz. undeclared" "undeclared argument" { target *-*-* } .-1 } */
+
+extern void func10 (int, int) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 1 value '1' refers to parameter type 'int'" } */
+
+extern void func11 (char *, float) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 2 value '2' refers to parameter type 'float'" } */
+
+extern void func12 (char *, _Bool) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 2 value '2' refers to parameter type '_Bool'" } */
+
+extern void func13 (char *, char *) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 2 value '2' refers to parameter type 'char \\\*'" } */
-extern void func9 (char *, float) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 2 value '2' refers to parameter type 'float'" } */
+extern void func14 (char *, int, float) __attribute__((nonnull_if_nonzero(1, 2, 3))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 3 value '3' refers to parameter type 'float'" } */
-extern void func10 (char *, _Bool) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 2 value '2' refers to parameter type '_Bool'" } */
+extern void func15 (char *, long, _Bool) __attribute__((nonnull_if_nonzero(1, 2, 3))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 3 value '3' refers to parameter type '_Bool'" } */
-extern void func11 (char *, char *) __attribute__((nonnull_if_nonzero(1, 2))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 2 value '2' refers to parameter type 'char \\\*'" } */
+extern void func17 (char *, int, char *) __attribute__((nonnull_if_nonzero(1, 2, 3))); /* { dg-warning "'nonnull_if_nonzero' attribute argument 3 value '3' refers to parameter type 'char \\\*'" } */
void
foo (void)
bar (void)
{
}
+
+void
+baz (void)
+{
+}
unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < gimple_call_num_args (stmt)
- && idx2 < gimple_call_num_args (stmt))
+ && idx2 < gimple_call_num_args (stmt)
+ && idx3 < gimple_call_num_args (stmt))
{
tree arg = gimple_call_arg (stmt, idx);
tree arg2 = gimple_call_arg (stmt, idx2);
+ tree arg3 = gimple_call_arg (stmt, idx3);
if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE
|| !integer_zerop (arg)
|| !INTEGRAL_TYPE_P (TREE_TYPE (arg2))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (arg3))
|| integer_zerop (arg2)
+ || integer_zerop (arg3)
|| ((TREE_CODE (fntype) == METHOD_TYPE || closure)
- && (idx == 0 || idx2 == 0)))
+ && (idx == 0 || idx2 == 0 || idx3 == 0)))
continue;
if (!integer_nonzerop (arg2)
&& !tree_expr_nonzero_p (arg2))
if (range_includes_zero_p (vr))
continue;
}
+ if (idx2 != idx3
+ && !integer_nonzerop (arg3)
+ && !tree_expr_nonzero_p (arg3))
+ {
+ if (TREE_CODE (arg3) != SSA_NAME || optimize < 2)
+ continue;
+ if (!ranger)
+ ranger = enable_ranger (cfun);
+
+ int_range_max vr;
+ get_range_query (cfun)->range_of_expr (vr, arg3, stmt);
+ if (range_includes_zero_p (vr))
+ continue;
+ }
unsigned argno = idx + 1;
unsigned argno2 = idx2 + 1;
+ unsigned argno3 = idx3 + 1;
location_t loc = (EXPR_HAS_LOCATION (arg)
? EXPR_LOCATION (arg)
: gimple_location (stmt));
auto_diagnostic_group d;
- if (!warning_at (loc, OPT_Wnonnull,
- "argument %u null where non-null "
- "expected because argument %u is "
- "nonzero", argno, argno2))
+ if (idx2 != idx3)
+ {
+ if (!warning_at (loc, OPT_Wnonnull,
+ "argument %u null where non-null "
+ "expected because arguments %u and %u "
+ "are nonzero", argno, argno2, argno3))
+ continue;
+ }
+ else if (!warning_at (loc, OPT_Wnonnull,
+ "argument %u null where non-null "
+ "expected because argument %u is "
+ "nonzero", argno, argno2))
continue;
tree fndecl = gimple_call_fndecl (stmt);
for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
{
tree arg = gimple_call_arg (stmt, i);
- tree arg2;
+ tree arg2, arg3;
if (POINTER_TYPE_P (TREE_TYPE (arg))
- && infer_nonnull_range_by_attribute (stmt, arg, &arg2))
+ && infer_nonnull_range_by_attribute (stmt, arg, &arg2, &arg3))
{
gimple *g;
if (!is_gimple_val (arg))
gsi_safe_insert_before (gsi, g);
arg = gimple_assign_lhs (g);
}
+ if (arg2 == arg3)
+ arg3 = NULL_TREE;
if (arg2 && !is_gimple_val (arg2))
{
g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg2)), arg2);
gsi_safe_insert_before (gsi, g);
arg2 = gimple_assign_lhs (g);
}
+ if (arg3 && !is_gimple_val (arg3))
+ {
+ g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg3)), arg3);
+ gimple_set_location (g, loc[0]);
+ gsi_safe_insert_before (gsi, g);
+ arg3 = gimple_assign_lhs (g);
+ }
basic_block then_bb, fallthru_bb;
*gsi = create_cond_insert_point (gsi, true, false, true,
gimple_set_location (g, loc[0]);
gsi_insert_after (gsi, g, GSI_NEW_STMT);
+ *gsi = gsi_after_labels (then_bb);
+ }
+ if (arg3)
+ {
+ *gsi = create_cond_insert_point (gsi, true, false, true,
+ &then_bb, &fallthru_bb);
+ g = gimple_build_cond (NE_EXPR, arg3,
+ build_zero_cst (TREE_TYPE (arg3)),
+ NULL_TREE, NULL_TREE);
+ gimple_set_location (g, loc[0]);
+ gsi_insert_after (gsi, g, GSI_NEW_STMT);
+
*gsi = gsi_after_labels (then_bb);
}
if (flag_sanitize_trap & SANITIZE_NONNULL_ATTRIBUTE)