diff options
author | Martin Sebor <msebor@redhat.com> | 2018-11-21 02:50:02 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2018-11-20 19:50:02 -0700 |
commit | 98f08eb8939735c1e9cbc1ec5cadebe79e935c90 (patch) | |
tree | 9fb2084c7e170349abee1d8f950047936556b98a /gcc/c/c-parser.c | |
parent | 48d1f31d1b7131e8f809ede8256e4f1eb6c5c3ae (diff) | |
download | gcc-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/c/c-parser.c')
-rw-r--r-- | gcc/c/c-parser.c | 340 |
1 files changed, 251 insertions, 89 deletions
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. |