aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-11-21 02:50:02 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-11-20 19:50:02 -0700
commit98f08eb8939735c1e9cbc1ec5cadebe79e935c90 (patch)
tree9fb2084c7e170349abee1d8f950047936556b98a /gcc
parent48d1f31d1b7131e8f809ede8256e4f1eb6c5c3ae (diff)
downloadgcc-98f08eb8939735c1e9cbc1ec5cadebe79e935c90.zip
gcc-98f08eb8939735c1e9cbc1ec5cadebe79e935c90.tar.gz
gcc-98f08eb8939735c1e9cbc1ec5cadebe79e935c90.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/c-family/ChangeLog11
-rw-r--r--gcc/c-family/c-attribs.c2
-rw-r--r--gcc/c-family/c-common.c1
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/c/ChangeLog7
-rw-r--r--gcc/c/c-parser.c340
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl2.c2
-rw-r--r--gcc/cp/parser.c130
-rw-r--r--gcc/doc/extend.texi41
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/c-c++-common/builtin-has-attribute-2.c206
-rw-r--r--gcc/testsuite/c-c++-common/builtin-has-attribute-3.c314
-rw-r--r--gcc/testsuite/c-c++-common/builtin-has-attribute-4.c285
-rw-r--r--gcc/testsuite/c-c++-common/builtin-has-attribute.c60
-rw-r--r--gcc/testsuite/gcc.dg/builtin-has-attribute.c45
-rw-r--r--gcc/testsuite/gcc.target/i386/builtin-has-attribute.c54
19 files changed, 1426 insertions, 96 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3075648..229e1b0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+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
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index db46542..6d60cf0 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,14 @@
+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.
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 88b24cd..373381d 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -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);
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 4034b64..9d51815 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4aa6142..4187343 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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 {
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 706839c..0b73df9 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,10 @@
+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
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 5f69e9d..afc4071 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1445,6 +1445,8 @@ static vec<tree, va_gc> *c_parser_expr_list (c_parser *, bool, bool,
vec<tree, va_gc> **, location_t *,
tree *, vec<location_t> *,
unsigned int * = NULL);
+static struct c_expr c_parser_has_attribute_expression (c_parser *);
+
static void c_parser_oacc_declare (c_parser *);
static void c_parser_oacc_enter_exit_data (c_parser *, bool);
static void c_parser_oacc_update (c_parser *);
@@ -4313,7 +4315,126 @@ c_parser_attribute_any_word (c_parser *parser)
type), a reserved word storage class specifier, type specifier or
type qualifier. ??? This still leaves out most reserved keywords
(following the old parser), shouldn't we include them, and why not
- allow identifiers declared as types to start the arguments? */
+ allow identifiers declared as types to start the arguments?
+ When EXPECT_COMMA is true, expect the attribute to be preceded
+ by a comma and fail if it isn't.
+ When EMPTY_OK is true, allow and consume any number of consecutive
+ commas with no attributes in between. */
+
+static tree
+c_parser_attribute (c_parser *parser, tree attrs,
+ bool expect_comma = false, bool empty_ok = true)
+{
+ bool comma_first = c_parser_next_token_is (parser, CPP_COMMA);
+ if (!comma_first
+ && !c_parser_next_token_is (parser, CPP_NAME)
+ && !c_parser_next_token_is (parser, CPP_KEYWORD))
+ return NULL_TREE;
+
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ if (!empty_ok)
+ return attrs;
+ }
+
+ tree attr_name = c_parser_attribute_any_word (parser);
+ if (attr_name == NULL_TREE)
+ return NULL_TREE;
+
+ attr_name = canonicalize_attr_name (attr_name);
+ c_parser_consume_token (parser);
+
+ tree attr;
+ if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+ {
+ if (expect_comma && !comma_first)
+ {
+ /* A comma is missing between the last attribute on the chain
+ and this one. */
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+ attr = build_tree_list (attr_name, NULL_TREE);
+ /* Add this attribute to the list. */
+ attrs = chainon (attrs, attr);
+ return attrs;
+ }
+ c_parser_consume_token (parser);
+
+ vec<tree, va_gc> *expr_list;
+ tree attr_args;
+ /* Parse the attribute contents. If they start with an
+ identifier which is followed by a comma or close
+ parenthesis, then the arguments start with that
+ identifier; otherwise they are an expression list.
+ In objective-c the identifier may be a classname. */
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+ || (c_dialect_objc ()
+ && c_parser_peek_token (parser)->id_kind
+ == C_ID_CLASSNAME))
+ && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+ || (c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN))
+ && (attribute_takes_identifier_p (attr_name)
+ || (c_dialect_objc ()
+ && c_parser_peek_token (parser)->id_kind
+ == C_ID_CLASSNAME)))
+ {
+ tree arg1 = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ attr_args = build_tree_list (NULL_TREE, arg1);
+ else
+ {
+ tree tree_list;
+ c_parser_consume_token (parser);
+ expr_list = c_parser_expr_list (parser, false, true,
+ NULL, NULL, NULL, NULL);
+ tree_list = build_tree_list_vec (expr_list);
+ attr_args = tree_cons (NULL_TREE, arg1, tree_list);
+ release_tree_vector (expr_list);
+ }
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ attr_args = NULL_TREE;
+ else
+ {
+ expr_list = c_parser_expr_list (parser, false, true,
+ NULL, NULL, NULL, NULL);
+ attr_args = build_tree_list_vec (expr_list);
+ release_tree_vector (expr_list);
+ }
+ }
+
+ attr = build_tree_list (attr_name, attr_args);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ parser->lex_untranslated_string = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+
+ if (expect_comma && !comma_first)
+ {
+ /* A comma is missing between the last attribute on the chain
+ and this one. */
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+
+ /* Add this attribute to the list. */
+ attrs = chainon (attrs, attr);
+ return attrs;
+}
static tree
c_parser_attributes (c_parser *parser)
@@ -4338,97 +4459,19 @@ c_parser_attributes (c_parser *parser)
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
return attrs;
}
- /* Parse the attribute list. */
- while (c_parser_next_token_is (parser, CPP_COMMA)
- || c_parser_next_token_is (parser, CPP_NAME)
- || c_parser_next_token_is (parser, CPP_KEYWORD))
+ /* Parse the attribute list. Require a comma between successive
+ (possibly empty) attributes. */
+ for (bool expect_comma = false; ; expect_comma = true)
{
- tree attr, attr_name, attr_args;
- vec<tree, va_gc> *expr_list;
- if (c_parser_next_token_is (parser, CPP_COMMA))
- {
- c_parser_consume_token (parser);
- continue;
- }
-
- attr_name = c_parser_attribute_any_word (parser);
- if (attr_name == NULL)
+ /* Parse a single attribute. */
+ tree attr = c_parser_attribute (parser, attrs, expect_comma);
+ if (attr == error_mark_node)
+ return attrs;
+ if (!attr)
break;
- attr_name = canonicalize_attr_name (attr_name);
- c_parser_consume_token (parser);
- if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
- {
- attr = build_tree_list (attr_name, NULL_TREE);
- /* Add this attribute to the list. */
- attrs = chainon (attrs, attr);
- /* If the next token isn't a comma, we're done. */
- if (!c_parser_next_token_is (parser, CPP_COMMA))
- break;
- continue;
- }
- c_parser_consume_token (parser);
- /* Parse the attribute contents. If they start with an
- identifier which is followed by a comma or close
- parenthesis, then the arguments start with that
- identifier; otherwise they are an expression list.
- In objective-c the identifier may be a classname. */
- if (c_parser_next_token_is (parser, CPP_NAME)
- && (c_parser_peek_token (parser)->id_kind == C_ID_ID
- || (c_dialect_objc ()
- && c_parser_peek_token (parser)->id_kind
- == C_ID_CLASSNAME))
- && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
- || (c_parser_peek_2nd_token (parser)->type
- == CPP_CLOSE_PAREN))
- && (attribute_takes_identifier_p (attr_name)
- || (c_dialect_objc ()
- && c_parser_peek_token (parser)->id_kind
- == C_ID_CLASSNAME)))
- {
- tree arg1 = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- attr_args = build_tree_list (NULL_TREE, arg1);
- else
- {
- tree tree_list;
- c_parser_consume_token (parser);
- expr_list = c_parser_expr_list (parser, false, true,
- NULL, NULL, NULL, NULL);
- tree_list = build_tree_list_vec (expr_list);
- attr_args = tree_cons (NULL_TREE, arg1, tree_list);
- release_tree_vector (expr_list);
- }
- }
- else
- {
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- attr_args = NULL_TREE;
- else
- {
- expr_list = c_parser_expr_list (parser, false, true,
- NULL, NULL, NULL, NULL);
- attr_args = build_tree_list_vec (expr_list);
- release_tree_vector (expr_list);
- }
- }
+ attrs = attr;
+ }
- attr = build_tree_list (attr_name, attr_args);
- if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
- c_parser_consume_token (parser);
- else
- {
- parser->lex_untranslated_string = false;
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
- "expected %<)%>");
- return attrs;
- }
- /* Add this attribute to the list. */
- attrs = chainon (attrs, attr);
- /* If the next token isn't a comma, we're done. */
- if (!c_parser_next_token_is (parser, CPP_COMMA))
- break;
- }
/* Look for the two `)' tokens. */
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
c_parser_consume_token (parser);
@@ -7263,6 +7306,8 @@ c_parser_unary_expression (c_parser *parser)
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
return c_parser_alignof_expression (parser);
+ case RID_BUILTIN_HAS_ATTRIBUTE:
+ return c_parser_has_attribute_expression (parser);
case RID_EXTENSION:
c_parser_consume_token (parser);
ext = disable_extension_diagnostics ();
@@ -7462,6 +7507,123 @@ c_parser_alignof_expression (c_parser *parser)
}
}
+/* Parse the __builtin_has_attribute ([expr|type], attribute-spec)
+ expression. */
+
+static struct c_expr
+c_parser_has_attribute_expression (c_parser *parser)
+{
+ gcc_assert (c_parser_next_token_is_keyword (parser,
+ RID_BUILTIN_HAS_ATTRIBUTE));
+ c_parser_consume_token (parser);
+
+ c_inhibit_evaluation_warnings++;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+
+ struct c_expr result;
+ result.set_error ();
+ result.original_code = ERROR_MARK;
+ result.original_type = NULL;
+ return result;
+ }
+
+ /* Treat the type argument the same way as in typeof for the purposes
+ of warnings. FIXME: Generalize this so the warning refers to
+ __builtin_has_attribute rather than typeof. */
+ in_typeof++;
+
+ /* The first operand: one of DECL, EXPR, or TYPE. */
+ tree oper = NULL_TREE;
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+ {
+ struct c_type_name *tname = c_parser_type_name (parser);
+ in_typeof--;
+ if (tname)
+ {
+ oper = groktypename (tname, NULL, NULL);
+ pop_maybe_used (variably_modified_type_p (oper, NULL_TREE));
+ }
+ }
+ else
+ {
+ struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL);
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+ if (cexpr.value != error_mark_node)
+ {
+ mark_exp_read (cexpr.value);
+ oper = cexpr.value;
+ tree etype = TREE_TYPE (oper);
+ bool was_vm = variably_modified_type_p (etype, NULL_TREE);
+ /* This is returned with the type so that when the type is
+ evaluated, this can be evaluated. */
+ if (was_vm)
+ oper = c_fully_fold (oper, false, NULL);
+ pop_maybe_used (was_vm);
+ }
+ }
+
+ struct c_expr result;
+ result.original_code = ERROR_MARK;
+ result.original_type = NULL;
+
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ /* Consume the closing parenthesis if that's the next token
+ in the likely case the built-in was invoked with fewer
+ than two arguments. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ c_inhibit_evaluation_warnings--;
+ result.set_error ();
+ return result;
+ }
+
+ parser->lex_untranslated_string = true;
+
+ location_t atloc = c_parser_peek_token (parser)->location;
+ /* Parse a single attribute. Require no leading comma and do not
+ allow empty attributes. */
+ tree attr = c_parser_attribute (parser, NULL_TREE, false, false);
+
+ parser->lex_untranslated_string = false;
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+
+ result.set_error ();
+ return result;
+ }
+
+ if (!attr)
+ {
+ error_at (atloc, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ result.set_error ();
+ return result;
+ }
+
+ result.original_code = INTEGER_CST;
+ result.original_type = boolean_type_node;
+
+ if (has_attribute (atloc, oper, attr, default_conversion))
+ result.value = boolean_true_node;
+ else
+ result.value = boolean_false_node;
+
+ return result;
+}
+
/* Helper function to read arguments of builtins which are interfaces
for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and
others. The name of the builtin is passed using BNAME parameter.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a5ee86e..a8e0544 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index edb9494..111a123 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 7686a90..ffc0d0d 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 292cce1..0617f56 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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. */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0dff5e8..858b2d1 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d3ebbf0..43831fc 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+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
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-2.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-2.c
new file mode 100644
index 0000000..0f692ff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-2.c
@@ -0,0 +1,206 @@
+/* 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);
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-3.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-3.c
new file mode 100644
index 0000000..237dc72
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-3.c
@@ -0,0 +1,314 @@
+/* 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" } */
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
new file mode 100644
index 0000000..14bdd3f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
@@ -0,0 +1,285 @@
+/* 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" } */
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute.c b/gcc/testsuite/c-c++-common/builtin-has-attribute.c
new file mode 100644
index 0000000..67c792f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-has-attribute.c
@@ -0,0 +1,60 @@
+/* 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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-has-attribute.c b/gcc/testsuite/gcc.dg/builtin-has-attribute.c
new file mode 100644
index 0000000..8c11cf8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-has-attribute.c
@@ -0,0 +1,45 @@
+/* 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;
+}
diff --git a/gcc/testsuite/gcc.target/i386/builtin-has-attribute.c b/gcc/testsuite/gcc.target/i386/builtin-has-attribute.c
new file mode 100644
index 0000000..2de1ba3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-has-attribute.c
@@ -0,0 +1,54 @@
+/* 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"));