diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 660 |
1 files changed, 584 insertions, 76 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index baaa809..07f76e3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1197,13 +1197,13 @@ static cp_declarator *make_call_declarator static cp_declarator *make_array_declarator (cp_declarator *, tree); static cp_declarator *make_pointer_declarator - (cp_cv_quals, cp_declarator *); + (cp_cv_quals, cp_declarator *, tree); static cp_declarator *make_reference_declarator - (cp_cv_quals, cp_declarator *, bool); + (cp_cv_quals, cp_declarator *, bool, tree); static cp_parameter_declarator *make_parameter_declarator (cp_decl_specifier_seq *, cp_declarator *, tree); static cp_declarator *make_ptrmem_declarator - (cp_cv_quals, tree, cp_declarator *); + (cp_cv_quals, tree, cp_declarator *, tree); /* An erroneous declarator. */ static cp_declarator *cp_error_declarator; @@ -1231,6 +1231,7 @@ make_declarator (cp_declarator_kind kind) declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator)); declarator->kind = kind; declarator->attributes = NULL_TREE; + declarator->std_attributes = NULL_TREE; declarator->declarator = NULL; declarator->parameter_pack_p = false; declarator->id_loc = UNKNOWN_LOCATION; @@ -1277,10 +1278,12 @@ make_id_declarator (tree qualifying_scope, tree unqualified_name, /* Make a declarator for a pointer to TARGET. CV_QUALIFIERS is a list of modifiers such as const or volatile to apply to the pointer - type, represented as identifiers. */ + type, represented as identifiers. ATTRIBUTES represent the attributes that + appertain to the pointer or reference. */ cp_declarator * -make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target) +make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target, + tree attributes) { cp_declarator *declarator; @@ -1297,14 +1300,18 @@ make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target) else declarator->parameter_pack_p = false; + declarator->std_attributes = attributes; + return declarator; } -/* Like make_pointer_declarator -- but for references. */ +/* Like make_pointer_declarator -- but for references. ATTRIBUTES + represent the attributes that appertain to the pointer or + reference. */ cp_declarator * make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target, - bool rvalue_ref) + bool rvalue_ref, tree attributes) { cp_declarator *declarator; @@ -1321,15 +1328,19 @@ make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target, else declarator->parameter_pack_p = false; + declarator->std_attributes = attributes; + return declarator; } /* Like make_pointer_declarator -- but for a pointer to a non-static - member of CLASS_TYPE. */ + member of CLASS_TYPE. ATTRIBUTES represent the attributes that + appertain to the pointer or reference. */ cp_declarator * make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type, - cp_declarator *pointee) + cp_declarator *pointee, + tree attributes) { cp_declarator *declarator; @@ -1346,6 +1357,8 @@ make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type, else declarator->parameter_pack_p = false; + declarator->std_attributes = attributes; + return declarator; } @@ -1853,7 +1866,7 @@ static void cp_parser_lambda_body static void cp_parser_statement (cp_parser *, tree, bool, bool *); static void cp_parser_label_for_labeled_statement - (cp_parser *); +(cp_parser *, tree); static tree cp_parser_expression_statement (cp_parser *, tree); static tree cp_parser_compound_statement @@ -1957,7 +1970,7 @@ static cp_declarator *cp_parser_declarator static cp_declarator *cp_parser_direct_declarator (cp_parser *, cp_parser_declarator_kind, int *, bool); static enum tree_code cp_parser_ptr_operator - (cp_parser *, tree *, cp_cv_quals *); + (cp_parser *, tree *, cp_cv_quals *, tree *); static cp_cv_quals cp_parser_cv_qualifier_seq_opt (cp_parser *); static cp_virt_specifiers cp_parser_virt_specifier_seq_opt @@ -2099,9 +2112,29 @@ static tree cp_parser_asm_clobber_list (cp_parser *); static tree cp_parser_asm_label_list (cp_parser *); +static bool cp_next_tokens_can_be_attribute_p + (cp_parser *); +static bool cp_next_tokens_can_be_gnu_attribute_p + (cp_parser *); +static bool cp_next_tokens_can_be_std_attribute_p + (cp_parser *); +static bool cp_nth_tokens_can_be_std_attribute_p + (cp_parser *, size_t); +static bool cp_nth_tokens_can_be_gnu_attribute_p + (cp_parser *, size_t); +static bool cp_nth_tokens_can_be_attribute_p + (cp_parser *, size_t); static tree cp_parser_attributes_opt (cp_parser *); -static tree cp_parser_attribute_list +static tree cp_parser_gnu_attributes_opt + (cp_parser *); +static tree cp_parser_gnu_attribute_list + (cp_parser *); +static tree cp_parser_std_attribute + (cp_parser *); +static tree cp_parser_std_attribute_spec + (cp_parser *); +static tree cp_parser_std_attribute_spec_seq (cp_parser *); static bool cp_parser_extension_opt (cp_parser *, int *); @@ -2308,7 +2341,7 @@ static bool cp_parser_is_keyword static tree cp_parser_make_typename_type (cp_parser *, tree, tree, location_t location); static cp_declarator * cp_parser_make_indirect_declarator - (enum tree_code, tree, cp_cv_quals, cp_declarator *); + (enum tree_code, tree, cp_cv_quals, cp_declarator *, tree); /* Returns nonzero if we are parsing tentatively. */ @@ -3178,24 +3211,30 @@ cp_parser_make_typename_type (cp_parser *parser, tree scope, make_{pointer,ptrmem,reference}_declarator functions that decides which one to call based on the CODE and CLASS_TYPE arguments. The CODE argument should be one of the values returned by - cp_parser_ptr_operator. */ + cp_parser_ptr_operator. ATTRIBUTES represent the attributes that + appertain to the pointer or reference. */ + static cp_declarator * cp_parser_make_indirect_declarator (enum tree_code code, tree class_type, cp_cv_quals cv_qualifiers, - cp_declarator *target) + cp_declarator *target, + tree attributes) { if (code == ERROR_MARK) return cp_error_declarator; if (code == INDIRECT_REF) if (class_type == NULL_TREE) - return make_pointer_declarator (cv_qualifiers, target); + return make_pointer_declarator (cv_qualifiers, target, attributes); else - return make_ptrmem_declarator (cv_qualifiers, class_type, target); + return make_ptrmem_declarator (cv_qualifiers, class_type, + target, attributes); else if (code == ADDR_EXPR && class_type == NULL_TREE) - return make_reference_declarator (cv_qualifiers, target, false); + return make_reference_declarator (cv_qualifiers, target, + false, attributes); else if (code == NON_LVALUE_EXPR && class_type == NULL_TREE) - return make_reference_declarator (cv_qualifiers, target, true); + return make_reference_declarator (cv_qualifiers, target, + true, attributes); gcc_unreachable (); } @@ -5605,6 +5644,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, switch (token->type) { case CPP_OPEN_SQUARE: + if (cp_next_tokens_can_be_std_attribute_p (parser)) + { + cp_parser_error (parser, + "two consecutive %<[%> shall " + "only introduce an attribute"); + return error_mark_node; + } postfix_expression = cp_parser_postfix_open_square_expression (parser, postfix_expression, @@ -6873,13 +6919,13 @@ static cp_declarator * cp_parser_new_declarator_opt (cp_parser* parser) { enum tree_code code; - tree type; - cp_cv_quals cv_quals; + tree type, std_attributes = NULL_TREE; + cp_cv_quals cv_quals; /* We don't know if there's a ptr-operator next, or not. */ cp_parser_parse_tentatively (parser); /* Look for a ptr-operator. */ - code = cp_parser_ptr_operator (parser, &type, &cv_quals); + code = cp_parser_ptr_operator (parser, &type, &cv_quals, &std_attributes); /* If that worked, look for more new-declarators. */ if (cp_parser_parse_definitely (parser)) { @@ -6888,8 +6934,10 @@ cp_parser_new_declarator_opt (cp_parser* parser) /* Parse another optional declarator. */ declarator = cp_parser_new_declarator_opt (parser); - return cp_parser_make_indirect_declarator - (code, type, cv_quals, declarator); + declarator = cp_parser_make_indirect_declarator + (code, type, cv_quals, declarator, std_attributes); + + return declarator; } /* If the next token is a `[', there is a direct-new-declarator. */ @@ -8628,6 +8676,18 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) declaration-statement try-block + C++11: + + statement: + labeled-statement + attribute-specifier-seq (opt) expression-statement + attribute-specifier-seq (opt) compound-statement + attribute-specifier-seq (opt) selection-statement + attribute-specifier-seq (opt) iteration-statement + attribute-specifier-seq (opt) jump-statement + declaration-statement + attribute-specifier-seq (opt) try-block + TM Extension: statement: @@ -8644,15 +8704,20 @@ static void cp_parser_statement (cp_parser* parser, tree in_statement_expr, bool in_compound, bool *if_p) { - tree statement; + tree statement, std_attrs = NULL_TREE; cp_token *token; - location_t statement_location; + location_t statement_location, attrs_location; restart: if (if_p != NULL) *if_p = false; /* There is no statement yet. */ statement = NULL_TREE; + + cp_lexer_save_tokens (parser->lexer); + attrs_location = cp_lexer_peek_token (parser->lexer)->location; + std_attrs = cp_parser_std_attribute_spec_seq (parser); + /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ @@ -8670,7 +8735,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Looks like a labeled-statement with a case label. Parse the label, and then use tail recursion to parse the statement. */ - cp_parser_label_for_labeled_statement (parser); + cp_parser_label_for_labeled_statement (parser, std_attrs); goto restart; case RID_IF: @@ -8733,7 +8798,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Looks like a labeled-statement with an ordinary label. Parse the label, and then use tail recursion to parse the statement. */ - cp_parser_label_for_labeled_statement (parser); + + cp_parser_label_for_labeled_statement (parser, std_attrs); goto restart; } } @@ -8769,6 +8835,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, { if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { + if (std_attrs != NULL_TREE) + { + /* Attributes should be parsed as part of the the + declaration, so let's un-parse them. */ + cp_lexer_rollback_tokens (parser->lexer); + std_attrs = NULL_TREE; + } + cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); @@ -8783,6 +8857,13 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Set the line number for the statement. */ if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) SET_EXPR_LOCATION (statement, statement_location); + + /* Note that for now, we don't do anything with c++11 statements + parsed at this level. */ + if (std_attrs != NULL_TREE) + warning_at (attrs_location, + OPT_Wattributes, + "attributes at the beginning of statement are ignored"); } /* Parse the label for a labeled-statement, i.e. @@ -8799,7 +8880,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, have to return the label. */ static void -cp_parser_label_for_labeled_statement (cp_parser* parser) +cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) { cp_token *token; tree label = NULL_TREE; @@ -8879,21 +8960,23 @@ cp_parser_label_for_labeled_statement (cp_parser* parser) lab: __attribute__ ((unused)) int i; we want the attribute to attach to "i", not "lab". */ if (label != NULL_TREE - && cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + && cp_next_tokens_can_be_gnu_attribute_p (parser)) { tree attrs; - cp_parser_parse_tentatively (parser); - attrs = cp_parser_attributes_opt (parser); + attrs = cp_parser_gnu_attributes_opt (parser); if (attrs == NULL_TREE || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) cp_parser_abort_tentative_parse (parser); else if (!cp_parser_parse_definitely (parser)) ; else - cplus_decl_attributes (&label, attrs, 0); + attributes = chainon (attributes, attrs); } + if (attributes != NULL_TREE) + cplus_decl_attributes (&label, attributes, 0); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; } @@ -10319,8 +10402,7 @@ cp_parser_block_declaration (cp_parser *parser, else if (cxx_dialect >= cxx0x && token2->type == CPP_NAME && ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) - || (cp_lexer_peek_nth_token (parser->lexer, 3)->keyword - == RID_ATTRIBUTE))) + || (cp_nth_tokens_can_be_attribute_p (parser, 3)))) cp_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else @@ -10550,6 +10632,7 @@ cp_parser_simple_declaration (cp_parser* parser, decl-specifier-seq: decl-specifier-seq [opt] decl-specifier + decl-specifier attribute-specifier-seq [opt] (C++11) decl-specifier: storage-class-specifier @@ -10584,6 +10667,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, int* declares_class_or_enum) { bool constructor_possible_p = !parser->in_declarator_p; + bool found_decl_spec = false; cp_token *start_token = NULL; cp_decl_spec ds; @@ -10597,7 +10681,6 @@ cp_parser_decl_specifier_seq (cp_parser* parser, while (true) { bool constructor_p; - bool found_decl_spec; cp_token *token; ds = ds_last; @@ -10609,12 +10692,55 @@ cp_parser_decl_specifier_seq (cp_parser* parser, if (!start_token) start_token = token; /* Handle attributes. */ - if (token->keyword == RID_ATTRIBUTE) + if (cp_next_tokens_can_be_attribute_p (parser)) { /* Parse the attributes. */ - decl_specs->attributes - = chainon (decl_specs->attributes, - cp_parser_attributes_opt (parser)); + tree attrs = cp_parser_attributes_opt (parser); + + /* In a sequence of declaration specifiers, c++11 attributes + appertain to the type that precede them. In that case + [dcl.spec]/1 says: + + The attribute-specifier-seq affects the type only for + the declaration it appears in, not other declarations + involving the same type. + + But for now let's force the user to position the + attribute either at the beginning of the declaration or + after the declarator-id, which would clearly mean that it + applies to the declarator. */ + if (cxx11_attribute_p (attrs)) + { + if (!found_decl_spec) + /* The c++11 attribute is at the beginning of the + declaration. It appertains to the entity being + declared. */; + else + { + if (decl_specs->type && CLASS_TYPE_P (decl_specs->type)) + { + /* This is an attribute following a + class-specifier. */ + if (decl_specs->type_definition_p) + warn_misplaced_attr_for_class_type (token->location, + decl_specs->type); + attrs = NULL_TREE; + } + else + { + decl_specs->std_attributes + = chainon (decl_specs->std_attributes, + attrs); + if (decl_specs->locations[ds_std_attribute] == 0) + decl_specs->locations[ds_std_attribute] = token->location; + } + continue; + } + } + + decl_specs->attributes + = chainon (decl_specs->attributes, + attrs); if (decl_specs->locations[ds_attribute] == 0) decl_specs->locations[ds_attribute] = token->location; continue; @@ -11341,13 +11467,14 @@ static cp_declarator * cp_parser_conversion_declarator_opt (cp_parser* parser) { enum tree_code code; - tree class_type; + tree class_type, std_attributes = NULL_TREE; cp_cv_quals cv_quals; /* We don't know if there's a ptr-operator next, or not. */ cp_parser_parse_tentatively (parser); /* Try the ptr-operator. */ - code = cp_parser_ptr_operator (parser, &class_type, &cv_quals); + code = cp_parser_ptr_operator (parser, &class_type, &cv_quals, + &std_attributes); /* If it worked, look for more conversion-declarators. */ if (cp_parser_parse_definitely (parser)) { @@ -11356,8 +11483,10 @@ cp_parser_conversion_declarator_opt (cp_parser* parser) /* Parse another optional declarator. */ declarator = cp_parser_conversion_declarator_opt (parser); - return cp_parser_make_indirect_declarator - (code, class_type, cv_quals, declarator); + declarator = cp_parser_make_indirect_declarator + (code, class_type, cv_quals, declarator, std_attributes); + + return declarator; } return NULL; @@ -13188,7 +13317,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) { tree type; - type = check_tag_decl (&decl_specifiers); + type = check_tag_decl (&decl_specifiers, + /*explicit_type_instantiation_p=*/true); /* Turn access control back on for names used during template instantiation. */ pop_deferring_access_checks (); @@ -14619,7 +14749,7 @@ cp_parser_enum_specifier (cp_parser* parser) apply them if appropriate. */ if (cp_parser_allow_gnu_extensions_p (parser)) { - tree trailing_attr = cp_parser_attributes_opt (parser); + tree trailing_attr = cp_parser_gnu_attributes_opt (parser); trailing_attr = chainon (trailing_attr, attributes); cplus_decl_attributes (&type, trailing_attr, @@ -15521,7 +15651,7 @@ cp_parser_init_declarator (cp_parser* parser, *attributes_start_token = NULL; cp_declarator *declarator; tree prefix_attributes; - tree attributes; + tree attributes = NULL; tree asm_specification; tree initializer; tree decl = NULL_TREE; @@ -15587,22 +15717,20 @@ cp_parser_init_declarator (cp_parser* parser, decl_specifiers->type = maybe_update_decl_type (decl_specifiers->type, scope); - /* If we're allowing GNU extensions, look for an asm-specification - and attributes. */ + /* If we're allowing GNU extensions, look for an + asm-specification. */ if (cp_parser_allow_gnu_extensions_p (parser)) { /* Look for an asm-specification. */ asm_spec_start_token = cp_lexer_peek_token (parser->lexer); asm_specification = cp_parser_asm_specification_opt (parser); - /* And attributes. */ - attributes_start_token = cp_lexer_peek_token (parser->lexer); - attributes = cp_parser_attributes_opt (parser); } else - { - asm_specification = NULL_TREE; - attributes = NULL_TREE; - } + asm_specification = NULL_TREE; + + /* Look for attributes. */ + attributes_start_token = cp_lexer_peek_token (parser->lexer); + attributes = cp_parser_attributes_opt (parser); /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -15931,7 +16059,7 @@ cp_parser_declarator (cp_parser* parser, enum tree_code code; cp_cv_quals cv_quals; tree class_type; - tree attributes = NULL_TREE; + tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE; /* Assume this is not a constructor, destructor, or type-conversion operator. */ @@ -15939,14 +16067,16 @@ cp_parser_declarator (cp_parser* parser, *ctor_dtor_or_conv_p = 0; if (cp_parser_allow_gnu_extensions_p (parser)) - attributes = cp_parser_attributes_opt (parser); + gnu_attributes = cp_parser_gnu_attributes_opt (parser); /* Check for the ptr-operator production. */ cp_parser_parse_tentatively (parser); /* Parse the ptr-operator. */ code = cp_parser_ptr_operator (parser, &class_type, - &cv_quals); + &cv_quals, + &std_attributes); + /* If that worked, then we have a ptr-operator. */ if (cp_parser_parse_definitely (parser)) { @@ -15972,7 +16102,7 @@ cp_parser_declarator (cp_parser* parser, declarator = NULL; declarator = cp_parser_make_indirect_declarator - (code, class_type, cv_quals, declarator); + (code, class_type, cv_quals, declarator, std_attributes); } /* Everything else is a direct-declarator. */ else @@ -15985,9 +16115,8 @@ cp_parser_declarator (cp_parser* parser, member_p); } - if (attributes && declarator && declarator != cp_error_declarator) - declarator->attributes = attributes; - + if (gnu_attributes && declarator && declarator != cp_error_declarator) + declarator->attributes = gnu_attributes; return declarator; } @@ -16127,6 +16256,7 @@ cp_parser_direct_declarator (cp_parser* parser, cp_virt_specifiers virt_specifiers; tree exception_specification; tree late_return; + tree attrs; is_declarator = true; @@ -16140,6 +16270,8 @@ cp_parser_direct_declarator (cp_parser* parser, exception_specification = cp_parser_exception_specification_opt (parser); + attrs = cp_parser_std_attribute_spec_seq (parser); + late_return = (cp_parser_late_return_type_opt (parser, member_p ? cv_quals : -1)); @@ -16153,6 +16285,7 @@ cp_parser_direct_declarator (cp_parser* parser, virt_specifiers, exception_specification, late_return); + declarator->std_attributes = attrs; /* Any subsequent parameter lists are to do with return type, so are not those of the declared function. */ @@ -16202,10 +16335,11 @@ cp_parser_direct_declarator (cp_parser* parser, break; } else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED) - && token->type == CPP_OPEN_SQUARE) + && token->type == CPP_OPEN_SQUARE + && !cp_next_tokens_can_be_attribute_p (parser)) { /* Parse an array-declarator. */ - tree bounds; + tree bounds, attrs; if (ctor_dtor_or_conv_p) *ctor_dtor_or_conv_p = 0; @@ -16258,13 +16392,16 @@ cp_parser_direct_declarator (cp_parser* parser, break; } + attrs = cp_parser_std_attribute_spec_seq (parser); declarator = make_array_declarator (declarator, bounds); + declarator->std_attributes = attrs; } else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) { { tree qualifying_scope; tree unqualified_name; + tree attrs; special_function_kind sfk; bool abstract_ok; bool pack_expansion_p = false; @@ -16331,6 +16468,8 @@ cp_parser_direct_declarator (cp_parser* parser, break; } + attrs = cp_parser_std_attribute_spec_seq (parser); + if (qualifying_scope && at_namespace_scope_p () && TREE_CODE (qualifying_scope) == TYPENAME_TYPE) { @@ -16445,6 +16584,7 @@ cp_parser_direct_declarator (cp_parser* parser, declarator = make_id_declarator (qualifying_scope, unqualified_name, sfk); + declarator->std_attributes = attrs; declarator->id_loc = token->location; declarator->parameter_pack_p = pack_expansion_p; @@ -16492,9 +16632,11 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse a ptr-operator. ptr-operator: + * attribute-specifier-seq [opt] cv-qualifier-seq [opt] (C++11) * cv-qualifier-seq [opt] & :: [opt] nested-name-specifier * cv-qualifier-seq [opt] + nested-name-specifier * attribute-specifier-seq [opt] cv-qualifier-seq [opt] (C++11) GNU Extension: @@ -16514,10 +16656,12 @@ cp_parser_direct_declarator (cp_parser* parser, static enum tree_code cp_parser_ptr_operator (cp_parser* parser, tree* type, - cp_cv_quals *cv_quals) + cp_cv_quals *cv_quals, + tree *attributes) { enum tree_code code = ERROR_MARK; cp_token *token; + tree attrs = NULL_TREE; /* Assume that it's not a pointer-to-member. */ *type = NULL_TREE; @@ -16548,6 +16692,10 @@ cp_parser_ptr_operator (cp_parser* parser, if (code == INDIRECT_REF || cp_parser_allow_gnu_extensions_p (parser)) *cv_quals = cp_parser_cv_qualifier_seq_opt (parser); + + attrs = cp_parser_std_attribute_spec_seq (parser); + if (attributes != NULL) + *attributes = attrs; } else { @@ -16585,6 +16733,10 @@ cp_parser_ptr_operator (cp_parser* parser, parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + /* Look for optional c++11 attributes. */ + attrs = cp_parser_std_attribute_spec_seq (parser); + if (attributes != NULL) + *attributes = attrs; /* Look for the optional cv-qualifier-seq. */ *cv_quals = cp_parser_cv_qualifier_seq_opt (parser); } @@ -16944,7 +17096,7 @@ cp_parser_type_specifier_seq (cp_parser* parser, bool is_cv_qualifier; /* Check for attributes first. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + if (cp_next_tokens_can_be_attribute_p (parser)) { type_specifier_seq->attributes = chainon (type_specifier_seq->attributes, @@ -18050,7 +18202,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) closing_brace = cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); /* Look for trailing attributes to apply to this class. */ if (cp_parser_allow_gnu_extensions_p (parser)) - attributes = cp_parser_attributes_opt (parser); + attributes = cp_parser_gnu_attributes_opt (parser); if (type != error_mark_node) type = finish_struct (type, attributes); if (nested_name_specifier_p) @@ -18071,6 +18223,12 @@ cp_parser_class_specifier_1 (cp_parser* parser) cp_token *token = cp_lexer_peek_token (parser->lexer); bool want_semicolon = true; + if (cp_next_tokens_can_be_std_attribute_p (parser)) + /* Don't try to parse c++11 attributes here. As per the + grammar, that should be a task for + cp_parser_decl_specifier_seq. */ + want_semicolon = false; + switch (token->type) { case CPP_NAME: @@ -18921,8 +19079,6 @@ cp_parser_member_declaration (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); - prefix_attributes = decl_specifiers.attributes; - decl_specifiers.attributes = NULL_TREE; /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -18954,7 +19110,8 @@ cp_parser_member_declaration (cp_parser* parser) friend_p = cp_parser_friend_p (&decl_specifiers); /* If there were decl-specifiers, check to see if there was a class-declaration. */ - type = check_tag_decl (&decl_specifiers); + type = check_tag_decl (&decl_specifiers, + /*explicit_type_instantiation_p=*/false); /* Nested classes have already been added to the class, but a `friend' needs to be explicitly registered. */ if (friend_p) @@ -19021,6 +19178,12 @@ cp_parser_member_declaration (cp_parser* parser) { bool assume_semicolon = false; + /* Clear attributes from the decl_specifiers but keep them + around as prefix attributes that apply them to the entity + being declared. */ + prefix_attributes = decl_specifiers.attributes; + decl_specifiers.attributes = NULL_TREE; + /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -20127,6 +20290,80 @@ cp_parser_asm_label_list (cp_parser* parser) return nreverse (labels); } +/* Return TRUE iff the next tokens in the stream are possibly the + beginning of a GNU extension attribute. */ + +static bool +cp_next_tokens_can_be_gnu_attribute_p (cp_parser *parser) +{ + return cp_nth_tokens_can_be_gnu_attribute_p (parser, 1); +} + +/* Return TRUE iff the next tokens in the stream are possibly the + beginning of a standard C++-11 attribute. */ + +static bool +cp_next_tokens_can_be_std_attribute_p (cp_parser *parser) +{ + return cp_nth_tokens_can_be_std_attribute_p (parser, 1); +} + +/* Return TRUE iff the next Nth tokens in the stream are possibly the + beginning of a standard C++-11 attribute. */ + +static bool +cp_nth_tokens_can_be_std_attribute_p (cp_parser *parser, size_t n) +{ + cp_token *token = cp_lexer_peek_nth_token (parser->lexer, n); + + return (cxx_dialect >= cxx0x + && token->type == CPP_OPEN_SQUARE + && (token = cp_lexer_peek_nth_token (parser->lexer, n + 1)) + && token->type == CPP_OPEN_SQUARE); +} + +/* Return TRUE iff the next Nth tokens in the stream are possibly the + beginning of a GNU extension attribute. */ + +static bool +cp_nth_tokens_can_be_gnu_attribute_p (cp_parser *parser, size_t n) +{ + cp_token *token = cp_lexer_peek_nth_token (parser->lexer, n); + + return token->type == CPP_KEYWORD && token->keyword == RID_ATTRIBUTE; +} + +/* Return true iff the next tokens can be the beginning of either a + GNU attribute list, or a standard C++11 attribute sequence. */ + +static bool +cp_next_tokens_can_be_attribute_p (cp_parser *parser) +{ + return (cp_next_tokens_can_be_gnu_attribute_p (parser) + || cp_next_tokens_can_be_std_attribute_p (parser)); +} + +/* Return true iff the next Nth tokens can be the beginning of either + a GNU attribute list, or a standard C++11 attribute sequence. */ + +static bool +cp_nth_tokens_can_be_attribute_p (cp_parser *parser, size_t n) +{ + return (cp_nth_tokens_can_be_gnu_attribute_p (parser, n) + || cp_nth_tokens_can_be_std_attribute_p (parser, n)); +} + +/* Parse either a standard C++-11 attribute-specifier-seq, or a series + of GNU attributes, or return NULL. */ + +static tree +cp_parser_attributes_opt (cp_parser *parser) +{ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + return cp_parser_gnu_attributes_opt (parser); + return cp_parser_std_attribute_spec_seq (parser); +} + /* Parse an (optional) series of attributes. attributes: @@ -20135,10 +20372,10 @@ cp_parser_asm_label_list (cp_parser* parser) attribute: __attribute__ (( attribute-list [opt] )) - The return value is as for cp_parser_attribute_list. */ + The return value is as for cp_parser_gnu_attribute_list. */ static tree -cp_parser_attributes_opt (cp_parser* parser) +cp_parser_gnu_attributes_opt (cp_parser* parser) { tree attributes = NULL_TREE; @@ -20164,7 +20401,7 @@ cp_parser_attributes_opt (cp_parser* parser) token = cp_lexer_peek_token (parser->lexer); if (token->type != CPP_CLOSE_PAREN) /* Parse the attribute-list. */ - attribute_list = cp_parser_attribute_list (parser); + attribute_list = cp_parser_gnu_attribute_list (parser); else /* If the next token is a `)', then there is no attribute list. */ @@ -20185,7 +20422,7 @@ cp_parser_attributes_opt (cp_parser* parser) return attributes; } -/* Parse an attribute-list. +/* Parse a GNU attribute-list. attribute-list: attribute @@ -20203,7 +20440,7 @@ cp_parser_attributes_opt (cp_parser* parser) the arguments, if any. */ static tree -cp_parser_attribute_list (cp_parser* parser) +cp_parser_gnu_attribute_list (cp_parser* parser) { tree attribute_list = NULL_TREE; bool save_translate_strings_p = parser->translate_strings_p; @@ -20282,6 +20519,277 @@ cp_parser_attribute_list (cp_parser* parser) return nreverse (attribute_list); } +/* Parse a standard C++11 attribute. + + The returned representation is a TREE_LIST which TREE_PURPOSE is + the scoped name of the attribute, and the TREE_VALUE is its + arguments list. + + Note that the scoped name of the attribute is itself a TREE_LIST + which TREE_PURPOSE is the namespace of the attribute, and + TREE_VALUE its name. This is unlike a GNU attribute -- as parsed + by cp_parser_gnu_attribute_list -- that doesn't have any namespace + and which TREE_PURPOSE is directly the attribute name. + + Clients of the attribute code should use get_attribute_namespace + and get_attribute_name to get the actual namespace and name of + attributes, regardless of their being GNU or C++11 attributes. + + attribute: + attribute-token attribute-argument-clause [opt] + + attribute-token: + identifier + attribute-scoped-token + + attribute-scoped-token: + attribute-namespace :: identifier + + attribute-namespace: + identifier + + attribute-argument-clause: + ( balanced-token-seq ) + + balanced-token-seq: + balanced-token [opt] + balanced-token-seq balanced-token + + balanced-token: + ( balanced-token-seq ) + [ balanced-token-seq ] + { balanced-token-seq }. */ + +static tree +cp_parser_std_attribute (cp_parser *parser) +{ + tree attribute, attr_ns = NULL_TREE, attr_id = NULL_TREE, arguments; + cp_token *token; + + /* First, parse name of the the attribute, a.k.a + attribute-token. */ + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME) + attr_id = token->u.value; + else if (token->type == CPP_KEYWORD) + attr_id = ridpointers[(int) token->keyword]; + else if (token->flags & NAMED_OP) + attr_id = get_identifier (cpp_type2name (token->type, token->flags)); + + if (attr_id == NULL_TREE) + return NULL_TREE; + + cp_lexer_consume_token (parser->lexer); + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_SCOPE) + { + /* We are seeing a scoped attribute token. */ + + cp_lexer_consume_token (parser->lexer); + attr_ns = attr_id; + + token = cp_lexer_consume_token (parser->lexer); + if (token->type == CPP_NAME) + attr_id = token->u.value; + else if (token->type == CPP_KEYWORD) + attr_id = ridpointers[(int) token->keyword]; + else + { + error_at (token->location, + "expected an identifier for the attribute name"); + return error_mark_node; + } + attribute = build_tree_list (build_tree_list (attr_ns, attr_id), + NULL_TREE); + token = cp_lexer_peek_token (parser->lexer); + } + else + attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id), + NULL_TREE); + + /* Now parse the optional argument clause of the attribute. */ + + if (token->type != CPP_OPEN_PAREN) + return attribute; + + { + VEC(tree, gc) *vec; + int attr_flag = normal_attr; + + if (attr_ns == get_identifier ("gnu") + && attribute_takes_identifier_p (attr_id)) + /* A GNU attribute that takes an identifier in parameter. */ + attr_flag = id_attr; + + vec = cp_parser_parenthesized_expression_list + (parser, attr_flag, /*cast_p=*/false, + /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL); + if (vec == NULL) + arguments = error_mark_node; + else + { + arguments = build_tree_list_vec (vec); + release_tree_vector (vec); + } + + if (arguments == error_mark_node) + attribute = error_mark_node; + else + TREE_VALUE (attribute) = arguments; + } + + return attribute; +} + +/* Parse a list of standard C++-11 attributes. + + attribute-list: + attribute [opt] + attribute-list , attribute[opt] + attribute ... + attribute-list , attribute ... +*/ + +static tree +cp_parser_std_attribute_list (cp_parser *parser) +{ + tree attributes = NULL_TREE, attribute = NULL_TREE; + cp_token *token = NULL; + + while (true) + { + attribute = cp_parser_std_attribute (parser); + if (attribute == error_mark_node) + break; + if (attribute != NULL_TREE) + { + TREE_CHAIN (attribute) = attributes; + attributes = attribute; + } + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_COMMA) + break; + cp_lexer_consume_token (parser->lexer); + } + attributes = nreverse (attributes); + return attributes; +} + +/* Parse a standard C++-11 attribute specifier. + + attribute-specifier: + [ [ attribute-list ] ] + alignment-specifier + + alignment-specifier: + alignas ( type-id ... [opt] ) + alignas ( alignment-expression ... [opt] ). */ + +static tree +cp_parser_std_attribute_spec (cp_parser *parser) +{ + tree attributes = NULL_TREE; + cp_token *token = cp_lexer_peek_token (parser->lexer); + + if (token->type == CPP_OPEN_SQUARE + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE) + { + cp_lexer_consume_token (parser->lexer); + maybe_warn_cpp0x (CPP0X_ATTRIBUTES); + cp_lexer_consume_token (parser->lexer); + + attributes = cp_parser_std_attribute_list (parser); + + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE) + || !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) + cp_parser_skip_to_end_of_statement (parser); + } + else + { + tree alignas_expr; + + /* Look for an alignment-specifier. */ + + token = cp_lexer_peek_token (parser->lexer); + + if (token->type != CPP_KEYWORD + || token->keyword != RID_ALIGNAS) + return NULL_TREE; + + cp_lexer_consume_token (parser->lexer); + maybe_warn_cpp0x (CPP0X_ATTRIBUTES); + + if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN) == NULL) + { + cp_parser_error (parser, "expected %<(%>"); + return error_mark_node; + } + + cp_parser_parse_tentatively (parser); + alignas_expr = cp_parser_type_id (parser); + + if (!cp_parser_parse_definitely (parser)) + { + gcc_assert (alignas_expr == error_mark_node + || alignas_expr == NULL_TREE); + + alignas_expr = + cp_parser_assignment_expression (parser, /*cast_p=*/false, + /**cp_id_kind=*/NULL); + if (alignas_expr == NULL_TREE + || alignas_expr == error_mark_node) + return alignas_expr; + } + + if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) == NULL) + { + cp_parser_error (parser, "expected %<)%>"); + return error_mark_node; + } + + alignas_expr = cxx_alignas_expr (alignas_expr); + + /* Build the C++-11 representation of an 'aligned' + attribute. */ + attributes = + build_tree_list (build_tree_list (get_identifier ("gnu"), + get_identifier ("aligned")), + build_tree_list (NULL_TREE, alignas_expr)); + } + + return attributes; +} + +/* Parse a standard C++-11 attribute-specifier-seq. + + attribute-specifier-seq: + attribute-specifier-seq [opt] attribute-specifier + */ + +static tree +cp_parser_std_attribute_spec_seq (cp_parser *parser) +{ + tree attr_specs = NULL; + + while (true) + { + tree attr_spec = cp_parser_std_attribute_spec (parser); + if (attr_spec == NULL_TREE) + break; + if (attr_spec == error_mark_node) + return error_mark_node; + + TREE_CHAIN (attr_spec) = attr_specs; + attr_specs = attr_spec; + } + + attr_specs = nreverse (attr_specs); + return attr_specs; +} + /* Parse an optional `__extension__' keyword. Returns TRUE if it is present, and FALSE otherwise. *SAVED_PEDANTIC is set to the current value of the PEDANTIC flag, regardless of whether or not |