Commit 54aa6b58 by Martin Sebor Committed by Martin Sebor

PR middle-end/83859 - attributes to associate pointer arguments and sizes

gcc/ChangeLog:

	PR middle-end/83859
	* attribs.h (struct attr_access): New.
	* attribs.c (decl_attributes): Add an informational note.
	* builtins.c (check_access): Make extern.  Consistently set no-warning
	after issuing a warning.  Handle calls through function pointers.  Set
	no-warning.
	* builtins.h (check_access): Declare.
	* calls.c (rdwr_access_hash): New type.
	(rdwr_map): Same.
	(init_attr_rdwr_indices): New function.
	(maybe_warn_rdwr_sizes): Same.
	(initialize_argument_information): Call init_attr_rdwr_indices.
	Call maybe_warn_rdwr_sizes.
	(get_size_range): Avoid null argument.
	* doc/extend.texi (attribute access): Document new attribute.

gcc/c-family/ChangeLog:

	PR middle-end/83859
	* c-attribs.c (handle_access_attribute): New function.
	(c_common_attribute_table): Add new attribute.
	(get_argument_type): New function.
	(append_access_attrs): New function.
	(get_nonnull_operand): Rename...
	(get_attribute_operand): ...to this.
	* c-common.c (get_nonnull_operand): Rename...
	(get_attribute_operand): ...to this.

gcc/testsuite/ChangeLog:

	PR middle-end/83859
	* c-c++-common/attr-nonstring-8.c: Adjust text of expected warning.
	* gcc.dg/Wstringop-overflow-23.c: New test.
	* gcc.dg/Wstringop-overflow-24.c: New test.
	* gcc.dg/attr-access-read-only.c: New test.
	* gcc.dg/attr-access-read-write.c: New test.
	* gcc.dg/attr-access-read-write-2.c: New test.
	* gcc.dg/attr-access-write-only.c: New test.

