X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcp%2Fparser.c;h=4c853552f4f4e67d2dea621e9d4b72d953b73540;hb=8272c334a859bc3bfcdcc99218fc88004ffaadcf;hp=811b2faf32e0f0f0dafeb06c987c4e98b8fecd3f;hpb=4d6f53f47cd008d01308c1f051a91aa3e629b541;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 811b2faf32e..4c853552f4f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -106,7 +106,9 @@ typedef enum non_integral_constant { /* a comma operator */ NIC_COMMA, /* a call to a constructor */ - NIC_CONSTRUCTOR + NIC_CONSTRUCTOR, + /* a transaction expression */ + NIC_TRANSACTION } non_integral_constant; /* The various kinds of errors about name-lookup failing. */ @@ -171,7 +173,10 @@ typedef enum required_token { RT_INTERATION, /* iteration-statement */ RT_JUMP, /* jump-statement */ RT_CLASS_KEY, /* class-key */ - RT_CLASS_TYPENAME_TEMPLATE /* class, typename, or template */ + RT_CLASS_TYPENAME_TEMPLATE, /* class, typename, or template */ + RT_TRANSACTION_ATOMIC, /* __transaction_atomic */ + RT_TRANSACTION_RELAXED, /* __transaction_relaxed */ + RT_TRANSACTION_CANCEL /* __transaction_cancel */ } required_token; /* Prototypes. */ @@ -1935,6 +1940,8 @@ static bool cp_parser_using_declaration (cp_parser *, bool); static void cp_parser_using_directive (cp_parser *); +static tree cp_parser_alias_declaration + (cp_parser *); static void cp_parser_asm_definition (cp_parser *); static void cp_parser_linkage_specification @@ -2104,6 +2111,17 @@ static bool cp_parser_extension_opt static void cp_parser_label_declaration (cp_parser *); +/* Transactional Memory Extensions */ + +static tree cp_parser_transaction + (cp_parser *, enum rid); +static tree cp_parser_transaction_expression + (cp_parser *, enum rid); +static bool cp_parser_function_transaction + (cp_parser *, enum rid); +static tree cp_parser_transaction_cancel + (cp_parser *); + enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; static bool cp_parser_pragma (cp_parser *, enum pragma_context); @@ -2231,6 +2249,8 @@ static void cp_parser_pre_parsed_nested_name_specifier (cp_parser *); static bool cp_parser_cache_group (cp_parser *, enum cpp_ttype, unsigned); +static tree cp_parser_cache_defarg + (cp_parser *parser, bool nsdmi); static void cp_parser_parse_tentatively (cp_parser *); static void cp_parser_commit_to_tentative_parse @@ -2509,6 +2529,7 @@ cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs, "explicit", "friend", "typedef", + "using", "constexpr", "__complex", "__thread" @@ -2668,6 +2689,10 @@ cp_parser_non_integral_constant_expression (cp_parser *parser, error ("a call to a constructor " "cannot appear in a constant-expression"); return true; + case NIC_TRANSACTION: + error ("a transaction expression " + "cannot appear in a constant-expression"); + return true; case NIC_THIS: msg = "this"; break; @@ -3524,40 +3549,79 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) return value; } +/* Look up a literal operator with the name and the exact arguments. */ + +static tree +lookup_literal_operator (tree name, VEC(tree,gc) *args) +{ + tree decl, fns; + decl = lookup_name (name); + if (!decl || !is_overloaded_fn (decl)) + return error_mark_node; + + for (fns = decl; fns; fns = OVL_NEXT (fns)) + { + unsigned int ix; + bool found = true; + tree fn = OVL_CURRENT (fns); + tree argtypes = NULL_TREE; + argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn)); + if (argtypes != NULL_TREE) + { + for (ix = 0; ix < VEC_length (tree, args) && argtypes != NULL_TREE; + ++ix, argtypes = TREE_CHAIN (argtypes)) + { + tree targ = TREE_VALUE (argtypes); + tree tparm = TREE_TYPE (VEC_index (tree, args, ix)); + bool ptr = TREE_CODE (targ) == POINTER_TYPE; + bool arr = TREE_CODE (tparm) == ARRAY_TYPE; + if ((ptr || arr || !same_type_p (targ, tparm)) + && (!ptr || !arr + || !same_type_p (TREE_TYPE (targ), + TREE_TYPE (tparm)))) + found = false; + } + if (found) + return fn; + } + } + + return error_mark_node; +} + /* Parse a user-defined char constant. Returns a call to a user-defined literal operator taking the character as an argument. */ static tree cp_parser_userdef_char_literal (cp_parser *parser) { - cp_token *token = NULL; - tree literal, suffix_id, value; - tree name, decl; - tree result; - VEC(tree,gc) *vec; - - token = cp_lexer_consume_token (parser->lexer); - literal = token->u.value; - suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); - value = USERDEF_LITERAL_VALUE (literal); - name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + cp_token *token = cp_lexer_consume_token (parser->lexer); + tree literal = token->u.value; + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); + tree value = USERDEF_LITERAL_VALUE (literal); + tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + tree decl, result; /* Build up a call to the user-defined operator */ /* Lookup the name we got back from the id-expression. */ - vec = make_tree_vector (); - VEC_safe_push (tree, gc, vec, value); - decl = lookup_function_nonclass (name, vec, /*block_p=*/false); + VEC(tree,gc) *args = make_tree_vector (); + VEC_safe_push (tree, gc, args, value); + decl = lookup_literal_operator (name, args); if (!decl || decl == error_mark_node) { - error ("unable to find user-defined character literal operator %qD", - name); - release_tree_vector (vec); + error ("unable to find character literal operator %qD with %qT argument", + name, TREE_TYPE (value)); + release_tree_vector (args); return error_mark_node; } - result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error); - release_tree_vector (vec); + result = finish_call_expr (decl, &args, false, true, tf_warning_or_error); + release_tree_vector (args); + if (result != error_mark_node) + return result; - return result; + error ("unable to find character literal operator %qD with %qT argument", + name, TREE_TYPE (value)); + return error_mark_node; } /* A subroutine of cp_parser_userdef_numeric_literal to @@ -3592,26 +3656,20 @@ make_char_string_pack (tree value) static tree cp_parser_userdef_numeric_literal (cp_parser *parser) { - cp_token *token = NULL; - tree literal, suffix_id, value, num_string; - tree name, decl; - tree result = error_mark_node; + cp_token *token = cp_lexer_consume_token (parser->lexer); + tree literal = token->u.value; + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); + tree value = USERDEF_LITERAL_VALUE (literal); + tree num_string = USERDEF_LITERAL_NUM_STRING (literal); + tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + tree decl, result; VEC(tree,gc) *args; - token = cp_lexer_consume_token (parser->lexer); - literal = token->u.value; - suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); - value = USERDEF_LITERAL_VALUE (literal); - num_string = USERDEF_LITERAL_NUM_STRING (literal); - name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); - - /* Build up a call to the user-defined operator */ - /* Lookup the name we got back from the id-expression. */ - /* Try to find the literal operator by finishing the call expression - with the numeric argument. */ + /* Look for a literal operator taking the exact type of numeric argument + as the literal value. */ args = make_tree_vector (); VEC_safe_push (tree, gc, args, value); - decl = lookup_function_nonclass (name, args, /*block_p=*/false); + decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) { result = finish_call_expr (decl, &args, false, true, tf_none); @@ -3628,7 +3686,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) in string format. */ args = make_tree_vector (); VEC_safe_push (tree, gc, args, num_string); - decl = lookup_function_nonclass (name, args, /*block_p=*/false); + decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) { result = finish_call_expr (decl, &args, false, true, tf_none); @@ -3644,7 +3702,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) function with parameter pack char.... Call the function with template parameter characters representing the number. */ args = make_tree_vector (); - decl = lookup_function_nonclass (name, args, /*block_p=*/false); + decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) { tree tmpl_args = make_char_string_pack (num_string); @@ -3658,10 +3716,8 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) } release_tree_vector (args); - if (result == error_mark_node) - error ("unable to find user-defined numeric literal operator %qD", name); - - return result; + error ("unable to find numeric literal operator %qD", name); + return error_mark_node; } /* Parse a user-defined string constant. Returns a call to a user-defined @@ -3671,38 +3727,34 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) static tree cp_parser_userdef_string_literal (cp_token *token) { - tree literal, suffix_id, value; - tree name, decl; - tree result; - VEC(tree,gc) *vec; - int len; - - literal = token->u.value; - suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); - name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); - value = USERDEF_LITERAL_VALUE (literal); - len = TREE_STRING_LENGTH (value) + tree literal = token->u.value; + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); + tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + tree value = USERDEF_LITERAL_VALUE (literal); + int len = TREE_STRING_LENGTH (value) / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1; + tree decl, result; + /* Build up a call to the user-defined operator */ /* Lookup the name we got back from the id-expression. */ - vec = make_tree_vector (); - VEC_safe_push (tree, gc, vec, value); - VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len)); - decl = lookup_function_nonclass (name, vec, /*block_p=*/false); + VEC(tree,gc) *args = make_tree_vector (); + VEC_safe_push (tree, gc, args, value); + VEC_safe_push (tree, gc, args, build_int_cst (size_type_node, len)); + decl = lookup_name (name); if (!decl || decl == error_mark_node) { - error ("unable to find user-defined string literal operator %qD", name); - release_tree_vector (vec); + error ("unable to find string literal operator %qD", name); + release_tree_vector (args); return error_mark_node; } - result = finish_call_expr (decl, &vec, false, true, tf_none); - if (result == error_mark_node) - error ("unable to find valid user-defined string literal operator %qD." - " Possible missing length argument in string literal operator.", - name); - release_tree_vector (vec); + result = finish_call_expr (decl, &args, false, true, tf_none); + release_tree_vector (args); + if (result != error_mark_node) + return result; - return result; + error ("unable to find string literal operator %qD with %qT, %qT arguments", + name, TREE_TYPE (value), size_type_node); + return error_mark_node; } @@ -3804,6 +3856,7 @@ cp_parser_translation_unit (cp_parser* parser) __is_convertible_to ( type-id , type-id ) __is_empty ( type-id ) __is_enum ( type-id ) + __is_final ( type-id ) __is_literal_type ( type-id ) __is_pod ( type-id ) __is_polymorphic ( type-id ) @@ -4149,6 +4202,7 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_CONVERTIBLE_TO: case RID_IS_EMPTY: case RID_IS_ENUM: + case RID_IS_FINAL: case RID_IS_LITERAL_TYPE: case RID_IS_POD: case RID_IS_POLYMORPHIC: @@ -5135,7 +5189,7 @@ cp_parser_nested_name_specifier (cp_parser *parser, this is either a class-name or a namespace-name (which corresponds to the class-or-namespace-name production in the grammar). For C++0x, it can also be a type-name that refers to an enumeration - type. + type or a simple-template-id. TYPENAME_KEYWORD_P is TRUE iff the `typename' keyword is in effect. TEMPLATE_KEYWORD_P is TRUE iff the `template' keyword is in effect. @@ -5211,8 +5265,8 @@ cp_parser_qualifying_entity (cp_parser *parser, /* Parse tentatively. */ cp_parser_parse_tentatively (parser); - /* Parse a typedef-name or enum-name. */ - scope = cp_parser_nonclass_name (parser); + /* Parse a type-name */ + scope = cp_parser_type_name (parser); /* "If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed." @@ -5777,6 +5831,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, by cp_parser_builtin_offsetof. We're looking for postfix-expression [ expression ] + postfix-expression [ braced-init-list ] (C++11) FOR_OFFSETOF is set if we're being called in that context, which changes how we deal with integer constant expressions. */ @@ -5802,7 +5857,16 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, if (for_offsetof) index = cp_parser_constant_expression (parser, false, NULL); else - index = cp_parser_expression (parser, /*cast_p=*/false, NULL); + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_nonconst_p; + maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); + index = cp_parser_braced_list (parser, &expr_nonconst_p); + } + else + index = cp_parser_expression (parser, /*cast_p=*/false, NULL); + } /* Look for the closing `]'. */ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); @@ -5966,17 +6030,24 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, { if (name != error_mark_node && !BASELINK_P (name) && parser->scope) { - name = build_qualified_name (/*type=*/NULL_TREE, - parser->scope, - name, - template_p); + if (TREE_CODE (parser->scope) == NAMESPACE_DECL) + { + error_at (token->location, "%<%D::%D%> is not a class member", + parser->scope, name); + postfix_expression = error_mark_node; + } + else + name = build_qualified_name (/*type=*/NULL_TREE, + parser->scope, + name, + template_p); parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; } - if (scope && name && BASELINK_P (name)) + if (parser->scope && name && BASELINK_P (name)) adjust_result_of_qualified_name_lookup - (name, BINFO_TYPE (BASELINK_ACCESS_BINFO (name)), scope); + (name, parser->scope, scope); postfix_expression = finish_class_member_access_expr (postfix_expression, name, template_p, @@ -6362,6 +6433,10 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + return cp_parser_transaction_expression (parser, keyword); + case RID_NOEXCEPT: { tree expr; @@ -6593,10 +6668,17 @@ cp_parser_new_expression (cp_parser* parser) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { cp_token *token; + const char *saved_message = parser->type_definition_forbidden_message; + /* Consume the `('. */ cp_lexer_consume_token (parser->lexer); + /* Parse the type-id. */ + parser->type_definition_forbidden_message + = G_("types may not be defined in a new-expression"); type = cp_parser_type_id (parser); + parser->type_definition_forbidden_message = saved_message; + /* Look for the closing `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); token = cp_lexer_peek_token (parser->lexer); @@ -7807,6 +7889,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_ENUM: kind = CPTK_IS_ENUM; break; + case RID_IS_FINAL: + kind = CPTK_IS_FINAL; + break; case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; @@ -7972,6 +8057,8 @@ cp_parser_lambda_expression (cp_parser* parser) cp_parser_lambda_introducer (parser, lambda_expr); type = begin_lambda_type (lambda_expr); + if (type == error_mark_node) + return error_mark_node; record_lambda_scope (lambda_expr); @@ -8496,6 +8583,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) declaration-statement try-block + TM Extension: + + statement: + atomic-statement + IN_COMPOUND is true when the statement is nested inside a cp_parser_compound_statement; this matters for certain pragmas. @@ -8572,6 +8664,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_declaration_statement (parser); return; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + statement = cp_parser_transaction (parser, keyword); + break; + case RID_TRANSACTION_CANCEL: + statement = cp_parser_transaction_cancel (parser); + break; + default: /* It might be a keyword like `int' that can start a declaration-statement. */ @@ -9245,6 +9345,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl) at instantiation. If not, it is done just ahead. */ if (processing_template_decl) { + if (check_for_bare_parameter_packs (range_expr)) + range_expr = error_mark_node; stmt = begin_range_for_stmt (scope, init); finish_range_for_decl (stmt, range_decl, range_expr); if (!type_dependent_expression_p (range_expr) @@ -9448,9 +9550,11 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) id_begin = get_identifier ("begin"); id_end = get_identifier ("end"); member_begin = lookup_member (TREE_TYPE (range), id_begin, - /*protect=*/2, /*want_type=*/false); + /*protect=*/2, /*want_type=*/false, + tf_warning_or_error); member_end = lookup_member (TREE_TYPE (range), id_end, - /*protect=*/2, /*want_type=*/false); + /*protect=*/2, /*want_type=*/false, + tf_warning_or_error); if (member_begin != NULL_TREE || member_end != NULL_TREE) { @@ -10150,8 +10254,8 @@ cp_parser_block_declaration (cp_parser *parser, namespace-alias-definition. */ else if (token1->keyword == RID_NAMESPACE) cp_parser_namespace_alias_definition (parser); - /* If the next keyword is `using', we have either a - using-declaration or a using-directive. */ + /* If the next keyword is `using', we have a + using-declaration, a using-directive, or an alias-declaration. */ else if (token1->keyword == RID_USING) { cp_token *token2; @@ -10163,6 +10267,14 @@ cp_parser_block_declaration (cp_parser *parser, token2 = cp_lexer_peek_nth_token (parser->lexer, 2); if (token2->keyword == RID_NAMESPACE) cp_parser_using_directive (parser); + /* If the second token after 'using' is '=', then we have an + alias-declaration. */ + 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_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else cp_parser_using_declaration (parser, @@ -11235,6 +11347,7 @@ static void cp_parser_mem_initializer_list (cp_parser* parser) { tree mem_initializer_list = NULL_TREE; + tree target_ctor = error_mark_node; cp_token *token = cp_lexer_peek_token (parser->lexer); /* Let the semantic analysis code know that we are starting the @@ -11272,6 +11385,27 @@ cp_parser_mem_initializer_list (cp_parser* parser) if (mem_initializer != error_mark_node) mem_initializer = make_pack_expansion (mem_initializer); } + if (target_ctor != error_mark_node + && mem_initializer != error_mark_node) + { + error ("mem-initializer for %qD follows constructor delegation", + TREE_PURPOSE (mem_initializer)); + mem_initializer = error_mark_node; + } + /* Look for a target constructor. */ + if (mem_initializer != error_mark_node + && TYPE_P (TREE_PURPOSE (mem_initializer)) + && same_type_p (TREE_PURPOSE (mem_initializer), current_class_type)) + { + maybe_warn_cpp0x (CPP0X_DELEGATING_CTORS); + if (mem_initializer_list) + { + error ("constructor delegation follows mem-initializer for %qD", + TREE_PURPOSE (mem_initializer_list)); + mem_initializer = error_mark_node; + } + target_ctor = mem_initializer; + } /* Add it to the list, unless it was erroneous. */ if (mem_initializer != error_mark_node) { @@ -12343,7 +12477,7 @@ cp_parser_template_id (cp_parser *parser, /* Build a representation of the specialization. */ if (TREE_CODE (templ) == IDENTIFIER_NODE) template_id = build_min_nt (TEMPLATE_ID_EXPR, templ, arguments); - else if (DECL_CLASS_TEMPLATE_P (templ) + else if (DECL_TYPE_TEMPLATE_P (templ) || DECL_TEMPLATE_TEMPLATE_PARM_P (templ)) { bool entering_scope; @@ -13611,6 +13745,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, class-name enum-name typedef-name + simple-template-id [in c++0x] enum-name: identifier @@ -13638,8 +13773,37 @@ cp_parser_type_name (cp_parser* parser) /* If it's not a class-name, keep looking. */ if (!cp_parser_parse_definitely (parser)) { - /* It must be a typedef-name or an enum-name. */ - return cp_parser_nonclass_name (parser); + if (cxx_dialect < cxx0x) + /* It must be a typedef-name or an enum-name. */ + return cp_parser_nonclass_name (parser); + + cp_parser_parse_tentatively (parser); + /* It is either a simple-template-id representing an + instantiation of an alias template... */ + type_decl = cp_parser_template_id (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/false, + /*is_declaration=*/false); + /* Note that this must be an instantiation of an alias template + because [temp.names]/6 says: + + A template-id that names an alias template specialization + is a type-name. + + Whereas [temp.names]/7 says: + + A simple-template-id that names a class template + specialization is a class-name. */ + if (type_decl != NULL_TREE + && TREE_CODE (type_decl) == TYPE_DECL + && TYPE_DECL_ALIAS_P (type_decl)) + gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl)); + else + cp_parser_simulate_error (parser); + + if (!cp_parser_parse_definitely (parser)) + /* ... Or a typedef-name or an enum-name. */ + return cp_parser_nonclass_name (parser); } return type_decl; @@ -13669,6 +13833,26 @@ cp_parser_nonclass_name (cp_parser* parser) /* Look up the type-name. */ type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location); + if (TREE_CODE (type_decl) == USING_DECL) + { + if (!DECL_DEPENDENT_P (type_decl)) + type_decl = strip_using_decl (type_decl); + else if (USING_DECL_TYPENAME_P (type_decl)) + { + /* We have found a type introduced by a using + declaration at class scope that refers to a dependent + type. + + using typename :: [opt] nested-name-specifier unqualified-id ; + */ + type_decl = make_typename_type (TREE_TYPE (type_decl), + DECL_NAME (type_decl), + typename_type, tf_error); + if (type_decl != error_mark_node) + type_decl = TYPE_NAME (type_decl); + } + } + if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) { @@ -13841,7 +14025,8 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, else if (tag_type == typename_type && TREE_CODE (decl) != TYPE_DECL) type = NULL_TREE; else - type = TREE_TYPE (decl); + type = check_elaborated_type_specifier (tag_type, decl, + /*allow_template_p=*/true); } if (!type) @@ -14058,6 +14243,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, enum-specifier: enum-head { enumerator-list [opt] } + enum-head { enumerator-list , } [C++0x] enum-head: enum-key identifier [opt] enum-base [opt] @@ -14077,6 +14263,8 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, GNU Extensions: enum-key attributes[opt] identifier [opt] enum-base [opt] { enumerator-list [opt] }attributes[opt] + enum-key attributes[opt] identifier [opt] enum-base [opt] + { enumerator-list, }attributes[opt] [C++0x] Returns an ENUM_TYPE representing the enumeration, or NULL_TREE if the token stream isn't an enum-specifier after all. */ @@ -14416,8 +14604,9 @@ cp_parser_enumerator_list (cp_parser* parser, tree type) /* If the next token is a `}', there is a trailing comma. */ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) { - if (!in_system_header) - pedwarn (input_location, OPT_pedantic, "comma at end of enumerator list"); + if (cxx_dialect < cxx0x && !in_system_header) + pedwarn (input_location, OPT_pedantic, + "comma at end of enumerator list"); break; } } @@ -14717,9 +14906,14 @@ cp_parser_using_declaration (cp_parser* parser, tree decl; tree identifier; tree qscope; + int oldcount = errorcount; + cp_token *diag_token = NULL; if (access_declaration_p) - cp_parser_parse_tentatively (parser); + { + diag_token = cp_lexer_peek_token (parser->lexer); + cp_parser_parse_tentatively (parser); + } else { /* Look for the `using' keyword. */ @@ -14801,9 +14995,12 @@ cp_parser_using_declaration (cp_parser* parser, /* Create the USING_DECL. */ decl = do_class_using_decl (parser->scope, identifier); + if (decl && typename_p) + USING_DECL_TYPENAME_P (decl) = 1; + if (check_for_bare_parameter_packs (decl)) return false; - else + else /* Add it to the list of members in this class. */ finish_member_declaration (decl); } @@ -14827,10 +15024,122 @@ cp_parser_using_declaration (cp_parser* parser, /* Look for the final `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - + + if (access_declaration_p && errorcount == oldcount) + warning_at (diag_token->location, OPT_Wdeprecated, + "access declarations are deprecated " + "in favour of using-declarations; " + "suggestion: add the % keyword"); + return true; } +/* Parse an alias-declaration. + + alias-declaration: + using identifier attribute-specifier-seq [opt] = type-id */ + +static tree +cp_parser_alias_declaration (cp_parser* parser) +{ + tree id, type, decl, pushed_scope = NULL_TREE, attributes; + location_t id_location; + cp_declarator *declarator; + cp_decl_specifier_seq decl_specs; + bool member_p; + const char *saved_message = NULL; + + /* Look for the `using' keyword. */ + cp_parser_require_keyword (parser, RID_USING, RT_USING); + id_location = cp_lexer_peek_token (parser->lexer)->location; + id = cp_parser_identifier (parser); + if (id == error_mark_node) + return error_mark_node; + + attributes = cp_parser_attributes_opt (parser); + if (attributes == error_mark_node) + return error_mark_node; + + cp_parser_require (parser, CPP_EQ, RT_EQ); + + /* Now we are going to parse the type-id of the declaration. */ + + /* + [dcl.type]/3 says: + + "A type-specifier-seq shall not define a class or enumeration + unless it appears in the type-id of an alias-declaration (7.1.3) that + is not the declaration of a template-declaration." + + In other words, if we currently are in an alias template, the + type-id should not define a type. + + So let's set parser->type_definition_forbidden_message in that + case; cp_parser_check_type_definition (called by + cp_parser_class_specifier) will then emit an error if a type is + defined in the type-id. */ + if (parser->num_template_parameter_lists) + { + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message = + G_("types may not be defined in alias template declarations"); + } + + type = cp_parser_type_id (parser); + + /* Restore the error message if need be. */ + if (parser->num_template_parameter_lists) + parser->type_definition_forbidden_message = saved_message; + + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + if (cp_parser_error_occurred (parser)) + return error_mark_node; + + /* A typedef-name can also be introduced by an alias-declaration. The + identifier following the using keyword becomes a typedef-name. It has + the same semantics as if it were introduced by the typedef + specifier. In particular, it does not define a new type and it shall + not appear in the type-id. */ + + clear_decl_specs (&decl_specs); + decl_specs.type = type; + decl_specs.attributes = attributes; + ++decl_specs.specs[(int) ds_typedef]; + ++decl_specs.specs[(int) ds_alias]; + + declarator = make_id_declarator (NULL_TREE, id, sfk_none); + declarator->id_loc = id_location; + + member_p = at_class_scope_p (); + if (member_p) + decl = grokfield (declarator, &decl_specs, NULL_TREE, false, + NULL_TREE, attributes); + else + decl = start_decl (declarator, &decl_specs, 0, + attributes, NULL_TREE, &pushed_scope); + if (decl == error_mark_node) + return decl; + + cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0); + + if (pushed_scope) + pop_scope (pushed_scope); + + /* If decl is a template, return its TEMPLATE_DECL so that it gets + added into the symbol table; otherwise, return the TYPE_DECL. */ + if (DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))) + { + decl = DECL_TI_TEMPLATE (decl); + if (member_p) + check_member_template (decl); + } + + return decl; +} + /* Parse a using-directive. using-directive: @@ -15082,6 +15391,11 @@ cp_parser_asm_definition (cp_parser* parser) function-definition: __extension__ function-definition + TM Extension: + + function-definition: + decl-specifier-seq [opt] declarator function-transaction-block + The DECL_SPECIFIERS apply to this declarator. Returns a representation of the entity declared. If MEMBER_P is TRUE, then this declarator appears in a class scope. The new DECL created by @@ -15410,8 +15724,7 @@ cp_parser_init_declarator (cp_parser* parser, { /* We want to record the extra mangling scope for in-class initializers of class members and initializers of static data - member templates. The former is a C++0x feature which isn't - implemented yet, and I expect it will involve deferring + member templates. The former involves deferring parsing of the initializer until end of class as with default arguments. So right here we only handle the latter. */ if (!member_p && processing_template_decl) @@ -15826,18 +16139,20 @@ cp_parser_direct_declarator (cp_parser* parser, &non_constant_p); if (!non_constant_p) /* OK */; - /* Normally, the array bound must be an integral constant - expression. However, as an extension, we allow VLAs - in function scopes as long as they aren't part of a - parameter declaration. */ + else if (error_operand_p (bounds)) + /* Already gave an error. */; else if (!parser->in_function_body || current_binding_level->kind == sk_function_parms) { + /* Normally, the array bound must be an integral constant + expression. However, as an extension, we allow VLAs + in function scopes as long as they aren't part of a + parameter declaration. */ cp_parser_error (parser, "array bound is not an integer constant"); bounds = error_mark_node; } - else if (processing_template_decl && !error_operand_p (bounds)) + else if (processing_template_decl) { /* Remember this wasn't a constant-expression. */ bounds = build_nop (TREE_TYPE (bounds), bounds); @@ -16168,6 +16483,9 @@ cp_parser_ptr_operator (cp_parser* parser, if (TREE_CODE (parser->scope) == NAMESPACE_DECL) error_at (token->location, "%qD is a namespace", parser->scope); + else if (TREE_CODE (parser->scope) == ENUMERAL_TYPE) + error_at (token->location, "cannot form pointer to member of " + "non-class %q#T", parser->scope); else { /* The type of which the member is a member is given by the @@ -16973,159 +17291,18 @@ cp_parser_parameter_declaration (cp_parser *parser, /* If the next token is `=', then process a default argument. */ if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) { + token = cp_lexer_peek_token (parser->lexer); /* If we are defining a class, then the tokens that make up the default argument must be saved and processed later. */ if (!template_parm_p && at_class_scope_p () && TYPE_BEING_DEFINED (current_class_type) && !LAMBDA_TYPE_P (current_class_type)) - { - unsigned depth = 0; - int maybe_template_id = 0; - cp_token *first_token; - cp_token *token; - - /* Add tokens until we have processed the entire default - argument. We add the range [first_token, token). */ - first_token = cp_lexer_peek_token (parser->lexer); - while (true) - { - bool done = false; - - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); - /* What we do depends on what token we have. */ - switch (token->type) - { - /* In valid code, a default argument must be - immediately followed by a `,' `)', or `...'. */ - case CPP_COMMA: - if (depth == 0 && maybe_template_id) - { - /* If we've seen a '<', we might be in a - template-argument-list. Until Core issue 325 is - resolved, we don't know how this situation ought - to be handled, so try to DTRT. We check whether - what comes after the comma is a valid parameter - declaration list. If it is, then the comma ends - the default argument; otherwise the default - argument continues. */ - bool error = false; - tree t; - - /* Set ITALP so cp_parser_parameter_declaration_list - doesn't decide to commit to this parse. */ - bool saved_italp = parser->in_template_argument_list_p; - parser->in_template_argument_list_p = true; - - cp_parser_parse_tentatively (parser); - cp_lexer_consume_token (parser->lexer); - begin_scope (sk_function_parms, NULL_TREE); - cp_parser_parameter_declaration_list (parser, &error); - for (t = current_binding_level->names; t; t = DECL_CHAIN (t)) - pop_binding (DECL_NAME (t), t); - leave_scope (); - if (!cp_parser_error_occurred (parser) && !error) - done = true; - cp_parser_abort_tentative_parse (parser); - - parser->in_template_argument_list_p = saved_italp; - break; - } - case CPP_CLOSE_PAREN: - case CPP_ELLIPSIS: - /* If we run into a non-nested `;', `}', or `]', - then the code is invalid -- but the default - argument is certainly over. */ - case CPP_SEMICOLON: - case CPP_CLOSE_BRACE: - case CPP_CLOSE_SQUARE: - if (depth == 0) - done = true; - /* Update DEPTH, if necessary. */ - else if (token->type == CPP_CLOSE_PAREN - || token->type == CPP_CLOSE_BRACE - || token->type == CPP_CLOSE_SQUARE) - --depth; - break; - - case CPP_OPEN_PAREN: - case CPP_OPEN_SQUARE: - case CPP_OPEN_BRACE: - ++depth; - break; - - case CPP_LESS: - if (depth == 0) - /* This might be the comparison operator, or it might - start a template argument list. */ - ++maybe_template_id; - break; - - case CPP_RSHIFT: - if (cxx_dialect == cxx98) - break; - /* Fall through for C++0x, which treats the `>>' - operator like two `>' tokens in certain - cases. */ - - case CPP_GREATER: - if (depth == 0) - { - /* This might be an operator, or it might close a - template argument list. But if a previous '<' - started a template argument list, this will have - closed it, so we can't be in one anymore. */ - maybe_template_id -= 1 + (token->type == CPP_RSHIFT); - if (maybe_template_id < 0) - maybe_template_id = 0; - } - break; - - /* If we run out of tokens, issue an error message. */ - case CPP_EOF: - case CPP_PRAGMA_EOL: - error_at (token->location, "file ends in default argument"); - done = true; - break; - - case CPP_NAME: - case CPP_SCOPE: - /* In these cases, we should look for template-ids. - For example, if the default argument is - `X()', we need to do name lookup to - figure out whether or not `X' is a template; if - so, the `,' does not end the default argument. - - That is not yet done. */ - break; - - default: - break; - } - - /* If we've reached the end, stop. */ - if (done) - break; - - /* Add the token to the token block. */ - token = cp_lexer_consume_token (parser->lexer); - } - - /* Create a DEFAULT_ARG to represent the unparsed default - argument. */ - default_argument = make_node (DEFAULT_ARG); - DEFARG_TOKENS (default_argument) - = cp_token_cache_new (first_token, token); - DEFARG_INSTANTIATIONS (default_argument) = NULL; - } + default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false); /* Outside of a class definition, we can just parse the assignment-expression. */ else - { - token = cp_lexer_peek_token (parser->lexer); - default_argument - = cp_parser_default_argument (parser, template_parm_p); - } + default_argument + = cp_parser_default_argument (parser, template_parm_p); if (!parser->default_arg_ok_p) { @@ -17478,10 +17655,14 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) && !c_dialect_objc () && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) { + /* In C++11, [ could start a lambda-introducer. */ + cp_parser_parse_tentatively (parser); cp_lexer_consume_token (parser->lexer); designator = cp_parser_constant_expression (parser, false, NULL); cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); cp_parser_require (parser, CPP_EQ, RT_EQ); + if (!cp_parser_parse_definitely (parser)) + designator = NULL_TREE; } else designator = NULL_TREE; @@ -18528,6 +18709,7 @@ cp_parser_member_specification_opt (cp_parser* parser) :: [opt] nested-name-specifier template [opt] unqualified-id ; using-declaration template-declaration + alias-declaration member-declarator-list: member-declarator @@ -18595,10 +18777,25 @@ cp_parser_member_declaration (cp_parser* parser) /* Check for a using-declaration. */ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) { - /* Parse the using-declaration. */ - cp_parser_using_declaration (parser, - /*access_declaration_p=*/false); - return; + if (cxx_dialect < cxx0x) + { + /* Parse the using-declaration. */ + cp_parser_using_declaration (parser, + /*access_declaration_p=*/false); + return; + } + else + { + tree decl; + cp_parser_parse_tentatively (parser); + decl = cp_parser_alias_declaration (parser); + if (cp_parser_parse_definitely (parser)) + finish_member_declaration (decl); + else + cp_parser_using_declaration (parser, + /*access_declaration_p=*/false); + return; + } } /* Check for @defs. */ @@ -18627,7 +18824,7 @@ cp_parser_member_declaration (cp_parser* parser) parser->colon_corrects_to_scope_p = false; if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) - goto out; + goto out; /* Parse the decl-specifier-seq. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); @@ -19291,19 +19488,25 @@ cp_parser_base_specifier (cp_parser* parser) /* Exception handling [gram.exception] */ -/* Parse an (optional) exception-specification. +/* Parse an (optional) noexcept-specification. - exception-specification: - throw ( type-id-list [opt] ) + noexcept-specification: + noexcept ( constant-expression ) [opt] - Returns a TREE_LIST representing the exception-specification. The - TREE_VALUE of each node is a type. */ + If no noexcept-specification is present, returns NULL_TREE. + Otherwise, if REQUIRE_CONSTEXPR is false, then either parse and return any + expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if + there are no parentheses. CONSUMED_EXPR will be set accordingly. + Otherwise, returns a noexcept specification unless RETURN_COND is true, + in which case a boolean condition is returned instead. */ static tree -cp_parser_exception_specification_opt (cp_parser* parser) +cp_parser_noexcept_specification_opt (cp_parser* parser, + bool require_constexpr, + bool* consumed_expr, + bool return_cond) { cp_token *token; - tree type_id_list; const char *saved_message; /* Peek at the next token. */ @@ -19319,23 +19522,67 @@ cp_parser_exception_specification_opt (cp_parser* parser) { cp_lexer_consume_token (parser->lexer); - /* Types may not be defined in an exception-specification. */ - saved_message = parser->type_definition_forbidden_message; - parser->type_definition_forbidden_message - = G_("types may not be defined in an exception-specification"); + if (require_constexpr) + { + /* Types may not be defined in an exception-specification. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = G_("types may not be defined in an exception-specification"); - expr = cp_parser_constant_expression (parser, false, NULL); + expr = cp_parser_constant_expression (parser, false, NULL); - /* Restore the saved message. */ - parser->type_definition_forbidden_message = saved_message; + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + } + else + { + expr = cp_parser_expression (parser, false, NULL); + *consumed_expr = true; + } cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); } else - expr = boolean_true_node; + { + expr = boolean_true_node; + if (!require_constexpr) + *consumed_expr = false; + } - return build_noexcept_spec (expr, tf_warning_or_error); + /* We cannot build a noexcept-spec right away because this will check + that expr is a constexpr. */ + if (!return_cond) + return build_noexcept_spec (expr, tf_warning_or_error); + else + return expr; } + else + return NULL_TREE; +} + +/* Parse an (optional) exception-specification. + + exception-specification: + throw ( type-id-list [opt] ) + + Returns a TREE_LIST representing the exception-specification. The + TREE_VALUE of each node is a type. */ + +static tree +cp_parser_exception_specification_opt (cp_parser* parser) +{ + cp_token *token; + tree type_id_list; + const char *saved_message; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* Is it a noexcept-specification? */ + type_id_list = cp_parser_noexcept_specification_opt(parser, true, NULL, + false); + if (type_id_list != NULL_TREE) + return type_id_list; /* If it's not `throw', then there's no exception-specification. */ if (!cp_parser_is_keyword (token, RID_THROW)) @@ -20217,7 +20464,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name, object_decl = lookup_member (object_type, name, /*protect=*/0, - tag_type != none_type); + tag_type != none_type, + tf_warning_or_error); /* Look it up in the enclosing context, too. */ decl = lookup_name_real (name, tag_type != none_type, /*nonclass=*/0, @@ -20780,12 +21028,19 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, start_lambda_scope (current_function_decl); - /* If the next token is `try', then we are looking at a - function-try-block. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) + /* If the next token is `try', `__transaction_atomic', or + `__transaction_relaxed`, then we are looking at either function-try-block + or function-transaction-block. Note that all of these include the + function-body. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_ATOMIC)) + ctor_initializer_p = cp_parser_function_transaction (parser, + RID_TRANSACTION_ATOMIC); + else if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_TRANSACTION_RELAXED)) + ctor_initializer_p = cp_parser_function_transaction (parser, + RID_TRANSACTION_RELAXED); + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) ctor_initializer_p = cp_parser_function_try_block (parser); - /* A function-try-block includes the function-body, so we only do - this next part if we're not processing a function-try-block. */ else ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body (parser); @@ -20889,6 +21144,9 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) cp_parser_template_declaration_after_export (parser, member_p); + else if (cxx_dialect >= cxx0x + && cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) + decl = cp_parser_alias_declaration (parser); else { /* There are no access checks when parsing a template, as we do not @@ -21255,25 +21513,9 @@ cp_parser_save_member_function_body (cp_parser* parser, static tree cp_parser_save_nsdmi (cp_parser* parser) { - /* Save away the tokens that make up the body of the - function. */ - cp_token *first = parser->lexer->next_token; - cp_token *last; - tree node; - - /* Save tokens until the next comma or semicolon. */ - cp_parser_cache_group (parser, CPP_COMMA, /*depth=*/0); - - last = parser->lexer->next_token; - - node = make_node (DEFAULT_ARG); - DEFARG_TOKENS (node) = cp_token_cache_new (first, last); - DEFARG_INSTANTIATIONS (node) = NULL; - - return node; + return cp_parser_cache_defarg (parser, /*nsdmi=*/true); } - /* Parse a template-argument-list, as well as the trailing ">" (but not the opening "<"). See cp_parser_template_argument_list for the return value. */ @@ -21492,6 +21734,9 @@ cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl, tree parsed_arg; bool dummy; + if (default_arg == error_mark_node) + return error_mark_node; + /* Push the saved tokens for the default argument onto the parser's lexer stack. */ tokens = DEFARG_TOKENS (default_arg); @@ -21939,6 +22184,12 @@ cp_parser_required_error (cp_parser *parser, case RT_AT_THROW: cp_parser_error (parser, "expected %<@throw%>"); return; + case RT_TRANSACTION_ATOMIC: + cp_parser_error (parser, "expected %<__transaction_atomic%>"); + return; + case RT_TRANSACTION_RELAXED: + cp_parser_error (parser, "expected %<__transaction_relaxed%>"); + return; default: break; } @@ -22169,6 +22420,10 @@ cp_parser_token_starts_function_definition_p (cp_token* token) || token->type == CPP_COLON /* A function-try-block begins with `try'. */ || token->keyword == RID_TRY + /* A function-transaction-block begins with `__transaction_atomic' + or `__transaction_relaxed'. */ + || token->keyword == RID_TRANSACTION_ATOMIC + || token->keyword == RID_TRANSACTION_RELAXED /* The named return value extension begins with `return'. */ || token->keyword == RID_RETURN); } @@ -22250,11 +22505,17 @@ cp_parser_token_is_class_key (cp_token* token) static void cp_parser_check_class_key (enum tag_types class_key, tree type) { + if (type == error_mark_node) + return; if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type)) - permerror (input_location, "%qs tag used in naming %q#T", - class_key == union_type ? "union" - : class_key == record_type ? "struct" : "class", - type); + { + permerror (input_location, "%qs tag used in naming %q#T", + class_key == union_type ? "union" + : class_key == record_type ? "struct" : "class", + type); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)), + "%q#T was previously declared here", type); + } } /* Issue an error message if DECL is redeclared with different @@ -22364,12 +22625,6 @@ cp_parser_cache_group (cp_parser *parser, kind of syntax error. */ return true; - /* If we're caching something finished by a comma (or semicolon), - such as an NSDMI, don't consume the comma. */ - if (end == CPP_COMMA - && (token->type == CPP_SEMICOLON || token->type == CPP_COMMA)) - return false; - /* Consume the token. */ cp_lexer_consume_token (parser->lexer); /* See if it starts a new group. */ @@ -22395,6 +22650,178 @@ cp_parser_cache_group (cp_parser *parser, } } +/* Like above, for caching a default argument or NSDMI. Both of these are + terminated by a non-nested comma, but it can be unclear whether or not a + comma is nested in a template argument list unless we do more parsing. + In order to handle this ambiguity, when we encounter a ',' after a '<' + we try to parse what follows as a parameter-declaration-list (in the + case of a default argument) or a member-declarator (in the case of an + NSDMI). If that succeeds, then we stop caching. */ + +static tree +cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) +{ + unsigned depth = 0; + int maybe_template_id = 0; + cp_token *first_token; + cp_token *token; + tree default_argument; + + /* Add tokens until we have processed the entire default + argument. We add the range [first_token, token). */ + first_token = cp_lexer_peek_token (parser->lexer); + if (first_token->type == CPP_OPEN_BRACE) + { + /* For list-initialization, this is straightforward. */ + cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0); + token = cp_lexer_peek_token (parser->lexer); + } + else while (true) + { + bool done = false; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* What we do depends on what token we have. */ + switch (token->type) + { + /* In valid code, a default argument must be + immediately followed by a `,' `)', or `...'. */ + case CPP_COMMA: + if (depth == 0 && maybe_template_id) + { + /* If we've seen a '<', we might be in a + template-argument-list. Until Core issue 325 is + resolved, we don't know how this situation ought + to be handled, so try to DTRT. We check whether + what comes after the comma is a valid parameter + declaration list. If it is, then the comma ends + the default argument; otherwise the default + argument continues. */ + bool error = false; + tree t; + + /* Set ITALP so cp_parser_parameter_declaration_list + doesn't decide to commit to this parse. */ + bool saved_italp = parser->in_template_argument_list_p; + parser->in_template_argument_list_p = true; + + cp_parser_parse_tentatively (parser); + cp_lexer_consume_token (parser->lexer); + + if (nsdmi) + { + int ctor_dtor_or_conv_p; + cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + &ctor_dtor_or_conv_p, + /*parenthesized_p=*/NULL, + /*member_p=*/true); + } + else + { + begin_scope (sk_function_parms, NULL_TREE); + cp_parser_parameter_declaration_list (parser, &error); + for (t = current_binding_level->names; t; t = DECL_CHAIN (t)) + pop_binding (DECL_NAME (t), t); + leave_scope (); + } + if (!cp_parser_error_occurred (parser) && !error) + done = true; + cp_parser_abort_tentative_parse (parser); + + parser->in_template_argument_list_p = saved_italp; + break; + } + case CPP_CLOSE_PAREN: + case CPP_ELLIPSIS: + /* If we run into a non-nested `;', `}', or `]', + then the code is invalid -- but the default + argument is certainly over. */ + case CPP_SEMICOLON: + case CPP_CLOSE_BRACE: + case CPP_CLOSE_SQUARE: + if (depth == 0) + done = true; + /* Update DEPTH, if necessary. */ + else if (token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_SQUARE) + --depth; + break; + + case CPP_OPEN_PAREN: + case CPP_OPEN_SQUARE: + case CPP_OPEN_BRACE: + ++depth; + break; + + case CPP_LESS: + if (depth == 0) + /* This might be the comparison operator, or it might + start a template argument list. */ + ++maybe_template_id; + break; + + case CPP_RSHIFT: + if (cxx_dialect == cxx98) + break; + /* Fall through for C++0x, which treats the `>>' + operator like two `>' tokens in certain + cases. */ + + case CPP_GREATER: + if (depth == 0) + { + /* This might be an operator, or it might close a + template argument list. But if a previous '<' + started a template argument list, this will have + closed it, so we can't be in one anymore. */ + maybe_template_id -= 1 + (token->type == CPP_RSHIFT); + if (maybe_template_id < 0) + maybe_template_id = 0; + } + break; + + /* If we run out of tokens, issue an error message. */ + case CPP_EOF: + case CPP_PRAGMA_EOL: + error_at (token->location, "file ends in default argument"); + done = true; + break; + + case CPP_NAME: + case CPP_SCOPE: + /* In these cases, we should look for template-ids. + For example, if the default argument is + `X()', we need to do name lookup to + figure out whether or not `X' is a template; if + so, the `,' does not end the default argument. + + That is not yet done. */ + break; + + default: + break; + } + + /* If we've reached the end, stop. */ + if (done) + break; + + /* Add the token to the token block. */ + token = cp_lexer_consume_token (parser->lexer); + } + + /* Create a DEFAULT_ARG to represent the unparsed default + argument. */ + default_argument = make_node (DEFAULT_ARG); + DEFARG_TOKENS (default_argument) + = cp_token_cache_new (first_token, token); + DEFARG_INSTANTIATIONS (default_argument) = NULL; + + return default_argument; +} + /* Begin parsing tentatively. We always save tokens while parsing tentatively so that if the tentative parsing fails we can restore the tokens. */ @@ -26006,11 +26433,11 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) { /* If decl is an iterator, preserve the operator on decl until finish_omp_for. */ - if (decl - && ((type_dependent_expression_p (decl) - && !POINTER_TYPE_P (TREE_TYPE (decl))) - || CLASS_TYPE_P (TREE_TYPE (decl)))) - incr = cp_parser_omp_for_incr (parser, decl); + if (real_decl + && ((processing_template_decl + && !POINTER_TYPE_P (TREE_TYPE (real_decl))) + || CLASS_TYPE_P (TREE_TYPE (real_decl)))) + incr = cp_parser_omp_for_incr (parser, real_decl); else incr = cp_parser_expression (parser, false, NULL); } @@ -26489,6 +26916,291 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) SET_EXPR_LOCATION (stmt, pragma_tok->location); } +/* Transactional Memory parsing routines. */ + +/* Parse a transaction attribute. + + txn-attribute: + attribute + [ [ identifier ] ] + + ??? Simplify this when C++0x bracket attributes are + implemented properly. */ + +static tree +cp_parser_txn_attribute_opt (cp_parser *parser) +{ + cp_token *token; + tree attr_name, attr = NULL; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + return cp_parser_attributes_opt (parser); + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE)) + return NULL_TREE; + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE)) + goto error1; + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME || token->type == CPP_KEYWORD) + { + token = cp_lexer_consume_token (parser->lexer); + + attr_name = (token->type == CPP_KEYWORD + /* For keywords, use the canonical spelling, + not the parsed identifier. */ + ? ridpointers[(int) token->keyword] + : token->u.value); + attr = build_tree_list (attr_name, NULL_TREE); + } + else + cp_parser_error (parser, "expected identifier"); + + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + error1: + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + return attr; +} + +/* Parse a __transaction_atomic or __transaction_relaxed statement. + + transaction-statement: + __transaction_atomic txn-attribute[opt] txn-noexcept-spec[opt] + compound-statement + __transaction_relaxed txn-noexcept-spec[opt] compound-statement +*/ + +static tree +cp_parser_transaction (cp_parser *parser, enum rid keyword) +{ + unsigned char old_in = parser->in_transaction; + unsigned char this_in = 1, new_in; + cp_token *token; + tree stmt, attrs, noex; + + gcc_assert (keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED); + token = cp_parser_require_keyword (parser, keyword, + (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC + : RT_TRANSACTION_RELAXED)); + gcc_assert (token != NULL); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = cp_parser_txn_attribute_opt (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + /* Parse a noexcept specification. */ + noex = cp_parser_noexcept_specification_opt (parser, true, NULL, true); + + /* Keep track if we're in the lexical scope of an outer transaction. */ + new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); + + stmt = begin_transaction_stmt (token->location, NULL, this_in); + + parser->in_transaction = new_in; + cp_parser_compound_statement (parser, NULL, false, false); + parser->in_transaction = old_in; + + finish_transaction_stmt (stmt, NULL, this_in, noex); + + return stmt; +} + +/* Parse a __transaction_atomic or __transaction_relaxed expression. + + transaction-expression: + __transaction_atomic txn-noexcept-spec[opt] ( expression ) + __transaction_relaxed txn-noexcept-spec[opt] ( expression ) +*/ + +static tree +cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) +{ + unsigned char old_in = parser->in_transaction; + unsigned char this_in = 1; + cp_token *token; + tree expr, noex; + bool noex_expr; + + gcc_assert (keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED); + + if (!flag_tm) + error (keyword == RID_TRANSACTION_RELAXED + ? G_("%<__transaction_relaxed%> without transactional memory " + "support enabled") + : G_("%<__transaction_atomic%> without transactional memory " + "support enabled")); + + token = cp_parser_require_keyword (parser, keyword, + (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC + : RT_TRANSACTION_RELAXED)); + gcc_assert (token != NULL); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + + /* Set this early. This might mean that we allow transaction_cancel in + an expression that we find out later actually has to be a constexpr. + However, we expect that cxx_constant_value will be able to deal with + this; also, if the noexcept has no constexpr, then what we parse next + really is a transaction's body. */ + parser->in_transaction = this_in; + + /* Parse a noexcept specification. */ + noex = cp_parser_noexcept_specification_opt (parser, false, &noex_expr, + true); + + if (!noex || !noex_expr + || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) + { + cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + + expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + finish_parenthesized_expr (expr); + + cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + } + else + { + /* The only expression that is available got parsed for the noexcept + already. noexcept is true then. */ + expr = noex; + noex = boolean_true_node; + } + + expr = build_transaction_expr (token->location, expr, this_in, noex); + parser->in_transaction = old_in; + + if (cp_parser_non_integral_constant_expression (parser, NIC_TRANSACTION)) + return error_mark_node; + + return (flag_tm ? expr : error_mark_node); +} + +/* Parse a function-transaction-block. + + function-transaction-block: + __transaction_atomic txn-attribute[opt] ctor-initializer[opt] + function-body + __transaction_atomic txn-attribute[opt] function-try-block + __transaction_relaxed ctor-initializer[opt] function-body + __transaction_relaxed function-try-block +*/ + +static bool +cp_parser_function_transaction (cp_parser *parser, enum rid keyword) +{ + unsigned char old_in = parser->in_transaction; + unsigned char new_in = 1; + tree compound_stmt, stmt, attrs; + bool ctor_initializer_p; + cp_token *token; + + gcc_assert (keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED); + token = cp_parser_require_keyword (parser, keyword, + (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC + : RT_TRANSACTION_RELAXED)); + gcc_assert (token != NULL); + + if (keyword == RID_TRANSACTION_RELAXED) + new_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = cp_parser_txn_attribute_opt (parser); + if (attrs) + new_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + stmt = begin_transaction_stmt (token->location, &compound_stmt, new_in); + + parser->in_transaction = new_in; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) + ctor_initializer_p = cp_parser_function_try_block (parser); + else + ctor_initializer_p + = cp_parser_ctor_initializer_opt_and_function_body (parser); + + parser->in_transaction = old_in; + + finish_transaction_stmt (stmt, compound_stmt, new_in, NULL_TREE); + + return ctor_initializer_p; +} + +/* Parse a __transaction_cancel statement. + + cancel-statement: + __transaction_cancel txn-attribute[opt] ; + __transaction_cancel txn-attribute[opt] throw-expression ; + + ??? Cancel and throw is not yet implemented. */ + +static tree +cp_parser_transaction_cancel (cp_parser *parser) +{ + cp_token *token; + bool is_outer = false; + tree stmt, attrs; + + token = cp_parser_require_keyword (parser, RID_TRANSACTION_CANCEL, + RT_TRANSACTION_CANCEL); + gcc_assert (token != NULL); + + attrs = cp_parser_txn_attribute_opt (parser); + if (attrs) + is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); + + /* ??? Parse cancel-and-throw here. */ + + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + if (!flag_tm) + { + error_at (token->location, "%<__transaction_cancel%> without " + "transactional memory support enabled"); + return error_mark_node; + } + else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) + { + error_at (token->location, "%<__transaction_cancel%> within a " + "%<__transaction_relaxed%>"); + return error_mark_node; + } + else if (is_outer) + { + if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 + && !is_tm_may_cancel_outer (current_function_decl)) + { + error_at (token->location, "outer %<__transaction_cancel%> not " + "within outer %<__transaction_atomic%>"); + error_at (token->location, + " or a % function"); + return error_mark_node; + } + } + else if (parser->in_transaction == 0) + { + error_at (token->location, "%<__transaction_cancel%> not within " + "%<__transaction_atomic%>"); + return error_mark_node; + } + + stmt = build_tm_abort_call (token->location, is_outer); + add_stmt (stmt); + finish_stmt (); + + return stmt; +} + /* The parser. */ static GTY (()) cp_parser *the_parser;