Commit 98f08eb8 by Martin Sebor Committed by Martin Sebor

c-parser.c (c_parser_has_attribute_expression): New function.

gcc/c/ChangeLog:

	* c-parser.c (c_parser_has_attribute_expression): New function.
	(c_parser_attribute): New function.
	(c_parser_attributes): Move code into c_parser_attribute.
	(c_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.

gcc/c-family/ChangeLog:

	* c-attribs.c (type_for_vector_size): New function.
	(type_valid_for_vector_size): Same.
	(handle_vector_size_attribute): Move code to the functions above
	and call them.
	(validate_attribute, has_attribute): New functions.
	* c-common.h (has_attribute): Declare.
	(rid): Add RID_HAS_ATTRIBUTE_EXPRESSION.
	* c-common.c (c_common_resword): Same.

gcc/cp/ChangeLog:

	* cp-tree.h (cp_check_const_attributes): Declare.
	* decl2.c (cp_check_const_attributes): Declare extern.
	* parser.c (cp_parser_has_attribute_expression): New function.
	(cp_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.
	(cp_parser_gnu_attribute_list): Add argument.

gcc/ChangeLog:

	* doc/extend.texi (Other Builtins): Add __builtin_has_attribute.

gcc/testsuite/ChangeLog:

	* c-c++-common/builtin-has-attribute-2.c: New test.
	* c-c++-common/builtin-has-attribute-3.c: New test.
	* c-c++-common/builtin-has-attribute-4.c: New test.
	* c-c++-common/builtin-has-attribute.c: New test.
	* gcc.dg/builtin-has-attribute.c: New test.
	* gcc/testsuite/gcc.target/i386/builtin-has-attribute.c: New test.

From-SVN: r266335
parent 48d1f31d
2018-11-20 Martin Sebor <msebor@redhat.com>
* doc/extend.texi (Other Builtins): Add __builtin_has_attribute.
2018-11-20 Jan Hubicka <hubicka@ucw.cz>
PR lto/84044
2018-11-20 Martin Sebor <msebor@redhat.com>
* c-attribs.c (type_for_vector_size): New function.
(type_valid_for_vector_size): Same.
(handle_vector_size_attribute): Move code to the functions above
and call them.
(validate_attribute, has_attribute): New functions.
* c-common.h (has_attribute): Declare.
(rid): Add RID_HAS_ATTRIBUTE_EXPRESSION.
* c-common.c (c_common_resword): Same.
2018-11-16 Jason Merrill <jason@redhat.com>
* c-lex.c (c_common_has_attribute): Handle likely/unlikely.
......
......@@ -4176,7 +4176,7 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
if (expr && DECL_P (expr))
found_match = TREE_READONLY (expr);
}
else if (!strcmp ("const", namestr))
else if (!strcmp ("pure", namestr))
{
if (expr && DECL_P (expr))
found_match = DECL_PURE_P (expr);
......
......@@ -376,6 +376,7 @@ const struct c_common_resword c_common_reswords[] =
RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
{ "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
{ "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
{ "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 },
{ "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
{ "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
{ "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
......
......@@ -103,6 +103,7 @@ enum rid
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
RID_BUILTIN_TGMATH,
RID_BUILTIN_HAS_ATTRIBUTE,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
/* TS 18661-3 keywords, in the same sequence as the TI_* values. */
......@@ -1355,6 +1356,7 @@ extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
enum cpp_ttype token_type,
location_t prev_token_loc);
extern tree braced_list_to_string (tree, tree);
extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
#if CHECKING_P
namespace selftest {
......
2018-11-20 Martin Sebor <msebor@redhat.com>
* c-parser.c (c_parser_has_attribute_expression): New function.
(c_parser_attribute): New function.
(c_parser_attributes): Move code into c_parser_attribute.
(c_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.
2018-11-15 Martin Sebor <msebor@redhat.com>
PR c/83656
......
2018-11-20 Martin Sebor <msebor@redhat.com>
* cp-tree.h (cp_check_const_attributes): Declare.
* decl2.c (cp_check_const_attributes): Declare extern.
* parser.c (cp_parser_has_attribute_expression): New function.
(cp_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.
(cp_parser_gnu_attribute_list): Add argument.
2018-11-20 Jakub Jelinek <jakub@redhat.com>
PR c++/88110
......
......@@ -6491,6 +6491,7 @@ extern int parm_index (tree);
extern tree vtv_start_verification_constructor_init_function (void);
extern tree vtv_finish_verification_constructor_init_function (tree);
extern bool cp_omp_mappable_type (tree);
extern void cp_check_const_attributes (tree);
/* in error.c */
extern const char *type_as_string (tree, int);
......
......@@ -1368,7 +1368,7 @@ cp_reconstruct_complex_type (tree type, tree bottom)
/* Replaces any constexpr expression that may be into the attributes
arguments with their reduced value. */
static void
void
cp_check_const_attributes (tree attributes)
{
if (attributes == error_mark_node)
......
......@@ -2048,6 +2048,8 @@ static cp_expr cp_parser_unary_expression
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
static enum tree_code cp_parser_unary_operator
(cp_token *);
static tree cp_parser_has_attribute_expression
(cp_parser *);
static tree cp_parser_new_expression
(cp_parser *);
static vec<tree, va_gc> *cp_parser_new_placement
......@@ -2381,7 +2383,7 @@ static tree cp_parser_attributes_opt
static tree cp_parser_gnu_attributes_opt
(cp_parser *);
static tree cp_parser_gnu_attribute_list
(cp_parser *);
(cp_parser *, bool = false);
static tree cp_parser_std_attribute
(cp_parser *, tree);
static tree cp_parser_std_attribute_spec
......@@ -8110,6 +8112,9 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
return ret_expr;
}
case RID_BUILTIN_HAS_ATTRIBUTE:
return cp_parser_has_attribute_expression (parser);
case RID_NEW:
return cp_parser_new_expression (parser);
......@@ -8407,6 +8412,121 @@ cp_parser_unary_operator (cp_token* token)
}
}
/* Parse a __builtin_has_attribute([expr|type], attribute-spec) expression.
Returns a representation of the expression. */
static tree
cp_parser_has_attribute_expression (cp_parser *parser)
{
location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
/* Consume the __builtin_has_attribute token. */
cp_lexer_consume_token (parser->lexer);
matching_parens parens;
if (!parens.require_open (parser))
return error_mark_node;
/* Types cannot be defined in a `sizeof' expression. Save away the
old message. */
const char *saved_message = parser->type_definition_forbidden_message;
/* And create the new one. */
const int kwd = RID_BUILTIN_HAS_ATTRIBUTE;
char *tmp = concat ("types may not be defined in %<",
IDENTIFIER_POINTER (ridpointers[kwd]),
"%> expressions", NULL);
parser->type_definition_forbidden_message = tmp;
/* The restrictions on constant-expressions do not apply inside
sizeof expressions. */
bool saved_integral_constant_expression_p
= parser->integral_constant_expression_p;
bool saved_non_integral_constant_expression_p
= parser->non_integral_constant_expression_p;
parser->integral_constant_expression_p = false;
/* Do not actually evaluate the expression. */
++cp_unevaluated_operand;
++c_inhibit_evaluation_warnings;
tree oper = NULL_TREE;
/* We can't be sure yet whether we're looking at a type-id or an
expression. */
cp_parser_parse_tentatively (parser);
bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
/* Look for the type-id. */
oper = cp_parser_type_id (parser);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
cp_parser_parse_definitely (parser);
/* If the type-id production did not work out, then we must be
looking at the unary-expression production. */
if (!oper || oper == error_mark_node)
oper = cp_parser_unary_expression (parser);
/* Go back to evaluating expressions. */
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
/* Free the message we created. */
free (tmp);
/* And restore the old one. */
parser->type_definition_forbidden_message = saved_message;
parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
parser->non_integral_constant_expression_p
= saved_non_integral_constant_expression_p;
/* Consume the comma if it's there. */
if (!cp_parser_require (parser, CPP_COMMA, RT_COMMA))
{
cp_parser_skip_to_closing_parenthesis (parser, false, false,
/*consume_paren=*/true);
return error_mark_node;
}
/* Parse the attribute specification. */
bool ret = false;
location_t atloc = cp_lexer_peek_token (parser->lexer)->location;
if (tree attr = cp_parser_gnu_attribute_list (parser, /*exactly_one=*/true))
{
if (oper != error_mark_node)
{
/* Fold constant expressions used in attributes first. */
cp_check_const_attributes (attr);
/* Finally, see if OPER has been declared with ATTR. */
ret = has_attribute (atloc, oper, attr, default_conversion);
}
parens.require_close (parser);
}
else
{
error_at (atloc, "expected identifier");
cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
}
/* Construct a location e.g. :
__builtin_has_attribute (oper, attr)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
with start == caret at the start of the built-in token,
and with the endpoint at the final closing paren. */
location_t finish_loc
= cp_lexer_previous_token (parser->lexer)->location;
location_t compound_loc
= make_location (start_loc, start_loc, finish_loc);
cp_expr ret_expr (ret ? boolean_true_node : boolean_false_node);
ret_expr.set_location (compound_loc);
ret_expr = ret_expr.maybe_add_location_wrapper ();
return ret_expr;
}
/* Parse a new-expression.
new-expression:
......@@ -25376,7 +25496,7 @@ cp_parser_gnu_attributes_opt (cp_parser* parser)
the arguments, if any. */
static tree
cp_parser_gnu_attribute_list (cp_parser* parser)
cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
{
tree attribute_list = NULL_TREE;
bool save_translate_strings_p = parser->translate_strings_p;
......@@ -25443,9 +25563,9 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
token = cp_lexer_peek_token (parser->lexer);
}
/* Now, look for more attributes. If the next token isn't a
`,', we're done. */
if (token->type != CPP_COMMA)
/* Unless EXACTLY_ONE is set look for more attributes.
If the next token isn't a `,', we're done. */
if (exactly_one || token->type != CPP_COMMA)
break;
/* Consume the comma and keep going. */
......@@ -11140,6 +11140,7 @@ is called and the @var{flag} argument passed to it.
@findex __builtin_call_with_static_chain
@findex __builtin_extend_pointer
@findex __builtin_fpclassify
@findex __builtin_has_attribute
@findex __builtin_isfinite
@findex __builtin_isnormal
@findex __builtin_isgreater
......@@ -11797,6 +11798,46 @@ check its compatibility with @var{size}.
@end deftypefn
@deftypefn {Built-in Function} bool __builtin_has_attribute (@var{type-or-expression}, @var{attribute})
The @code{__builtin_has_attribute} function evaluates to an integer constant
expression equal to @code{true} if the symbol or type referenced by
the @var{type-or-expression} argument has been declared with
the @var{attribute} referenced by the second argument. Neither argument
is evaluated. The @var{type-or-expression} argument is subject to the same
restrictions as the argument to @code{typeof} (@pxref{Typeof}). The
@var{attribute} argument is an attribute name optionally followed by
a comma-separated list of arguments enclosed in parentheses. Both forms
of attribute names---with and without double leading and trailing
underscores---are recognized. See @xref{Attribute Syntax} for details.
When no attribute arguments are specified for an attribute that expects
one or more arguments the function returns @code{true} if
@var{type-or-expression} has been declared with the attribute regardless
of the attribute argument values. Arguments provided for an attribute
that expects some are validated and matched up to the provided number.
The function returns @code{true} if all provided arguments match. For
example, the first call to the function below evaluates to @code{true}
because @code{x} is declared with the @code{aligned} attribute but
the second call evaluates to @code{false} because @code{x} is declared
@code{aligned (8)} and not @code{aligned (4)}.
@smallexample
__attribute__ ((aligned (8))) int x;
_Static_assert (__builtin_has_attribute (x, aligned), "aligned");
_Static_assert (!__builtin_has_attribute (x, aligned (4)), "aligned (4)");
@end smallexample
Due to a limitation the @code{__builtin_has_attribute} function returns
@code{false} for the @code{mode} attribute even if the type or variable
referenced by the @var{type-or-expression} argument was declared with one.
The function is also not supported with labels, and in C with enumerators.
Note that unlike the @code{__has_attribute} preprocessor operator which
is suitable for use in @code{#if} preprocessing directives
@code{__builtin_has_attribute} is an intrinsic function that is not
recognized in such contexts.
@end deftypefn
@deftypefn {Built-in Function} @var{type} __builtin_speculation_safe_value (@var{type} val, @var{type} failval)
This built-in function can be used to help mitigate against unsafe
......
2018-11-20 Martin Sebor <msebor@redhat.com>
* c-c++-common/builtin-has-attribute-2.c: New test.
* c-c++-common/builtin-has-attribute-3.c: New test.
* c-c++-common/builtin-has-attribute-4.c: New test.
* c-c++-common/builtin-has-attribute.c: New test.
* gcc.dg/builtin-has-attribute.c: New test.
* gcc/testsuite/gcc.target/i386/builtin-has-attribute.c: New test.
2018-11-20 Jan Hubicka <hubicka@ucw.cz>
PR lto/84044
......
/* Verify __builtin_has_attribute return value for types.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" }
{ dg-options "-Wall -Wno-narrowing -Wno-unused-local-typedefs -ftrack-macro-expansion=0" { target c++ } } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
#define A(expect, sym, attr) \
typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
struct ATTR (packed) Packed { char c; int i; };
void fvoid (void);
struct Packed fpacked (void);
union OrdinaryUnion { void *p; int i; };
union ATTR (transparent_union) TransparentUnion { void *p; int i; };
/* Exercise __builtin_has_attribute with the first argument that
is a type. */
void test_type (int n)
{
/* Verify both forms of the attribute spelling. Unlike the attribute
keyword that can be spelled three ways (with either leading or
trailing underscores, or with both), attribute names can only be
spelled two ways. */
A (0, int, aligned);
A (0, int, __aligned__);
A (0, int, aligned (1));
A (0, int, aligned (2));
A (0, int[1], aligned);
A (0, int[1], aligned (2));
A (0, int[n], aligned);
A (0, int[n], aligned (4));
/* Again, verify both forms of the attribute spelling. */
A (1, ATTR (aligned) char, aligned);
A (1, ATTR (aligned (2)) short, aligned);
A (1, ATTR (aligned (4)) int, __aligned__);
A (0, int ATTR (aligned (4)), aligned (2));
A (0, int ATTR (aligned (2)), aligned (4));
/* GCC retains both attributes in the */
A (0, int ATTR (aligned (2), aligned (4)), aligned (2));
A (1, int ATTR (aligned (2), aligned (4)), aligned (4));
/* The following fails due to bug 87524.
A (1, int ATTR (aligned (4), aligned (2))), aligned (4)); */
A (0, int ATTR (aligned (4), aligned (2)), aligned (8));
A (1, int ATTR (aligned (8)), aligned (1 + 7));
enum { eight = 8 };
A (1, int ATTR (aligned (8)), aligned (eight));
A (1, int ATTR (aligned (eight)), aligned (1 + 7));
struct NotPacked { char c; int i; };
A (0, struct NotPacked, packed);
A (1, struct Packed, packed);
/* Exercise types returned from a function. */
A (0, fvoid (), packed);
A (1, fpacked (), packed);
struct ATTR (aligned (2), packed) Aligned2Packed { char c; int i; };
A (1, struct Aligned2Packed, aligned);
A (1, struct Aligned2Packed, aligned (2));
A (0, struct Aligned2Packed, aligned (4));
A (1, struct Aligned2Packed, packed);
A (0, int, may_alias);
A (1, ATTR (may_alias) int, may_alias);
A (0, char, warn_if_not_aligned (1));
A (0, char, warn_if_not_aligned (2));
A (1, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned);
A (0, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned (1));
A (1, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned (2));
A (0, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned (4));
A (0, union OrdinaryUnion, transparent_union);
A (1, union TransparentUnion, transparent_union);
A (1, const union TransparentUnion, transparent_union);
}
/* Exercise __builtin_has_attribute with the first argument that
is a typedef. */
void test_typedef (int n)
{
typedef char A1[1];
A (0, A1, aligned);
A (0, A1, aligned (1));
A (0, A1, aligned (2));
typedef char An[n];
A (0, An, aligned);
A (0, An, aligned (1));
A (0, An, aligned (2));
typedef ATTR (aligned (8)) short AI8;
A (1, AI8, aligned);
A (0, AI8, aligned (4));
A (1, AI8, aligned (8));
A (0, AI8, aligned (16));
A (1, const AI8, aligned);
A (1, const volatile AI8, aligned);
typedef ATTR (aligned (2), aligned (8), aligned (16)) int AI16;
A (1, AI16, aligned);
A (0, AI16, aligned (1));
A (0, AI16, aligned (2));
A (0, AI16, aligned (4));
A (0, AI16, aligned (8));
A (1, AI16, aligned (16));
A (0, AI16, aligned (32));
typedef const AI16 CAI16;
A (1, CAI16, aligned);
A (0, CAI16, aligned (1));
A (1, CAI16, aligned (16));
typedef int I;
A (0, I, may_alias);
A (0, AI8, may_alias);
typedef ATTR (may_alias) int MAI;
A (1, MAI, may_alias);
typedef ATTR (aligned (4), may_alias) char A4MAC;
A (0, A4MAC, aligned (0));
A (0, A4MAC, aligned (1));
A (0, A4MAC, aligned (2));
A (1, A4MAC, aligned (4));
A (0, A4MAC, aligned (8));
A (1, A4MAC, may_alias);
typedef ATTR (may_alias, aligned (8)) char A8MAC;
A (1, A8MAC, aligned);
A (0, A8MAC, aligned (0));
A (0, A8MAC, aligned (1));
A (0, A8MAC, aligned (2));
A (0, A8MAC, aligned (4));
A (1, A8MAC, aligned (8));
A (0, A8MAC, aligned (16));
A (1, A8MAC, may_alias);
typedef ATTR (may_alias) const AI8 CMAI8;
A (1, CMAI8, aligned);
A (1, CMAI8, may_alias);
A (0, CMAI8, aligned (4));
A (1, CMAI8, aligned (8));
typedef void Fnull (void*, void*, void*);
A (0, Fnull, nonnull);
A (0, Fnull, nonnull (1));
A (0, Fnull, nonnull (2));
A (0, Fnull, nonnull (3));
typedef ATTR (nonnull) Fnull Fnonnull;
A (1, Fnonnull, nonnull);
A (1, Fnonnull, nonnull (1));
A (1, Fnonnull, nonnull (2));
A (1, Fnonnull, nonnull (3));
typedef ATTR (nonnull (2)) void Fnonnull_2 (void*, void*, void*);
A (0, Fnonnull_2, nonnull);
A (0, Fnonnull_2, nonnull (1));
A (1, Fnonnull_2, nonnull (2));
A (0, Fnonnull_2, nonnull (3));
typedef ATTR (nonnull (1), nonnull (2), nonnull (3))
void Fnonnull_1_2_3 (void*, void*, void*);
/* The following fails because the built-in doesn't recognize that
a single nonnull with no arguments is the same as one nonnull for
each function parameter. Disable the testing for now.
A (1, Fnonnull_1_2_3, nonnull);
*/
A (1, Fnonnull_1_2_3, nonnull (1));
A (1, Fnonnull_1_2_3, nonnull (2));
A (1, Fnonnull_1_2_3, nonnull (3));
typedef void Freturns (void);
A (0, Fnull, noreturn);
A (0, Freturns, noreturn);
typedef ATTR (warn_if_not_aligned (8)) char CWA8;
A (0, CWA8, warn_if_not_aligned (2));
A (0, CWA8, warn_if_not_aligned (4));
A (1, CWA8, warn_if_not_aligned (8));
A (0, CWA8, warn_if_not_aligned (16));
typedef union OrdinaryUnion OrdUnion;
A (0, OrdUnion, transparent_union);
/* The attribute is ignored on typedefs but GCC fails to diagnose
it (see bug ). */
typedef union ATTR (transparent_union)
OrdinaryUnion TransUnion; /* { dg-warning "\\\[-Wattributes" "pr87578" { xfail { ! { c++ } } } } */
A (0, TransUnion, transparent_union);
}
/* Verify __builtin_has_attribute return value for functions.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" }
{ dg-options "-Wall -Wno-narrowing -Wno-unused-local-typedefs -ftrack-macro-expansion=0" { target c++ } } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
void fnone (void);
ATTR (aligned) void faligned (void);
ATTR (aligned (1)) void faligned_1 (void);
ATTR (aligned (2)) void faligned_2 (void);
ATTR (aligned (4)) void faligned_4 (void);
ATTR (aligned (8)) void faligned_8 (void);
ATTR (alloc_size (1)) void* falloc_size_1 (int, int);
ATTR (alloc_size (2)) void* falloc_size_2 (int, int);
ATTR (alloc_size (2, 4)) void* falloc_size_2_4 (int, int, int, int);
ATTR (alloc_align (1)) void* falloc_align_1 (int, int);
ATTR (alloc_align (2)) void* falloc_align_2 (int, int);
ATTR (alloc_align (1), alloc_size (2)) void* falloc_align_1_size_2 (int, int);
ATTR (alloc_align (2), alloc_size (1)) void* falloc_align_2_size_1 (int, int);
#if __cplusplus
extern "C"
#endif
ATTR (noreturn) void fnoreturn (void) { __builtin_abort (); }
ATTR (alias ("fnoreturn")) void falias (void);
#define A(expect, sym, attr) \
typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
void test_aligned (void)
{
A (0, fnone, aligned);
A (0, fnone, aligned (0));
A (0, fnone, aligned (1));
A (0, fnone, aligned (2));
A (0, fnone, aligned (4));
A (0, fnone, aligned (8));
A (0, fnone, aligned (16));
A (1, faligned, aligned);
A (0, faligned, aligned (0));
A (0, faligned, aligned (1));
A (0, faligned, aligned (2));
A (1, faligned_1, aligned);
A (0, faligned_1, aligned (0));
A (1, faligned_1, aligned (1));
A (0, faligned_1, aligned (2));
A (0, faligned_1, aligned (4));
A (1, faligned_2, aligned);
A (0, faligned_2, aligned (0));
A (0, faligned_2, aligned (1));
A (1, faligned_2, aligned (2));
A (0, faligned_2, aligned (4));
}
void test_alloc_align (void)
{
A (0, fnone, alloc_align);
A (0, falloc_size_1, alloc_align);
A (1, falloc_align_1, alloc_align);
A (1, falloc_align_2, alloc_align);
A (0, fnone, alloc_align (1)); /* { dg-warning "\\\[-Wattributes" } */
A (0, falloc_size_1, alloc_align (1));
A (1, falloc_align_1, alloc_align (1));
A (0, falloc_align_2, alloc_align (1));
A (1, falloc_align_2, alloc_align (2));
}
void test_alloc_size_malloc (void)
{
A (0, fnone, alloc_size);
A (0, fnone, alloc_size (1)); /* { dg-warning "\\\[-Wattributes" } */
A (0, fnone, alloc_size (2)); /* { dg-warning "\\\[-Wattributes" } */
A (0, falloc_align_1, alloc_size (1));
A (0, falloc_align_2, alloc_size (1));
A (1, falloc_size_1, alloc_size (1));
A (0, falloc_size_1, alloc_size (2));
A (0, falloc_size_2, alloc_size (1));
A (1, falloc_size_2, alloc_size (2));
A (1, falloc_size_2_4, alloc_size);
/* It would probably make more sense to have the built-in return
true only when both alloc_size arguments match, not just one
or the other. */
A (0, falloc_size_2_4, alloc_size (1));
A (1, falloc_size_2_4, alloc_size (2));
A (0, falloc_size_2_4, alloc_size (3));
A (1, falloc_size_2_4, alloc_size (4));
A (1, falloc_size_2_4, alloc_size (2, 4));
extern ATTR (alloc_size (3))
void* fmalloc_size_3 (int, int, int);
A (1, fmalloc_size_3, alloc_size);
A (0, fmalloc_size_3, alloc_size (1));
A (0, fmalloc_size_3, alloc_size (2));
A (1, fmalloc_size_3, alloc_size (3));
A (0, fmalloc_size_3, malloc);
extern ATTR (malloc)
void* fmalloc_size_3 (int, int, int);
A (1, fmalloc_size_3, alloc_size (3));
A (1, fmalloc_size_3, malloc);
}
void test_alias (void)
{
A (0, fnoreturn, alias);
A (1, falias, alias);
A (1, falias, alias ("fnoreturn"));
A (0, falias, alias ("falias"));
A (0, falias, alias ("fnone"));
}
void test_cold_hot (void)
{
extern ATTR (cold) void fcold (void);
extern ATTR (hot) void fhot (void);
A (0, fnone, cold);
A (0, fnone, hot);
A (1, fcold, cold);
A (0, fcold, hot);
A (0, fhot, cold);
A (1, fhot, hot);
}
void test_const_leaf_pure (void)
{
extern ATTR (const) int fconst (void);
extern ATTR (leaf) int fleaf (void);
extern ATTR (pure) int fpure (void);
A (0, fnone, const);
A (0, fnone, leaf);
A (0, fnone, pure);
A (1, fconst, const);
A (0, fconst, leaf);
A (0, fconst, pure);
A (0, fleaf, const);
A (1, fleaf, leaf);
A (0, fleaf, pure);
A (0, fpure, const);
A (0, fpure, leaf);
A (1, fpure, pure);
extern ATTR (const, leaf) int fconst_leaf (void);
A (1, fconst_leaf, const);
A (1, fconst_leaf, leaf);
extern ATTR (leaf, const) int fleaf_const (void);
A (1, fleaf_const, const);
A (1, fleaf_const, leaf);
}
void test_ctor_dtor (void)
{
extern ATTR (constructor) void fctor (void);
extern ATTR (destructor) void fdtor (void);
extern ATTR (constructor, destructor) void fctor_dtor (void);
A (0, fnone, constructor);
A (0, fnone, destructor);
A (1, fctor, constructor);
A (1, fdtor, destructor);
extern ATTR (constructor) void fctor_dtor (void);
extern ATTR (destructor) void fctor_dtor (void);
extern ATTR (constructor, destructor) void fctor_dtor (void);
A (1, fctor_dtor, constructor);
A (1, fctor_dtor, destructor);
extern ATTR (constructor (123)) void fctor_123 (void);
A (1, fctor_123, constructor);
A (0, fctor_123, destructor);
A (1, fctor_123, constructor (123));
A (0, fctor_123, constructor (124));
extern ATTR (destructor (234)) void fctor_123 (void);
A (1, fctor_123, constructor (123));
A (1, fctor_123, destructor);
A (1, fctor_123, destructor (234));
A (0, fctor_123, destructor (235));
}
void test_externally_visible (void)
{
extern void fexternally_visible (void);
A (0, fexternally_visible, externally_visible);
extern ATTR (externally_visible) void fexternally_visible (void);
A (1, fexternally_visible, externally_visible);
}
void test_flatten (void)
{
extern void fflatten (void);
A (0, fflatten, flatten);
extern ATTR (flatten) void fflatten (void);
A (1, fflatten, flatten);
extern void fflatten (void);
A (1, fflatten, flatten);
}
ATTR (format (printf, 2, 4)) void
fformat_printf_2_3 (int, const char*, int, ...);
void test_format (void)
{
A (0, fnone, format);
A (0, fnone, format (printf));
A (0, fnone, format (printf, 2));
}
inline void finline (void) { }
inline ATTR (always_inline) void falways_inline (void) { }
inline ATTR (always_inline, gnu_inline) void falways_gnu_inline (void) { }
ATTR (noinline) void fnoinline () { }
void test_inline (void)
{
A (0, fnone, always_inline);
A (0, fnone, gnu_inline);
A (0, fnone, noinline);
A (0, finline, always_inline);
A (0, finline, gnu_inline);
A (0, finline, noinline);
A (1, falways_inline, always_inline);
A (0, falways_inline, gnu_inline);
A (0, falways_inline, noinline);
A (1, falways_gnu_inline, always_inline);
A (1, falways_gnu_inline, gnu_inline);
A (0, falways_gnu_inline, noinline);
A (0, fnoinline, always_inline);
A (0, fnoinline, gnu_inline);
A (1, fnoinline, noinline);
}
ATTR (no_instrument_function) void fno_instrument (void);
ATTR (visibility ("default")) void fdefault (void);
ATTR (visibility ("hidden")) void fhidden (void);
ATTR (visibility ("internal")) void finternal (void);
ATTR (visibility ("protected")) void fprotected (void);
void test_visibility (void)
{
A (0, fnone, visibility ("default"));
A (0, fnone, visibility ("hidden"));
A (0, fnone, visibility ("internal"));
A (0, fnone, visibility ("protected"));
A (1, fdefault, visibility ("default"));
A (0, fdefault, visibility ("hidden"));
A (0, fdefault, visibility ("internal"));
A (0, fdefault, visibility ("protected"));
A (0, fhidden, visibility ("default"));
A (1, fhidden, visibility ("hidden"));
A (0, fhidden, visibility ("internal"));
A (0, fhidden, visibility ("protected"));
A (0, finternal, visibility ("default"));
A (0, finternal, visibility ("hidden"));
A (1, finternal, visibility ("internal"));
A (0, finternal, visibility ("protected"));
A (0, fprotected, visibility ("default"));
A (0, fprotected, visibility ("hidden"));
A (0, fprotected, visibility ("internal"));
A (1, fprotected, visibility ("protected"));
}
/* { dg-prune-output "specifies less restrictive attribute" } */
/* Verify __builtin_has_attribute return value for variables.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" }
{ dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
#define A(expect, sym, attr) \
typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
int vnone;
ATTR (aligned) char valigned;
ATTR (aligned (1)) char valigned_1;
ATTR (aligned (2)) char valigned_2;
ATTR (aligned (4)) char valigned_4;
ATTR (aligned (8)) char valigned_8;
void test_aligned (void)
{
A (0, vnone, aligned);
A (0, vnone, aligned (0));
A (0, vnone, aligned (1));
A (0, vnone, aligned (2));
A (0, vnone, aligned (4));
A (0, vnone, aligned (8));
A (0, vnone, aligned (16));
A (1, valigned, aligned);
A (0, valigned, aligned (0));
A (0, valigned, aligned (1));
A (0, valigned, aligned (2));
A (1, valigned_1, aligned);
A (0, valigned_1, aligned (0));
A (1, valigned_1, aligned (1));
A (0, valigned_1, aligned (2));
A (0, valigned_1, aligned (4));
A (1, valigned_2, aligned);
A (0, valigned_2, aligned (0));
A (0, valigned_2, aligned (1));
A (1, valigned_2, aligned (2));
A (0, valigned_2, aligned (4));
}
int vtarget;
extern ATTR (alias ("vtarget")) int valias;
void test_alias (void)
{
A (0, vnone, alias);
A (1, valias, alias);
A (1, valias, alias ("vtarget"));
A (0, valias, alias ("vnone"));
}
void test_cleanup (void)
{
extern void fpv (void*);
extern void fcleanup (void*);
int var;
ATTR (cleanup (fcleanup)) int var_cleanup;
A (0, var, cleanup);
A (1, var_cleanup, cleanup);
A (1, var_cleanup, cleanup (fcleanup));
A (0, var_cleanup, cleanup (fpv));
}
ATTR (common) int vcommon;
ATTR (nocommon) int vnocommon;
void test_common (void)
{
A (0, vnone, common);
A (0, vnone, nocommon);
A (1, vcommon, common);
A (0, vcommon, nocommon);
A (0, vnocommon, common);
A (1, vnocommon, nocommon);
}
void test_externally_visible (void)
{
extern int vexternally_visible;
A (0, vexternally_visible, externally_visible);
extern ATTR (externally_visible) int vexternally_visible;
A (1, vexternally_visible, externally_visible);
}
int test_mode (void)
{
ATTR (mode (byte)) int i8;
return __builtin_has_attribute (i8, mode); /* { dg-warning ".mode. attribute not supported in .__builtin_has_attribute." } */
}
void test_nonstring (void)
{
char arr[1];
char* ptr = arr;
ATTR (nonstring) char arr_nonstring[1];
ATTR (nonstring) char *ptr_nonstring = arr_nonstring;
A (0, arr, nonstring);
A (0, ptr, nonstring);
A (1, arr_nonstring, nonstring);
A (1, ptr_nonstring, nonstring);
}
struct PackedMember
{
char c;
short s;
int i;
ATTR (packed) int a[2];
} gpak[2];
void test_packed (struct PackedMember *p)
{
int vunpacked;
ATTR (packed) int vpacked; /* { dg-warning ".packed. attribute ignored" } */
A (0, vunpacked, packed);
A (0, vpacked, packed);
int arr_unpacked[2];
ATTR (packed) int arr_packed[2]; /* { dg-warning ".packed. attribute ignored" } */
A (0, arr_unpacked, packed);
A (0, arr_packed, packed);
A (0, arr_unpacked[0], packed);
A (0, arr_packed[0], packed);
A (0, gpak, packed);
A (0, gpak[0], packed);
A (0, *gpak, packed);
A (0, gpak[0].c, packed);
A (0, gpak[1].s, packed);
A (1, gpak->a, packed);
A (1, (*gpak).a[0], packed);
/* The following fails because in C it's represented as
INDIRECT_REF (POINTER_PLUS (NOP_EXPR (ADDR_EXPR (gpak)), ...))
with no reference to the member. Avoid testing it.
A (1, *gpak[9].a, packed); */
A (0, p->c, packed);
A (0, p->s, packed);
A (1, p->a, packed);
A (1, p->a[0], packed);
/* Similar to the comment above.
A (1, *p->a, packed); */
}
ATTR (section ("sectA")) int var_sectA;
ATTR (section ("sectB")) int var_sectB;
void test_section (void)
{
int var = 0;
A (0, var, section);
A (0, var, section ("sectA"));
A (1, var_sectA, section);
A (1, var_sectA, section ("sectA"));
A (0, var_sectA, section ("sectB"));
A (1, var_sectB, section);
A (0, var_sectB, section ("sectA"));
A (1, var_sectB, section ("sectB"));
}
void test_vector_size (void)
{
char c;
extern int arrx[];
extern int arr1[1];
A (0, c, vector_size);
A (0, c, vector_size (1));
A (0, arrx, vector_size);
A (0, arrx, vector_size (4));
A (0, arr1, vector_size);
A (0, arr1, vector_size (8));
ATTR (vector_size (4)) char cv4;
ATTR (vector_size (16)) int iv16;
A (1, cv4, vector_size);
A (0, cv4, vector_size (1));
A (0, cv4, vector_size (2));
A (1, cv4, vector_size (4));
A (0, cv4, vector_size (8));
A (1, iv16, vector_size);
A (0, iv16, vector_size (1));
A (0, iv16, vector_size (8));
A (1, iv16, vector_size (16));
A (0, iv16, vector_size (32));
ATTR (vector_size (8)) float afv8[4];
A (1, afv8, vector_size);
A (0, afv8, vector_size (1));
A (0, afv8, vector_size (2));
A (0, afv8, vector_size (4));
A (1, afv8, vector_size (8));
A (0, afv8, vector_size (16));
}
ATTR (visibility ("default")) int vdefault;
ATTR (visibility ("hidden")) int vhidden;
ATTR (visibility ("internal")) int vinternal;
ATTR (visibility ("protected")) int vprotected;
void test_visibility (void)
{
A (0, vnone, visibility ("default"));
A (0, vnone, visibility ("hidden"));
A (0, vnone, visibility ("internal"));
A (0, vnone, visibility ("protected"));
A (1, vdefault, visibility ("default"));
A (0, vdefault, visibility ("hidden"));
A (0, vdefault, visibility ("internal"));
A (0, vdefault, visibility ("protected"));
A (0, vhidden, visibility ("default"));
A (1, vhidden, visibility ("hidden"));
A (0, vhidden, visibility ("internal"));
A (0, vhidden, visibility ("protected"));
A (0, vinternal, visibility ("default"));
A (0, vinternal, visibility ("hidden"));
A (1, vinternal, visibility ("internal"));
A (0, vinternal, visibility ("protected"));
A (0, vprotected, visibility ("default"));
A (0, vprotected, visibility ("hidden"));
A (0, vprotected, visibility ("internal"));
A (1, vprotected, visibility ("protected"));
}
int var_init_strong = 123;
int var_uninit_strong;
static int var_extern_strong;
static int var_static_strong;
ATTR (weak) int var_init_weak = 234;
ATTR (weak) int var_uninit_weak;
void test_weak (void)
{
int var_local = 0;
static int var_static_local = 0;
A (0, var_init_strong, weak);
A (0, var_uninit_strong, weak);
A (0, var_extern_strong, weak);
A (0, var_static_strong, weak);
A (0, var_local, weak);
A (0, var_static_local, weak);
A (1, var_init_weak, weak);
A (1, var_uninit_weak, weak);
}
/* { dg-prune-output "specifies less restrictive attribute" } */
/* Verify __builtin_has_attribute error handling.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" } */
#define ATTR(list) __attribute__ (list)
void fnone (void);
ATTR ((aligned)) void faligned (void);
ATTR ((aligned (8))) void faligned_8 (void);
#define has_attr(x, attr) __builtin_has_attribute (x, attr)
#define A(expect, sym, attr) \
typedef int Assert [1 - 2 * !(has_attr (sym, attr) == expect)]
int b;
/* Exercise syntactically invalid arguments. */
void test_bad_arguments (void)
{
b = __builtin_has_attribute (); /* { dg-error "expected \(primary-\)?expression|expected .,." } */
b = __builtin_has_attribute (1); /* { dg-error "expected .,." } */
b = __builtin_has_attribute (void); /* { dg-error "expected .,." } */
b = __builtin_has_attribute (foo); /* { dg-error ".foo. \(undeclared|was not declared\)" } */
/* { dg-error "expected .,." "missing comma" { target *-*-* } .-1 } */
/* Verify the implementationm doesn't ICE. */
b = __builtin_has_attribute (foobar, aligned); /* { dg-error ".foobar. \(undeclared|was not declared\)" } */
b = __builtin_has_attribute (1, 2, 3); /* { dg-error "expected identifier" } */
b = __builtin_has_attribute (int, 1 + 2); /* { dg-error "expected identifier" } */
b = __builtin_has_attribute (2, "aligned"); /* { dg-error "expected identifier" } */
}
/* Exercise syntactically valid arguments applied in invalid ways. */
void test_invalid_arguments (void)
{
b = has_attr (fnone, align); /* { dg-error "unknown attribute .align." } */
b = has_attr (b, aligned__); /* { dg-error "unknown attribute .aligned__." } */
b = has_attr (fnone, aligned (3)); /* { dg-error "alignment .3. is not a positive power of 2" } */
/* Verify the out-of-bounds arguments are diagnosed and the result
of the built-in is false. */
A (0, fnone, alloc_size (1)); /* { dg-warning "\\\[-Wattributes]" } */
A (0, fnone, alloc_size (2)); /* { dg-warning "\\\[-Wattributes]" } */
A (0, int, alloc_size (1)); /* { dg-warning ".alloc_size. attribute only applies to function types" } */
int i = 1;
A (0, i, alloc_size (1)); /* { dg-warning ".alloc_size. attribute only applies to function types" } */
A (0, faligned_8, aligned (i)); /* { dg-error "alignment is not an integer constant" } */
typedef ATTR ((aligned (2))) char CA2;
b = has_attr (CA2[2], aligned); /* { dg-error "alignment of array elements is greater than element size" } */
}
/* Verify that defining a type in __builtin_has_attribute triggers
the expected -Wc++-compat warning and evaluates as expected.
Also verify that the expression in __builtin_has_attribute is
not evaluated.
{ dg-do run }
{ dg-options "-O2 -Wall -Wc++-compat" } */
#define ATTR(list) __attribute__ (list)
#define A(expect, sym, attr) \
typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
int nfails;
#define assert(expr) \
((expr) \
? (void)0 \
: (__builtin_printf ("Assertion failed on line %i: %s\n", \
__LINE__, #expr), \
++nfails))
A (0, struct A { int i; }, aligned); /* { dg-warning "expression is invalid in C\\\+\\\+" } */
A (1, struct ATTR ((aligned)) B { int i; }, aligned); /* { dg-warning "expression is invalid in C\\\+\\\+" } */
int f (void)
{
__builtin_abort ();
}
int n = 1;
int main (void)
{
assert (0 == __builtin_has_attribute (int[n++], aligned));
assert (1 == __builtin_has_attribute (ATTR ((aligned)) int[n++], aligned));
assert (1 == __builtin_has_attribute (ATTR ((aligned)) int[f ()], aligned));
assert (1 == 1);
if (nfails)
__builtin_abort ();
return 0;
}
/* Verify __builtin_has_attribute return value for i386 function attributes.
{ dg-do compile }
{ dg-options "-Wall -ftrack-macro-expansion=0" }
{ dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
#define A(expect, sym, attr) \
typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
void fnone (void);
ATTR (interrupt) void finterrupt (void*);
ATTR (interrupt, naked) void fnaked_interrupt (void*);
A (0, fnone, interrupt);
A (1, finterrupt, interrupt);
A (1, fnaked_interrupt, interrupt);
A (1, fnaked_interrupt, naked);
ATTR (naked) void fnaked (void);
A (0, fnone, naked);
A (1, fnaked, naked);
ATTR (no_caller_saved_registers) void fnsr (int);
A (0, fnone, no_caller_saved_registers);
A (1, fnsr, no_caller_saved_registers);
ATTR (target ("abm")) void ftarget_abm (void);
ATTR (target ("mmx")) void ftarget_mmx (void);
ATTR (target ("mmx"), target ("sse")) void ftarget_mmx_sse (void);
A (0, fnone, target);
A (0, fnone, target ("abm"));
A (0, fnone, target ("mmx"));
A (1, ftarget_abm, target);
A (0, ftarget_abm, target ("no-abm"));
A (1, ftarget_abm, target ("abm"));
A (1, ftarget_mmx, target);
A (0, ftarget_mmx, target ("no-mmx"));
A (1, ftarget_mmx, target ("mmx"));
A (1, ftarget_mmx_sse, target);
A (0, ftarget_mmx_sse, target ("no-mmx"));
A (1, ftarget_mmx_sse, target ("mmx"));
A (1, ftarget_mmx_sse, target ("sse"));
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