From-SVN: r278624
parent b5338fb3
2019-11-22 Martin Sebor <msebor@redhat.com>
PR middle-end/83859
* attribs.h (struct attr_access): New.
* attribs.c (decl_attributes): Add an informational note.
* builtins.c (check_access): Make extern. Consistently set no-warning
after issuing a warning. Handle calls through function pointers. Set
no-warning.
* builtins.h (check_access): Declare.
* calls.c (rdwr_access_hash): New type.
(rdwr_map): Same.
(init_attr_rdwr_indices): New function.
(maybe_warn_rdwr_sizes): Same.
(initialize_argument_information): Call init_attr_rdwr_indices.
Call maybe_warn_rdwr_sizes.
(get_size_range): Avoid null argument.
* doc/extend.texi (attribute access): Document new attribute.
2019-11-22 Andrew Stubbs <ams@codesourcery.com>
* config/gcn/gcn.c (OMP_LDS_SIZE): Define.
......@@ -573,13 +573,23 @@ decl_attributes (tree *node, tree attributes, int flags,
}
continue;
}
else if (list_length (args) < spec->min_length
|| (spec->max_length >= 0
&& list_length (args) > spec->max_length))
else
{
error ("wrong number of arguments specified for %qE attribute",
name);
continue;
int nargs = list_length (args);
if (nargs < spec->min_length
|| (spec->max_length >= 0
&& nargs > spec->max_length))
{
error ("wrong number of arguments specified for %qE attribute",
name);
if (spec->max_length < 0)
inform (input_location, "expected %i or more, found %i",
spec->min_length, nargs);
else
inform (input_location, "expected between %i and %i, found %i",
spec->min_length, spec->max_length, nargs);
continue;
}
}
gcc_assert (is_attribute_p (spec->name, name));
......
......@@ -218,4 +218,24 @@ lookup_attribute_by_prefix (const char *attr_name, tree list)
}
}
/* Description of a function argument declared with attribute access.
Used as an "iterator" over all such arguments in a function declaration
or call. */
struct attr_access
{
/* The attribute pointer argument. */
tree ptr;
/* The size of the pointed-to object or NULL when not specified. */
tree size;
/* The zero-based number of each of the formal function arguments. */
unsigned ptrarg;
unsigned sizarg;
/* The access mode. */
enum access_mode { read_only, write_only, read_write };
access_mode mode;
};
#endif // GCC_ATTRIBS_H
......@@ -3340,7 +3340,7 @@ determine_block_size (tree len, rtx len_rtx,
If the call is successfully verified as safe return true, otherwise
return false. */
static bool
bool
check_access (tree exp, tree, tree, tree dstwrite,
tree maxread, tree srcstr, tree dstsize)
{
......@@ -3436,16 +3436,26 @@ check_access (tree exp, tree, tree, tree dstwrite,
bool warned;
if (range[0] == range[1])
warned = warning_at (loc, opt,
"%K%qD specified size %E "
"exceeds maximum object size %E",
exp, func, range[0], maxobjsize);
warned = (func
? warning_at (loc, opt,
"%K%qD specified size %E "
"exceeds maximum object size %E",
exp, func, range[0], maxobjsize)
: warning_at (loc, opt,
"%Kspecified size %E "
"exceeds maximum object size %E",
exp, range[0], maxobjsize));
else
warned = warning_at (loc, opt,
"%K%qD specified size between %E and %E "
"exceeds maximum object size %E",
exp, func,
range[0], range[1], maxobjsize);
warned = (func
? warning_at (loc, opt,
"%K%qD specified size between %E and %E "
"exceeds maximum object size %E",
exp, func,
range[0], range[1], maxobjsize)
: warning_at (loc, opt,
"%Kspecified size between %E and %E "
"exceeds maximum object size %E",
exp, range[0], range[1], maxobjsize));
if (warned)
TREE_NO_WARNING (exp) = true;
......@@ -3474,37 +3484,69 @@ check_access (tree exp, tree, tree, tree dstwrite,
location_t loc = tree_nonartificial_location (exp);
loc = expansion_point_location_if_in_system_header (loc);
bool warned = false;
if (dstwrite == slen && at_least_one)
{
/* This is a call to strcpy with a destination of 0 size
and a source of unknown length. The call will write
at least one byte past the end of the destination. */
warning_at (loc, opt,
"%K%qD writing %E or more bytes into a region "
"of size %E overflows the destination",
exp, func, range[0], dstsize);
warned = (func
? warning_at (loc, opt,
"%K%qD writing %E or more bytes into "
"a region of size %E overflows "
"the destination",
exp, func, range[0], dstsize)
: warning_at (loc, opt,
"%Kwriting %E or more bytes into "
"a region of size %E overflows "
"the destination",
exp, range[0], dstsize));
}
else if (tree_int_cst_equal (range[0], range[1]))
warning_n (loc, opt, tree_to_uhwi (range[0]),
"%K%qD writing %E byte into a region "
"of size %E overflows the destination",
"%K%qD writing %E bytes into a region "
"of size %E overflows the destination",
exp, func, range[0], dstsize);
warned = (func
? warning_n (loc, opt, tree_to_uhwi (range[0]),
"%K%qD writing %E byte into a region "
"of size %E overflows the destination",
"%K%qD writing %E bytes into a region "
"of size %E overflows the destination",
exp, func, range[0], dstsize)
: warning_n (loc, opt, tree_to_uhwi (range[0]),
"%Kwriting %E byte into a region "
"of size %E overflows the destination",
"%Kwriting %E bytes into a region "
"of size %E overflows the destination",
exp, range[0], dstsize));
else if (tree_int_cst_sign_bit (range[1]))
{
/* Avoid printing the upper bound if it's invalid. */
warning_at (loc, opt,
"%K%qD writing %E or more bytes into a region "
"of size %E overflows the destination",
exp, func, range[0], dstsize);
warned = (func
? warning_at (loc, opt,
"%K%qD writing %E or more bytes into "
"a region of size %E overflows "
"the destination",
exp, func, range[0], dstsize)
: warning_at (loc, opt,
"%Kwriting %E or more bytes into "
"a region of size %E overflows "
"the destination",
exp, range[0], dstsize));
}
else
warning_at (loc, opt,
"%K%qD writing between %E and %E bytes into "
"a region of size %E overflows the destination",
exp, func, range[0], range[1],
dstsize);
warned = (func
? warning_at (loc, opt,
"%K%qD writing between %E and %E bytes "
"into a region of size %E overflows "
"the destination",
exp, func, range[0], range[1],
dstsize)
: warning_at (loc, opt,
"%Kwriting between %E and %E bytes "
"into a region of size %E overflows "
"the destination",
exp, range[0], range[1],
dstsize));
if (warned)
TREE_NO_WARNING (exp) = true;
/* Return error when an overflow has been detected. */
return false;
......@@ -3527,21 +3569,36 @@ check_access (tree exp, tree, tree, tree dstwrite,
if (TREE_NO_WARNING (exp))
return false;
bool warned = false;
/* Warn about crazy big sizes first since that's more
likely to be meaningful than saying that the bound
is greater than the object size if both are big. */
if (range[0] == range[1])
warning_at (loc, opt,
"%K%qD specified bound %E "
"exceeds maximum object size %E",
exp, func,
range[0], maxobjsize);
warned = (func
? warning_at (loc, opt,
"%K%qD specified bound %E "
"exceeds maximum object size %E",
exp, func, range[0], maxobjsize)
: warning_at (loc, opt,
"%Kspecified bound %E "
"exceeds maximum object size %E",
exp, range[0], maxobjsize));
else
warning_at (loc, opt,
"%K%qD specified bound between %E and %E "
"exceeds maximum object size %E",
exp, func,
range[0], range[1], maxobjsize);
warned = (func
? warning_at (loc, opt,
"%K%qD specified bound between "
"%E and %E exceeds maximum object "
"size %E",
exp, func,
range[0], range[1], maxobjsize)
: warning_at (loc, opt,
"%Kspecified bound between "
"%E and %E exceeds maximum object "
"size %E",
exp, range[0], range[1], maxobjsize));
if (warned)
TREE_NO_WARNING (exp) = true;
return false;
}
......@@ -3551,18 +3608,34 @@ check_access (tree exp, tree, tree, tree dstwrite,
if (TREE_NO_WARNING (exp))
return false;
bool warned = false;
if (tree_int_cst_equal (range[0], range[1]))
warning_at (loc, opt,
"%K%qD specified bound %E "
"exceeds destination size %E",
exp, func,
range[0], dstsize);
warned = (func
? warning_at (loc, opt,
"%K%qD specified bound %E "
"exceeds destination size %E",
exp, func,
range[0], dstsize)
: warning_at (loc, opt,
"%Kspecified bound %E "
"exceeds destination size %E",
exp, range[0], dstsize));
else
warning_at (loc, opt,
"%K%qD specified bound between %E and %E "
"exceeds destination size %E",
exp, func,
range[0], range[1], dstsize);
warned = (func
? warning_at (loc, opt,
"%K%qD specified bound between %E "
"and %E exceeds destination size %E",
exp, func,
range[0], range[1], dstsize)
: warning_at (loc, opt,
"%Kspecified bound between %E "
"and %E exceeds destination size %E",
exp,
range[0], range[1], dstsize));
if (warned)
TREE_NO_WARNING (exp) = true;
return false;
}
}
......@@ -3577,26 +3650,46 @@ check_access (tree exp, tree, tree, tree dstwrite,
if (TREE_NO_WARNING (exp))
return false;
bool warned = false;
location_t loc = tree_nonartificial_location (exp);
loc = expansion_point_location_if_in_system_header (loc);
if (tree_int_cst_equal (range[0], range[1]))
warning_n (loc, opt, tree_to_uhwi (range[0]),
"%K%qD reading %E byte from a region of size %E",
"%K%qD reading %E bytes from a region of size %E",
exp, func, range[0], slen);
warned = (func
? warning_n (loc, opt, tree_to_uhwi (range[0]),
"%K%qD reading %E byte from a region of size %E",
"%K%qD reading %E bytes from a region of size %E",
exp, func, range[0], slen)
: warning_n (loc, opt, tree_to_uhwi (range[0]),
"%Kreading %E byte from a region of size %E",
"%Kreading %E bytes from a region of size %E",
exp, range[0], slen));
else if (tree_int_cst_sign_bit (range[1]))
{
/* Avoid printing the upper bound if it's invalid. */
warning_at (loc, opt,
"%K%qD reading %E or more bytes from a region "
"of size %E",
exp, func, range[0], slen);
warned = (func
? warning_at (loc, opt,
"%K%qD reading %E or more bytes from a region "
"of size %E",
exp, func, range[0], slen)
: warning_at (loc, opt,
"%Kreading %E or more bytes from a region "
"of size %E",
exp, range[0], slen));
}
else
warning_at (loc, opt,
"%K%qD reading between %E and %E bytes from a region "
"of size %E",
exp, func, range[0], range[1], slen);
warned = (func
? warning_at (loc, opt,
"%K%qD reading between %E and %E bytes from "
"a region of size %E",
exp, func, range[0], range[1], slen)
: warning_at (loc, opt,
"%Kreading between %E and %E bytes from "
"a region of size %E",
exp, range[0], range[1], slen));
if (warned)
TREE_NO_WARNING (exp) = true;
return false;
}
......
......@@ -151,5 +151,7 @@ bool check_nul_terminated_array (tree, tree, tree = NULL_TREE);
extern void warn_string_no_nul (location_t, const char *, tree, tree);
extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
extern bool builtin_with_linkage_p (tree);
extern bool check_access (tree, tree, tree, tree, tree, tree, tree);
#endif /* GCC_BUILTINS_H */
2019-11-22 Martin Sebor <msebor@redhat.com>
PR middle-end/83859
* c-attribs.c (handle_access_attribute): New function.
(c_common_attribute_table): Add new attribute.
(get_argument_type): New function.
(append_access_attrs): New function.
(get_nonnull_operand): Rename...
(get_attribute_operand): ...to this.
* c-common.c (get_nonnull_operand): Rename...
(get_attribute_operand): ...to this.
2019-11-21 Joseph Myers <joseph@codesourcery.com>
* c-attribs.c (handle_fallthrough_attribute): Use pedwarn instead
......
......@@ -5483,7 +5483,7 @@ nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num)
for (; args; args = TREE_CHAIN (args))
{
bool found = get_nonnull_operand (TREE_VALUE (args), &arg_num);
bool found = get_attribute_operand (TREE_VALUE (args), &arg_num);
gcc_assert (found);
......@@ -5518,11 +5518,11 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
}
}
/* Helper for nonnull attribute handling; fetch the operand number
from the attribute argument list. */
/* Helper for attribute handling; fetch the operand number from
the attribute argument list. */
bool
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
get_attribute_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
{
/* Verify the arg number is a small constant. */
if (tree_fits_uhwi_p (arg_num_expr))
......
......@@ -880,7 +880,7 @@ extern bool pointer_to_zero_sized_aggr_p (tree);
extern bool bool_promoted_to_int_p (tree);
extern tree fold_for_warn (tree);
extern tree c_common_get_narrower (tree, int *);
extern bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
extern bool get_attribute_operand (tree, unsigned HOST_WIDE_INT *);
#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, false, 1)
#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1)
......
......@@ -2484,6 +2484,77 @@ The following attributes are supported on most targets.
@table @code
@c Keep this table alphabetized by attribute name. Treat _ as space.
@item access
@itemx access (@var{access-mode}, @var{ref-index})
@itemx access (@var{access-mode}, @var{ref-index}, @var{size-index})
The @code{access} attribute enables the detection of invalid or unsafe
accesses by functions to which they apply to or their callers, as well
as wite-only accesses to objects that are never read from. Such accesses
may be diagnosed by warnings such as @option{-Wstringop-overflow},
@option{-Wunnitialized}, @option{-Wunused}, and others.
The @code{access} attribute specifies that a function to whose by-reference
arguments the attribute applies accesses the referenced object according to
@var{access-mode}. The @var{access-mode} argument is required and must be
one of three names: @code{read_only}, @code{read_write}, or @code{write_only}.
The remaining two are positional arguments.
The required @var{ref-index} positional argument denotes a function
argument of pointer (or in C++, refeference) type that is subject to
the access. The same pointer argument can be referenced by at most one
distinct @code{access} attribute.
The optional @var{size-index} positional argument denotes a function
argument of integer type that specifies the maximum size of the access.
The size is the number of elements of the type refefenced by @var{ref-index},
or the number of bytes when the pointer type is @code{void*}. When no
@var{size-index} argument is specified, the pointer argument must be either
null or point to a space that is suitably aligned and large for at least one
object of the referenced type (this implies that a past-the-end pointer is
not a valid argument). The actual size of the access may be less but it
must not be more.
The @code{read_only} access mode specifies that the pointer to which it
applies is used to read the referenced object but not write to it. Unless
the argument specifying the size of the access denoted by @var{size-index}
is zero, the referenced object must be initialized. The mode implies
a stronger guarantee than the @code{const} qualifier which, when cast away
from a pointer, does not prevent a function from modifying the pointed-to
object. Examples of the use of the @code{read_only} access mode is
the argument to the @code{puts} function, or the second and third arguments
to the @code{memcpy} function.
@smallexample
__attribute__ ((access (read_only))) int puts (const char*);
__attribute__ ((access (read_only, 1, 2))) void* memcpy (void*, const void*, size_t);
@end smallexample
The @code{read_write} access mode applies to arguments of pointer types
without the @code{const} qualifier. It specifies that the pointer to which
it applies is used to both read and write the referenced object. Unless
the argument specifying the size of the access denoted by @var{size-index}
is zero, the object refrenced by the pointer must be initialized. An example
of the use of the @code{read_write} access mode is the first argument to
the @code{strcat} function.
@smallexample
__attribute__ ((access (read_write, 1), access (read_only, 2))) char* strcat (char*, const char*);
@end smallexample
The @code{write_only} access mode applies to arguments of pointer types
without the @code{const} qualifier. It specifies that the pointer to which
it applies is used to write to the referenced object but not read from it.
The object refrenced by the pointer need not be initialized. An example
of the use of the @code{write_only} access mode is the first argument to
the @code{strcpy} function, or the first two arguments to the @code{fgets}
function.
@smallexample
__attribute__ ((access (write_only, 1), access (read_only, 2))) char* strcpy (char*, const char*);
__attribute__ ((access (write_only, 1, 2), access (read_write, 3))) int fgets (char*, int, FILE*);
@end smallexample
@item alias ("@var{target}")
@cindex @code{alias} function attribute
The @code{alias} attribute causes the declaration to be emitted as an
......@@ -3849,7 +3920,6 @@ performing a link with relocatable output (ie: @code{ld -r}) on them.
At present, a declaration to which @code{weakref} is attached can
only be @code{static}.
@end table
@c This is the end of the target-independent attribute table
......
2019-11-22 Martin Sebor <msebor@redhat.com>
PR middle-end/83859
* c-c++-common/attr-nonstring-8.c: Adjust text of expected warning.
* gcc.dg/Wstringop-overflow-23.c: New test.
* gcc.dg/Wstringop-overflow-24.c: New test.
* gcc.dg/attr-access-read-only.c: New test.
* gcc.dg/attr-access-read-write.c: New test.
* gcc.dg/attr-access-read-write-2.c: New test.
* gcc.dg/attr-access-write-only.c: New test.
2019-11-22 Martin Sebor <msebor@redhat.com>
PR middle-end/88226
* gcc.dg/Wstringop-overflow-22.c: New test.
* gcc.dg/tree-ssa/builtin-fprintf-warn-1.c: Remove xfails.
......
......@@ -57,8 +57,8 @@ void test_strncat_nonstring_cst (char *d)
T (strncat (nd3, ns3, 1));
T (strncat (nd3, ns3, 2));
T (strncat (nd3, ns3, 3)); /* { dg-warning "specified bound 3 equals destination size" } */
T (strncat (nd3, ns3, 4)); /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */
/* { dg-warning "specified bound 4 exceeds destination size 3" "" { target *-*-* } .-1 } */
/* Either of the two warnings below is fine. */
T (strncat (nd3, ns3, 4)); /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4|specified bound 4 exceeds destination size 3" } */
T (strncat (d, pns, sizeof pns)); /* { dg-warning "argument to .sizeof. in .\[^\n\r\]*strncat\[^\n\r\]*. call is the same expression as the source" } */
}
......
/* PR middle-end/83859 - attribute to establish relation between parameters
for buffer and its size
Test to verify that with optimization enabled, -Wstringop-overflow
warnings are issued for calls to user-defined functions with attribute
access and with non-constant out-of-bounds arguments.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#include "range.h"
#define INT_MAX __INT_MAX__
#define INT_MIN (-INT_MAX - 1)
#define RDONLY(...) __attribute__ ((access (read_only, __VA_ARGS__)))
#define WRONLY(...) __attribute__ ((access (write_only, __VA_ARGS__)))
#define RDWR(...) __attribute__ ((access (read_write, __VA_ARGS__)))
typedef __INT32_TYPE__ int32_t;
/* Exercise null pointer detection. */
RDONLY (2, 1) void
rd2_1 (int, const void*); // { dg-message "in a call to function 'rd2_1' declared with attribute 'read_only \\\(2, 1\\\)" }
void test_rd2_1 (void)
{
{
void *null = 0;
void *p = &null;
rd2_1 (0, null);
rd2_1 (1, p);
}
{
void *null = 0;
rd2_1 (1, null); // { dg-warning "argument 2 is null but the corresponding size argument 1 value is 1" }
}
{
void *null = 0;
rd2_1 (SR (1, 2), null); // { dg-warning "argument 2 is null but the corresponding size argument 1 range is \\\[1, 2]" }
}
}
WRONLY (3, 1) void
wr3_1 (int, int, void*); // { dg-message "in a call to function 'wr3_1' declared with attribute 'write_only \\\(3, 1\\\)" }
void test_wr3_1 (void)
{
{
void *null = 0;
void *p = &null;
wr3_1 (SR (0, 1), 0, null);
wr3_1 (SR (1, 1), 0, p);
}
void *null = 0;
wr3_1 (SR (1, 2), 1, null); // { dg-warning "argument 3 is null but the corresponding size argument 1 range is \\\[1, 2]" }
}
WRONLY (2, 1) void
wr2_1 (int, void*);
void test_wrd2_1 (int n)
{
wr2_1 (0, 0);
wr2_1 (SR (-1, 1), 0);
wr2_1 (SR (0, 1), 0);
wr2_1 (SR (1, 2), 0); // { dg-warning "argument 2 is null but the corresponding size argument 1 range is \\\[1, 2]" }
/* This should probably be diagnosed but to avoid false positives
caused by jump threading and such it would have to be done
earlier than it is now. */
wr2_1 (n, 0); // { dg-warning "argument 2 is null" "unimplemented" { xfail *-*-* } }
}
/* Exercise pointer to an incomplete type other than void. */
struct Incomplete;
extern struct Incomplete inc;
extern char ax[];
WRONLY (1, 2) void
wr1_2_inc (struct Incomplete*, unsigned);
void test_wr1_2_inc (struct Incomplete *pinc, unsigned n)
{
wr1_2_inc (0, 0);
wr1_2_inc (0, 1); // { dg-warning "argument 1 is null but the corresponding size argument 2 value is 1" }
wr1_2_inc (pinc, 1);
wr1_2_inc (&inc, 1);
wr1_2_inc (pinc, 123);
wr1_2_inc (&inc, 456);
char a3[3];
pinc = (struct Incomplete*)a3;
wr1_2_inc (pinc, SR (3, 4));
wr1_2_inc (pinc, SR (4, 5));
// { dg-warning "'wr1_2_inc' writing between 4 and 5 bytes into a region of size 3" "small buffer cast to incomplete" { target *-*-* } .-1 }
pinc = (struct Incomplete*)ax;
wr1_2_inc (pinc, SR (123, 456));
char vla[n];
pinc = (struct Incomplete*)vla;
wr1_2_inc (pinc, SR (345, 456));
}
RDONLY (1, 3) WRONLY (2, 4) void
rd1_3_wr2_4 (const void*, void*, int, int);
void test_rd1_3_wr2_4 (const void *s, void *d, int n1, int n2)
{
rd1_3_wr2_4 (s, d, 1, 2);
rd1_3_wr2_4 (s, d, 123, 456);
rd1_3_wr2_4 (s, d, INT_MAX, INT_MAX);
rd1_3_wr2_4 (s, d, -1, 2); // { dg-warning "argument 3 value -1 is negative" }
const int ir_min_m1 = SR (INT_MIN, -1);
rd1_3_wr2_4 (s, d, ir_min_m1, 2); // { dg-warning "argument 3 range \\\[-\[0-9\]+, -1] is negative" }
rd1_3_wr2_4 (s, d, SR (-1, 0), 2);
rd1_3_wr2_4 (s, d, SR (INT_MIN, INT_MAX), 2);
rd1_3_wr2_4 (s, d, n1, n2);
const char s11[11] = "0123456789";
rd1_3_wr2_4 (s11, d, 11, n2);
rd1_3_wr2_4 (s11, d, 12, n2); // { dg-warning "'rd1_3_wr2_4' reading 12 bytes from a region of size 11" }
rd1_3_wr2_4 (s11, d, SR (0, 11), n2);
rd1_3_wr2_4 (s11, d, SR (0, 12), n2);
rd1_3_wr2_4 (s11, d, SR (11, 12), n2);
rd1_3_wr2_4 (s11, d, SR (11, INT_MAX), n2);
rd1_3_wr2_4 (s11, d, SR (12, 13), n2); // { dg-warning "'rd1_3_wr2_4' reading between 12 and 13 bytes from a region of size 11" }
char d4[4];
rd1_3_wr2_4 (s, d4, n1, 4);
rd1_3_wr2_4 (s, d4, n1, 5); // { dg-warning "'rd1_3_wr2_4' writing 5 bytes into a region of size 4" }
rd1_3_wr2_4 (s11, d4, SR (12, 13), SR (5, 6));
// { dg-warning "'rd1_3_wr2_4' reading between 12 and 13 bytes from a region of size 11" "read" { target *-*-* } .-1 }
// { dg-warning "'rd1_3_wr2_4' writing between 5 and 6 bytes into a region of size 4" "read" { target *-*-* } .-2 }
}
/* Verify that function pointers are handled. */
RDONLY (1) void (*pfrd1)(const void*, const void*);
void test_pfrd1 (void)
{
pfrd1 ("" + SR (0, 9), "" + SR (1, 9));
pfrd1 ("" + SR (1, 2), ""); // { dg-warning "reading 1 byte from a region of size 0" }
}
WRONLY (4, 3) void (*pfwr4_3)(int, const char*, int, int*);
void test_pfwr4_3 (void)
{
int32_t i;
pfwr4_3 (3, "", 0, &i + SR (0, 9));
pfwr4_3 (5, "", 1, &i + SR (1, 2)); // { dg-warning "writing 4 bytes into a region of size 0" }
}
/* PR middle-end/83859 - attribute to establish relation between parameters
for buffer and its size
Test to verify that -Wstringop-overflow warnings are issued even with
no optimization for calls to user-defined functions with attribute
access and with constant out-of-bounds arguments.
{ dg-do compile }
{ dg-options "-O0 -Wall" } */
#define INT_MAX __INT_MAX__
#define INT_MIN (-INT_MAX - 1)
#define rdonly __attribute__ ((access (read_only)))
#define RDONLY(...) __attribute__ ((access (read_only, __VA_ARGS__)))
#define WRONLY(...) __attribute__ ((access (write_only, __VA_ARGS__)))
#define RDWR(...) __attribute__ ((access (read_write, __VA_ARGS__)))
typedef __INT32_TYPE__ int32_t;
extern const char s1[1], s2[2], s3[3];
extern char d1[1], d2[2], d3[3];
/* Exercise that null pointers are allowed in functions declared with
the attribute without a size operand. */
RDONLY (1) void
rd1_int (const int*); // { dg-message "in a call to function 'rd1_int' declared with attribute 'read_only \\\(1\\\)'" }
void test_rd1_int (void)
{
rd1_int (0);
int32_t i = 0;
rd1_int (&i);
rd1_int ((int32_t*)s1); // { dg-warning "reading 4 bytes from a region of size 1" }
}
/* Exercise null pointer detection in functions declared with
the attribute and with non-zero size. */
RDONLY (2, 1) void
rd2_1 (int, const void*); // { dg-message "in a call to function 'rd2_1' declared with attribute 'read_only \\\(2, 1\\\)" }
void test_rd2_1 (void)
{
rd2_1 (0, 0);
rd2_1 (1, "");
rd2_1 (1, 0); // { dg-warning "argument 2 is null but the corresponding size argument 1 value is 1" }
}
WRONLY (3, 1) void
wr3_1 (int, int, void*); // { dg-message "in a call to function 'wr3_1' declared with attribute 'write_only \\\(3, 1\\\)" }
void test_wr3_1 (void)
{
wr3_1 (0, 0, 0);
wr3_1 (1, 0, d1);
wr3_1 (2, 1, 0); // { dg-warning "argument 3 is null but the corresponding size argument 1 value is 2" }
}
/* Exercise pointer to an incomplete type other than void. */
struct Incomplete;
extern struct Incomplete inc;
RDONLY (1) void
rd_inc (const struct Incomplete*);
void test_rd_inc (const struct Incomplete *pinc)
{
rd_inc (0);
rd_inc (pinc);
rd_inc ((const struct Incomplete*)s1);
rd_inc ((const struct Incomplete*)&s1[1]);
// { dg-warning "'rd_inc' reading 1 byte from a region of size 0" "past-the-end pointer" { target *-*-* } .-1 }
}
RDONLY (1, 2) void
rd1_2_inc (const struct Incomplete*, unsigned);
void test_rd1_2_inc (const struct Incomplete *pinc)
{
rd1_2_inc (0, 0);
rd1_2_inc (0, 1); // { dg-warning "argument 1 is null but the corresponding size argument 2 value is 1" }
rd1_2_inc (pinc, 1);
rd1_2_inc (&inc, 1);
rd1_2_inc (pinc, 123);
rd1_2_inc (&inc, 456);
rd1_2_inc ((const struct Incomplete*)s3, 4);
// { dg-warning "'rd1_2_inc' reading 4 bytes from a region of size 3" "small buffer cast to incomplete" { target *-*-* } .-1 }
}
/* Verify the handling of two attributes sharing the same size operand . */
RDONLY (1, 3) WRONLY (2, 3) void
rd1_3_wr2_3 (const void*, void*, int);
void test_rd1_3_wr2_3 (void)
{
rd1_3_wr2_3 (s1, d1, 0);
rd1_3_wr2_3 (s1, d1, 1);
rd1_3_wr2_3 (s1, d1, 2);
// { dg-warning "'rd1_3_wr2_3' reading 2 bytes from a region of size 1" "read" { target *-*-* } .-1 }
// { dg-warning "'rd1_3_wr2_3' writing 2 bytes into a region of size 1" "write" { target *-*-* } .-2 }
rd1_3_wr2_3 (s1, d2, 2);
// { dg-warning "'rd1_3_wr2_3' reading 2 bytes from a region of size 1" "read" { target *-*-* } .-1 }
rd1_3_wr2_3 (s2, d1, 2);
// { dg-warning "'rd1_3_wr2_3' writing 2 bytes into a region of size 1" "write" { target *-*-* } .-1 }
}
/* Verify the handling of multiple attributes of the same kind with
out-of-order operands. */
RDONLY (1, 6) RDONLY (2, 5) RDONLY (3, 4) void
rd1_6_2_5_3_4 (const void *s1, const void *s2, const void *s3,
int n3, int n2, int n1);
void test_rd1_6_2_5_3_4 (void)
{
rd1_6_2_5_3_4 (s1, s2, s3, 4, 2, 1); // { dg-warning "reading 4 bytes from a region of size 3" }
rd1_6_2_5_3_4 (s1, s2, s3, 3, 5, 1); // { dg-warning "reading 5 bytes from a region of size 2" }
rd1_6_2_5_3_4 (s1, s2, s3, 3, 2, 6); // { dg-warning "reading 6 bytes from a region of size 1" }
}
/* Verify the handling of multiple attributes of different kinds with
out-of-order operands. */
RDONLY (1, 6) WRONLY (2, 5) RDONLY (3, 4) void
rd1_6_wr2_5_rd3_4 (const void *s1, void *d2, const void *s3,
int n3, int n2, int n1);
void test_rd1_6_wr2_5_rd3_4 (void)
{
rd1_6_wr2_5_rd3_4 (s1, d2, s3, 7, 2, 1); // { dg-warning "reading 7 bytes from a region of size 3" }
rd1_6_wr2_5_rd3_4 (s1, d2, s3, 3, 8, 1); // { dg-warning "writing 8 bytes into a region of size 2" }
rd1_6_wr2_5_rd3_4 (s1, d2, s3, 3, 2, 9); // { dg-warning "reading 9 bytes from a region of size 1" }
}
RDONLY (6, 1) WRONLY (5, 2) RDWR (4, 3) void
rd6_1_wr5_2_rd4_3 (int n1, int n2, int n3,
void *d3, void *d2, const void *s1);
void test_rd6_1_wr5_2_rd4_3 (void)
{
rd6_1_wr5_2_rd4_3 (7, 2, 1, d1, d2, s3); // { dg-warning "reading 7 bytes from a region of size 3" }
rd6_1_wr5_2_rd4_3 (3, 8, 1, d1, d2, s3); // { dg-warning "writing 8 bytes into a region of size 2" }
rd6_1_wr5_2_rd4_3 (3, 2, 9, d1, d2, s3); // { dg-warning "writing 9 bytes into a region of size 1" }
}
RDONLY (1, 3) WRONLY (2, 4) void
rd1_3_wr2_4 (const void*, void*, int, int);
void test_rd1_3_wr2_4 (const void *s, void *d, int n1, int n2)
{
rd1_3_wr2_4 (s, d, 1, 2);
rd1_3_wr2_4 (s, d, 123, 456);
rd1_3_wr2_4 (s, d, INT_MAX, INT_MAX);
rd1_3_wr2_4 (s, d, -1, 2); // { dg-warning "argument 3 value -1 is negative" }
const char s11[11] = "0123456789";
rd1_3_wr2_4 (s11, d, 11, n2);
rd1_3_wr2_4 (s11, d, 12, n2); // { dg-warning "'rd1_3_wr2_4' reading 12 bytes from a region of size 11" }
}
/* Verify that function pointers are handled. */
RDONLY (1) void (*pfrd1)(const void*, const void*);
void test_pfrd1 (void)
{
pfrd1 (0, 0);
pfrd1 ("", "");
pfrd1 ("", "" + 1);
pfrd1 ("" + 1, ""); // { dg-warning "reading 1 byte from a region of size 0" }
}
WRONLY (4, 3) void (*pfwr4_3)(int, const char*, int, int*);
void test_pfwr4_3 (void)
{
pfwr4_3 (0, 0, 0, 0);
int32_t i;
pfwr4_3 (3, "", 0, &i + 1);
pfwr4_3 (5, "", 1, &i + 1); // { dg-warning "writing 4 bytes into a region of size 0" }
}
/* PR middle-end/83859 - attribute to establish relation between parameters
for buffer and its size
Test to verify the handling of attribute access (read_only) syntax.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" } */
int __attribute__ ((access))
access_v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" }
int __attribute__ ((access ()))
access___v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" }
int __attribute__ ((access (rdonly)))
rdonly_spelling (void); // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', or 'write_only'" }
int __attribute__ ((access (read_only)))
rdonly_v_all (void); // { dg-error "attribute .access\\(read_only\\). missing an argument" }
int __attribute__ ((access (read_only ())))
rdonly___v_all (void); // { dg-error "attribute 'access' unexpected '\\(' after mode 'read_only'; expected a positional argument or '\\)'" }
// { dg-warning "implicit declaration of function 'read_only'" "" { target *-*-* } .-2 }
int rdonly (void);
int __attribute__ ((access (rdonly ())))
rdonly___v_all (void); // { dg-error "attribute 'access' invalid mode 'rdonly'" }
int __attribute__ ((access (read_only)))
rdonly_i_all (int); // { dg-error "attribute .access\\(read_only\\). missing an argument" }
#define rdonly __attribute__ ((access (read_only)))
#define RDONLY(...) __attribute__ ((access (read_only, __VA_ARGS__)))
int RDONLY (1)
rdonly_pcv_1 (const void*);
int RDONLY (2)
rdonly_i_pcv_2 (int, const void*);
int RDONLY (3)
rdonly_i_i_pcv_3 (int, int, const void*);
int RDONLY (0 + 1)
rdonly_pcv_0p1 (const void*);
int RDONLY (2 - 1)
rdonly_pcv_2m1 (const void*);
int RDONLY (1, 1)
rdonly_pv_pi_1_1 (const void*, const int*); // { dg-error "attribute 'access\\(read_only, 1, 1\\)' positional argument 2 references non-integer argument type 'const void \\*'" }
int RDONLY (1, 2)
rdonly_pcv_pc_1_2 (const void*, char*); // { dg-error "attribute .access\\(read_only, 1, 2\\)' positional argument 2 references non-integer argument type 'char \\*'" }
int RDONLY (2, 1)
rdonly_pcd_pcv_2_1 (const double*, const void*); // { dg-error "attribute .access\\(read_only, 2, 1\\)' positional argument 2 references non-integer argument type 'const double \\*'" }
int RDONLY (2, 2)
rdonly_pi_pcv_2_2 (int*, const void*); // { dg-error "positional argument 2 references non-integer argument type 'const void \\*'" }
int RDONLY (4)
rdonly_i_i_i_4 (int, int, int); // { dg-error "attribute 'access\\(read_only, 4\\)' positional argument 1 value 4 exceeds number of function arguments 3" }
int RDONLY (1)
rdonly_i_1 (int); // { dg-error "attribute 'access\\(read_only, 1\\)' positional argument 1 references non-pointer argument type 'int'" }
// It's okay if the pointer argument is non-const, although a separate
// warning encouraging one might be worthwhile. Maybe something like
// -Wsuggest-const.
int RDONLY (2)
rdonly_i_pc (int, char*);
int RDONLY (-1)
rdonly_pcv_m1 (const void*); // { dg-error "attribute 'access\\(read_only, -1\\)' positional argument 1 invalid value -1" }
int RDONLY (1, -12345)
rdonly_pcv_i_1_m12345 (const void*, int*); // { dg-error "attribute 'access\\(read_only, 1, -12345\\)' positional argument 2 invalid value -12345" }
int RDONLY ("blah")
rdonly_pcv_str (const void*); // { dg-error "attribute 'access\\(read_only, \"blah\"\\)' invalid positional argument 1" }
int RDONLY (1, "foobar")
rdonly_pcv_i_1_str (const void*, int); // { dg-error "attribute 'access\\(read_only, 1, \"foobar\"\\)' invalid positional argument 2" }
// Verify that attributes whose operands reference function pointers
// are rejected.
typedef int F (int, int);
RDONLY (1) void rdwr_pf_1 (F*); // { dg-error "attribute 'access\\(read_only, 1\\)' positional argument 1 references argument of function type 'F' \\{aka 'int\\(int, *int\\)'\\}" }
// Verify pointers to functions.
void RDONLY(2) (*prdonly_pcv2)(int, const void*);
void RDONLY(3, 1) (*prdonly_pcv2_1)(int, void*, const void*);
// Verify types.
typedef RDONLY (2) void rdonly_p2_t (const int*, const char*, const void*);
typedef RDONLY (2) void rdonly_p2_1 (int, const int*);
/* PR middle-end/83859 - attribute to establish relation between parameters
for buffer and its size
Test to verify the handling of attribute read_only combining multiple
declarations of the same function.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" } */
#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
int rdwr1_rdwr1 (void*, void*);
int RW (1) RW (1) rdwr1_rdwr1 (void*, void*);
int RW (2) RW (2) rdwr1_rdwr1 (void*, void*);
int RW (1) RW (2) rdwr1_rdwr1 (void*, void*);
int RW (2) RW (1) rdwr1_rdwr1 (void*, void*);
int frdwr1_wr1 (void*, void*);
int RW (1) WO (1) frdwr1_wr1 (void*, void*); // { dg-warning "attribute 'access\\(write_only, 1\\)' mismatch with mode 'read_write'" }
int RW (1) grdwr1_wr1 (void*, void*); // { dg-message "previous declaration here" }
int WO (1) grdwr1_wr1 (void*, void*); // { dg-warning "attribute 'access\\(write_only, 1\\)' mismatch with mode 'read_write'" }
int RW (1) RW (1, 2) frdwr1_rdwr1_1 (void*, int); // { dg-warning "attribute 'access\\(read_write, 1, 2\\)' positional argument 2 conflicts with previous designation" }
int RW (1, 2) RW (1) frdwr1_1_rdwr1 (void*, int); // { dg-warning "attribute 'access\\(read_write, 1\\)' missing positional argument 2 provided in previous designation" }
int RW (1) grdwr1_rdwr1_1 (void*, int); // { dg-message "previous declaration here" }
int RW (1, 2) grdwr1_rdwr1_1 (void*, int); // { dg-warning "attribute 'access\\(read_write, 1, 2\\)' positional argument 2 conflicts with previous designation" }
typedef int *P;
int RW(1) WO(3) RW(5) WO(7) RW(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
int RW(1) WO(3) RW(5) WO(7) RW(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
int WO(1) WO(3) RW(5) WO(7) RW(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(write_only, 1\\)' mismatch with mode 'read_write'" "1" { target *-*-* } .-1 }
int RW(1) RW(3) RW(5) WO(7) RW(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(read_write, 3\\)' mismatch with mode 'write_only'" "3" { target *-*-* } .-1 }
int RW(1) WO(3) WO(5) WO(7) RW(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(write_only, 5\\)' mismatch with mode 'read_write'" "5" { target *-*-* } .-1 }
int RW(1) WO(3) RW(5) RW(7) RW(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(read_write, 7\\)' mismatch with mode 'write_only'" "7" { target *-*-* } .-1 }
int RW(1) WO(3) RW(5) WO(7) WO(9) WO(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(write_only, 9\\)' mismatch with mode 'read_write'" "9" { target *-*-* } .-1 }
int RW(1) WO(3) RW(5) WO(7) RW(9) RW(11) RW(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(read_write, 11\\)' mismatch with mode 'write_only'" "11" { target *-*-* } .-1 }
int RW(1) WO(3) RW(5) WO(7) RW(9) WO(11) WO(13) WO(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(write_only, 13\\)' mismatch with mode 'read_write'" "13" { target *-*-* } .-1 }
int RW(1) WO(3) RW(5) WO(7) RW(9) WO(11) RW(13) RW(15) frw1_w3_rw5_w7_rw9_wr11_rw13_w15 (P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, int);
// { dg-warning "attribute 'access\\(read_write, 15\\)' mismatch with mode 'write_only'" "15" { target *-*-* } .-1 }
/* PR middle-end/83859 - attribute to establish relation between parameters
for buffer and its size
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" } */
int __attribute__ ((access))
access_v (void); /* { dg-error "wrong number of arguments specified for 'access' attribute" } */
int __attribute__ ((access ()))
access___v (void); /* { dg-error "wrong number of arguments specified for 'access' attribute" } */
int __attribute__ ((access (rdwr)))
rdwr_spelling (void); /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', or 'write_only'" } */
int __attribute__ ((access (read_write)))
rdwr_v_all (void); /* { dg-error "attribute .access\\(read_write\\). missing an argument" } */
int __attribute__ ((access (read_write ())))
rdwr___v_all (void); /* { dg-error "attribute 'access' unexpected '\\(' after mode 'read_write'; expected a positional argument or '\\)'" } */
/* { dg-warning "implicit declaration of function 'read_write'" "" { target *-*-* } .-2 } */
int rdwr (void);
int __attribute__ ((access (rdwr ())))
rdwr___v_all (void); /* { dg-error "attribute 'access' invalid mode 'rdwr'" } */
#define RDWR(...) __attribute__ ((access (read_write, __VA_ARGS__)))
int RDWR (1)
rdwr_pcv_1 (void*);
int RDWR (2)
rdwr_i_pcv_2 (int, void*);
int RDWR (3)
rdwr_i_i_pcv_3 (int, int, void*);
int RDWR (0 + 1)
rdwr_pcv_0p1 (void*);
int RDWR (2 - 1)
rdwr_pcv_2m1 (void*);
int RDWR (1)
rdwr_pcv_pi_1_1 (const void*, int*); /* { dg-error "attribute 'access\\(read_write, 1\\)' positional argument 1 references 'const'-qualified argument type 'const void \\*'" } */
int RDWR (1, 1)
rdwr_pv_pi_1_1 (void*, int*); /* { dg-error "attribute 'access\\(read_write, 1, 1\\)' positional argument 2 references non-integer argument type 'void \\*'" } */
int RDWR (1, 2)
rdwr_pcv_pc_1_2 (void*, char*); /* { dg-error "attribute .access\\(read_write, 1, 2\\)' positional argument 2 references non-integer argument type 'char \\*'" } */
int RDWR (2, 1)
rdwr_pcd_pcv_2_1 (double*, void*); /* { dg-error "attribute .access\\(read_write, 2, 1\\)' positional argument 2 references non-integer argument type 'double \\*'" } */
int RDWR (2, 2)
rdwr_pi_pcv_2_2 (int*, void*); /* { dg-error "positional argument 2 references non-integer argument type 'void \\*'" } */
int RDWR (4)
rdwr_i_i_i_4 (int, int, int); /* { dg-error "attribute 'access\\(read_write, 4\\)' positional argument 1 value 4 exceeds number of function arguments 3" } */
int RDWR (1)
rdwr_i_1 (int); /* { dg-error "attribute 'access\\(read_write, 1\\)' positional argument 1 references non-pointer argument type 'int'" } */
int RDWR (2)
rdwr_i_pc (int, const char*); /* { dg-error "attribute 'access\\(read_write, 2\\)' positional argument 1 references 'const'-qualified argument type 'const char \\*'" } */
int RDWR (-1)
rdwr_pcv_m1 (void*); /* { dg-error "attribute 'access\\(read_write, -1\\)' positional argument 1 invalid value -1" } */
int RDWR (1, -12345)
rdwr_pcv_i_1_m12345 (void*, int*); /* { dg-error "attribute 'access\\(read_write, 1, -12345\\)' positional argument 2 invalid value -12345" } */
int RDWR ("blah")
rdwr_pcv_str (void*); /* { dg-error "attribute 'access\\(read_write, \"blah\"\\)' invalid positional argument 1" } */
int RDWR (1, "foobar")
rdwr_pcv_i_1_str (void*, int); /* { dg-error "attribute 'access\\(read_write, 1, \"foobar\"\\)' invalid positional argument 2" } */
/* Verify that attributes whose operands reference function pointers
are rejected. */
typedef int F (int, int);
RDWR (1) void rdwr_pf_1 (F*); /* { dg-error "attribute 'access\\(read_write, 1\\)' positional argument 1 references argument of function type 'F' \\{aka 'int\\(int, *int\\)'\\}" } */
/* Verify pointers to functions. */
void RDWR(2) (*prdwr_pv2)(int, void*);
void RDWR(3, 1) (*prdwr_pv2_1)(int, void*, void*);
/* Verify types. */
typedef RDWR (2) void rdwr_p2_t (int*, char*, void*);
typedef RDWR (2) void rdwr_p2_1 (int, int*);
/* PR middle-end/83859 - attribute to establish relation between parameters
for buffer and its size
Test to verify the handling of attribute access (write_only) syntax.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" } */
int __attribute__ ((access))
access_v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" }
int __attribute__ ((access ()))
access___v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" }
int __attribute__ ((access (wronly)))
wronly_spelling (void); // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', or 'write_only'" }
int __attribute__ ((access (read_only)))
wronly_v_all (void); // { dg-error "attribute .access\\(read_only\\). missing an argument" }
int __attribute__ ((access (read_only ())))
wronly___v_all (void); // { dg-error "attribute 'access' unexpected '\\(' after mode 'read_only'; expected a positional argument or '\\)'" }
// { dg-warning "implicit declaration of function 'read_only'" "" { target *-*-* } .-2 }
int wronly (void);
int __attribute__ ((access (wronly ())))
wronly___v_all (void); // { dg-error "attribute 'access' invalid mode 'wronly'" }
#define WRONLY(...) __attribute__ ((access (write_only, __VA_ARGS__)))
int WRONLY (1)
wronly_pcv_1 (void*);
int WRONLY (2)
wronly_i_pcv_2 (int, void*);
int WRONLY (3)
wronly_i_i_pcv_3 (int, int, void*);
int WRONLY (0 + 1)
wronly_pcv_0p1 (void*);
int WRONLY (2 - 1)
wronly_pcv_2m1 (void*);
int WRONLY (1, 1)
wronly_pv_pi_1_1 (void*, const int*); // { dg-error "attribute 'access\\(write_only, 1, 1\\)' positional argument 2 references non-integer argument type 'void \\*'" }
int WRONLY (1, 2)
wronly_pcv_pc_1_2 (void*, char*); // { dg-error "attribute .access\\(write_only, 1, 2\\)' positional argument 2 references non-integer argument type 'char \\*'" }
int WRONLY (2, 1)
wronly_pcd_pcv_2_1 (const double*, void*); // { dg-error "attribute .access\\(write_only, 2, 1\\)' positional argument 2 references non-integer argument type 'const double \\*'" }
int WRONLY (2, 2)
wronly_pi_pcv_2_2 (int*, void*); // { dg-error "positional argument 2 references non-integer argument type 'void \\*'" }
int WRONLY (4)
wronly_i_i_i_4 (int, int, int); // { dg-error "attribute 'access\\(write_only, 4\\)' positional argument 1 value 4 exceeds number of function arguments 3" }
int WRONLY (1)
wronly_i_1 (int); // { dg-error "attribute 'access\\(write_only, 1\\)' positional argument 1 references non-pointer argument type 'int'" }
int WRONLY (2)
wronly_i_pc (int, const char*); // { dg-error "attribute 'access\\(write_only, 2\\)' positional argument 1 references 'const'-qualified argument type 'const char \\*'" }
int WRONLY (-1)
wronly_pcv_m1 (void*); // { dg-error "attribute 'access\\(write_only, -1\\)' positional argument 1 invalid value -1" }
int WRONLY (1, -12345)
wronly_pcv_i_1_m12345 (void*, int*); // { dg-error "attribute 'access\\(write_only, 1, -12345\\)' positional argument 2 invalid value -12345" }
int WRONLY ("blah")
wronly_pcv_str (void*); // { dg-error "attribute 'access\\(write_only, \"blah\"\\)' invalid positional argument 1" }
int WRONLY (1, "foobar")
wronly_pcv_i_1_str (void*, int); // { dg-error "attribute 'access\\(write_only, 1, \"foobar\"\\)' invalid positional argument 2" }
// Verify that attributes whose operands reference function pointers
// are rejected.
typedef int F (int, int);
WRONLY (1) void wronly_pf_1 (F*); // { dg-error "attribute 'access\\(write_only, 1\\)' positional argument 1 references argument of function type 'F' \\{aka 'int\\(int, *int\\)'\\}" }
// Verify pointers to functions.
void WRONLY(2) (*pwronly_pcv2)(int, void*);
void WRONLY(3, 1) (*pwronly_pcv2_1)(int, void*, void*);
void WRONLY(1, 2) (*pwronly_i_pcv_1_2)(int, void*); // { dg-error "attribute 'access\\(write_only, 1, 2\\)' positional argument 1 references non-pointer argument type 'int'" }
// Verify types.
typedef WRONLY (2) void wronly_p2_t (const int*, char*, const void*);
typedef WRONLY (2) void wronly_p2_1 (int, int*);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment