diff options
Diffstat (limited to 'gcc/cp/parser.cc')
-rw-r--r-- | gcc/cp/parser.cc | 774 |
1 files changed, 616 insertions, 158 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index a8c54c7..9f9bd56 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -601,6 +601,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) parser->in_template_argument_list_p); cp_debug_print_flag (file, "Parsing an iteration statement", parser->in_statement & IN_ITERATION_STMT); + cp_debug_print_flag (file, "Parsing an expansion statement", + parser->in_statement & IN_EXPANSION_STMT); cp_debug_print_flag (file, "Parsing a switch statement", parser->in_statement & IN_SWITCH_STMT); cp_debug_print_flag (file, "Parsing a structured OpenMP block", @@ -2611,11 +2613,11 @@ static tree cp_parser_c_for static tree cp_parser_range_for (cp_parser *, tree, tree, tree, bool, tree, bool, bool); static void do_range_for_auto_deduction - (tree, tree, cp_decomp *); -static tree cp_parser_perform_range_for_lookup - (tree, tree *, tree *); -static tree cp_parser_range_for_member_function + (tree, tree, cp_decomp *, bool); +static tree cp_range_for_member_function (tree, tree); +static tree cp_parser_expansion_statement + (cp_parser *, bool *); static tree cp_parser_jump_statement (cp_parser *, tree &); static void cp_parser_declaration_statement @@ -11804,6 +11806,8 @@ cp_parser_lambda_expression (cp_parser* parser, it now. */ push_deferring_access_checks (dk_no_deferred); + auto gr = make_temp_override (parser->greater_than_is_operator_p, true); + if (!consteval_block_p) { cp_parser_lambda_introducer (parser, lambda_expr); @@ -11875,12 +11879,20 @@ cp_parser_lambda_expression (cp_parser* parser, bool save_in_consteval_if_p = in_consteval_if_p; in_consteval_if_p = false; + /* Similarly the body of a lambda is not part of expansion statement. */ + bool save_in_expansion_stmt = in_expansion_stmt; + in_expansion_stmt = 0; + /* By virtue of defining a local class, a lambda expression has access to the private variables of enclosing classes. */ if (cp_parser_start_tentative_firewall (parser)) start = token; + /* A lambda scope starts immediately after the lambda-introducer of E + and extends to the end of the compound-statement of E. */ + begin_scope (sk_lambda, NULL_TREE); + ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr, consteval_block_p); @@ -11902,8 +11914,11 @@ cp_parser_lambda_expression (cp_parser* parser, if (ok) maybe_add_lambda_conv_op (type); + /* Leave the lambda scope. */ + pop_bindings_and_leave_scope (); finish_struct (type, /*attributes=*/NULL_TREE); + in_expansion_stmt = save_in_expansion_stmt; in_consteval_if_p = save_in_consteval_if_p; in_discarded_stmt = discarded; @@ -12292,6 +12307,13 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr, clear_decl_specs (&lambda_specs); /* A lambda op() is const unless explicitly 'mutable'. */ cp_cv_quals quals = TYPE_QUAL_CONST; + /* Don't add "const" to entities in the parameter-declaration-clause. */ + LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = false; + + /* Inject the captures into the lambda scope as they may be used in the + declarator and we have to be able to look them up. */ + tree dummy_fco = maybe_add_dummy_lambda_op (lambda_expr); + push_capture_proxies (lambda_expr, /*early_p=*/true); /* The template-parameter-list is optional, but must begin with an opening angle if present. */ @@ -12482,6 +12504,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr, } } + /* Now we're done with the parameter-declaration-clause, and should + assume "const" unless "mutable" was present. */ + LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = quals == TYPE_QUAL_CONST; + tx_qual = cp_parser_tx_qualifier_opt (parser); if (omitted_parms_loc && tx_qual) { @@ -12539,6 +12565,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr, pop_bindings_and_leave_scope (); } + /* We are about to create the real operator(), so get rid of the old one. */ + if (dummy_fco) + remove_dummy_lambda_op (dummy_fco, lambda_expr); + /* Create the function call operator. Messing with declarators like this is no uglier than building up the @@ -12618,6 +12648,79 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr, } } +/* Create a fake operator() for a lambda. We do this so that we can + build_capture_proxy even before start_lambda_function. */ + +static tree +make_dummy_lambda_op () +{ + cp_decl_specifier_seq return_type_specs; + cp_cv_quals quals = TYPE_UNQUALIFIED; + + clear_decl_specs (&return_type_specs); + return_type_specs.type = make_auto (); + + void *p = obstack_alloc (&declarator_obstack, 0); + + cp_declarator *declarator = make_id_declarator (NULL_TREE, + call_op_identifier, + sfk_none, + input_location); + + declarator = make_call_declarator (declarator, void_list_node, quals, + VIRT_SPEC_UNSPECIFIED, + REF_QUAL_NONE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, + NULL_TREE, UNKNOWN_LOCATION); + + tree fco = grokmethod (&return_type_specs, declarator, NULL_TREE); + obstack_free (&declarator_obstack, p); + + return fco; +} + +/* We need to push early capture proxies (for parsing the lambda-declarator), + and we may need a dummy operator() to be able to build the proxies. + LAMBDA_EXPR is the lambda we are building the captures for. */ + +tree +maybe_add_dummy_lambda_op (tree lambda_expr) +{ + /* If there are no captures, we don't need this. */ + if (!LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)) + return NULL_TREE; + + tree fco = make_dummy_lambda_op (); + if (fco != error_mark_node) + finish_member_declaration (fco); + + return fco; +} + +/* Remove the dummy operator() DUMMY_FCO we built for parsing the + lambda-declarator of LAMBDA_EXPR. */ + +void +remove_dummy_lambda_op (tree dummy_fco, tree lambda_expr) +{ + tree type = TREE_TYPE (lambda_expr); + if (TYPE_FIELDS (type) == dummy_fco) + { + /* Stitch out the dummy operator(). */ + TYPE_FIELDS (type) = DECL_CHAIN (TYPE_FIELDS (type)); + /* And clear the member vector as well. */ + auto *member_vec = CLASSTYPE_MEMBER_VEC (type); + gcc_assert (member_vec->length () == 1); + member_vec->truncate (0); + } + /* Class templates will have the dummy operator() stashed here too. */ + tree &list = CLASSTYPE_DECL_LIST (type); + if (list && TREE_VALUE (list) == dummy_fco) + list = TREE_CHAIN (list); + /* ??? We can't ggc_free dummy_fco yet. There's still a binding in the + closure to it, and the captures have it as their DECL_CONTEXT. */ +} + /* Parse the body of a lambda expression, which is simply compound-statement @@ -13164,6 +13267,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_TRANSACTION_CANCEL: handle_omp_attribs = true; break; + case RID_TEMPLATE: + if (cxx_dialect >= cxx11 + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR)) + handle_omp_attribs = true; + break; default: break; } @@ -13216,6 +13324,16 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, NULL_TREE, false); break; + case RID_TEMPLATE: + if (cxx_dialect >= cxx11 + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR)) + { + std_attrs = process_stmt_hotness_attribute (std_attrs, + attrs_loc); + statement = cp_parser_expansion_statement (parser, if_p); + } + break; + case RID_BREAK: case RID_CONTINUE: case RID_RETURN: @@ -13618,6 +13736,13 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) default: /* Anything else must be an ordinary label. */ cp_expr identifier = cp_parser_identifier (parser); + if (in_expansion_stmt && identifier != error_mark_node) + { + error_at (token->location, + "identifier label %qE in %<template for%> body", + *identifier); + break; + } if (identifier != error_mark_node && parser->omp_metadirective_state) *identifier = mangle_metadirective_region_label (parser, *identifier); @@ -14644,6 +14769,73 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, return stmt; } +/* Helper function for cp_parser_range_for and cp_parser_expansion_statement. + Get the range declaration momentarily out of the way so that the range + expression doesn't clash with it. */ + +static cp_decomp * +cp_hide_range_decl (tree *range_decl_p, cp_decomp *decomp_d, + auto_vec <cxx_binding *> &bindings, + auto_vec <tree> &names) +{ + tree range_decl = *range_decl_p; + cp_decomp *decomp = NULL; + if (range_decl == error_mark_node) + return decomp; + + if (DECL_HAS_VALUE_EXPR_P (range_decl)) + { + tree v = DECL_VALUE_EXPR (range_decl); + /* For decomposition declaration get all of the corresponding + declarations out of the way. */ + if ((TREE_CODE (v) == ARRAY_REF + && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + || (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))) + { + tree d = range_decl; + decomp = decomp_d; + if (TREE_CODE (v) == ARRAY_REF) + { + *range_decl_p = range_decl = TREE_OPERAND (v, 0); + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + } + else + { + *range_decl_p = range_decl = TREE_VEC_ELT (v, 0); + decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1; + } + decomp->decl = d; + bool seen_name_independent_decl = false; + names.reserve (decomp->count); + bindings.reserve (decomp->count); + for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d)) + { + if (name_independent_decl_p (d)) + { + /* If there is more than one _ decl in the structured + binding, just push and move it away once. */ + if (seen_name_independent_decl) + continue; + seen_name_independent_decl = true; + } + tree name = DECL_NAME (d); + names.quick_push (name); + bindings.quick_push (IDENTIFIER_BINDING (name)); + IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; + } + } + } + if (names.is_empty ()) + { + tree name = DECL_NAME (range_decl); + names.safe_push (name); + bindings.safe_push (IDENTIFIER_BINDING (name)); + IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; + } + return decomp; +} + /* Tries to parse a range-based for-statement: range-based-for: @@ -14659,56 +14851,14 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, bool ivdep, tree unroll, bool novector, bool is_omp) { tree stmt, range_expr; - auto_vec <cxx_binding *, 16> bindings; - auto_vec <tree, 16> names; - cp_decomp decomp_d, *decomp = NULL; + auto_vec <cxx_binding *> bindings; + auto_vec <tree> names; + cp_decomp decomp_d; /* Get the range declaration momentarily out of the way so that the range expression doesn't clash with it. */ - if (range_decl != error_mark_node) - { - if (DECL_HAS_VALUE_EXPR_P (range_decl)) - { - tree v = DECL_VALUE_EXPR (range_decl); - /* For decomposition declaration get all of the corresponding - declarations out of the way. */ - if (TREE_CODE (v) == ARRAY_REF - && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) - { - tree d = range_decl; - range_decl = TREE_OPERAND (v, 0); - decomp = &decomp_d; - decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp->decl = d; - bool seen_name_independent_decl = false; - for (unsigned int i = 0; i < decomp->count; - i++, d = DECL_CHAIN (d)) - { - if (name_independent_decl_p (d)) - { - /* If there is more than one _ decl in - the structured binding, just push and move it - away once. */ - if (seen_name_independent_decl) - continue; - seen_name_independent_decl = true; - } - tree name = DECL_NAME (d); - names.safe_push (name); - bindings.safe_push (IDENTIFIER_BINDING (name)); - IDENTIFIER_BINDING (name) - = IDENTIFIER_BINDING (name)->previous; - } - } - } - if (names.is_empty ()) - { - tree name = DECL_NAME (range_decl); - names.safe_push (name); - bindings.safe_push (IDENTIFIER_BINDING (name)); - IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; - } - } + cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings, + names); if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) range_expr = cp_parser_braced_list (parser); @@ -14745,7 +14895,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ && !BRACE_ENCLOSED_INITIALIZER_P (range_expr)) - do_range_for_auto_deduction (range_decl, range_expr, decomp); + do_range_for_auto_deduction (range_decl, range_expr, decomp, false); } else { @@ -14759,7 +14909,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, /* Subroutine of cp_convert_range_for: given the initializer expression, builds up the range temporary. */ -static tree +tree build_range_temp (tree range_expr) { /* Find out the type deduced by the declaration @@ -14783,15 +14933,22 @@ build_range_temp (tree range_expr) a shortcut version of cp_convert_range_for. */ static void -do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp) +do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp, + bool expansion_stmt) { tree auto_node = type_uses_auto (TREE_TYPE (decl)); if (auto_node) { tree begin_dummy, end_dummy, range_temp, iter_type, iter_decl; range_temp = convert_from_reference (build_range_temp (range_expr)); - iter_type = (cp_parser_perform_range_for_lookup - (range_temp, &begin_dummy, &end_dummy)); + iter_type = cp_perform_range_for_lookup (range_temp, &begin_dummy, + &end_dummy, + expansion_stmt ? tf_none + : tf_warning_or_error); + if (expansion_stmt + && (begin_dummy == error_mark_node + || end_dummy == error_mark_node)) + return; if (iter_type) { iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE, @@ -14892,6 +15049,89 @@ warn_for_range_copy (tree decl, tree expr) } } +/* Helper function for cp_convert_range_for and finish_expansion_stmt. + Build the __range, __begin and __end declarations. Return the + __begin VAR_DECL, set *END_P to the __end VAR_DECL. */ + +tree +cp_build_range_for_decls (location_t loc, tree range_expr, tree *end_p, + bool expansion_stmt_p) +{ + tree iter_type, begin_expr, end_expr; + + if (range_expr == error_mark_node) + /* If an error happened previously do nothing or else a lot of + unhelpful errors would be issued. */ + begin_expr = end_expr = iter_type = error_mark_node; + else + { + tree range_temp; + + if (!expansion_stmt_p + && VAR_P (range_expr) + && array_of_runtime_bound_p (TREE_TYPE (range_expr))) + /* Can't bind a reference to an array of runtime bound. */ + range_temp = range_expr; + else + { + range_temp = build_range_temp (range_expr); + if (expansion_stmt_p) + { + /* Depending on CWG3044 resolution, we might want to remove + these 3 sets of TREE_STATIC (on range_temp, begin and end). + Although it can only be done when P2686R4 is fully + implemented. */ + TREE_STATIC (range_temp) = 1; + TREE_PUBLIC (range_temp) = 0; + DECL_COMMON (range_temp) = 0; + DECL_INTERFACE_KNOWN (range_temp) = 1; + DECL_DECLARED_CONSTEXPR_P (range_temp) = 1; + TREE_READONLY (range_temp) = 1; + } + pushdecl (range_temp); + cp_finish_decl (range_temp, range_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + range_temp = convert_from_reference (range_temp); + } + iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr, + &end_expr); + } + + /* The new for initialization statement. */ + tree begin = build_decl (loc, VAR_DECL, for_begin__identifier, iter_type); + TREE_USED (begin) = 1; + DECL_ARTIFICIAL (begin) = 1; + if (expansion_stmt_p) + { + TREE_STATIC (begin) = 1; + DECL_DECLARED_CONSTEXPR_P (begin) = 1; + TREE_READONLY (begin) = 1; + } + pushdecl (begin); + cp_finish_decl (begin, begin_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + + if (cxx_dialect >= cxx17) + iter_type = cv_unqualified (TREE_TYPE (end_expr)); + tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type); + TREE_USED (end) = 1; + DECL_ARTIFICIAL (end) = 1; + if (expansion_stmt_p) + { + TREE_STATIC (end) = 1; + DECL_DECLARED_CONSTEXPR_P (end) = 1; + TREE_READONLY (end) = 1; + } + pushdecl (end); + cp_finish_decl (end, end_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + *end_p = end; + return begin; +} + /* Converts a range-based for-statement into a normal for-statement, as per the definition. @@ -14932,56 +15172,14 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, cp_decomp *decomp, bool ivdep, tree unroll, bool novector) { - tree begin, end; - tree iter_type, begin_expr, end_expr; - tree condition, expression; + tree end, condition, expression; range_expr = mark_lvalue_use (range_expr); - if (range_decl == error_mark_node || range_expr == error_mark_node) - /* If an error happened previously do nothing or else a lot of - unhelpful errors would be issued. */ - begin_expr = end_expr = iter_type = error_mark_node; - else - { - tree range_temp; - - if (VAR_P (range_expr) - && array_of_runtime_bound_p (TREE_TYPE (range_expr))) - /* Can't bind a reference to an array of runtime bound. */ - range_temp = range_expr; - else - { - range_temp = build_range_temp (range_expr); - pushdecl (range_temp); - cp_finish_decl (range_temp, range_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); - range_temp = convert_from_reference (range_temp); - } - iter_type = cp_parser_perform_range_for_lookup (range_temp, - &begin_expr, &end_expr); - } - - /* The new for initialization statement. */ - begin = build_decl (input_location, VAR_DECL, for_begin__identifier, - iter_type); - TREE_USED (begin) = 1; - DECL_ARTIFICIAL (begin) = 1; - pushdecl (begin); - cp_finish_decl (begin, begin_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); - - if (cxx_dialect >= cxx17) - iter_type = cv_unqualified (TREE_TYPE (end_expr)); - end = build_decl (input_location, VAR_DECL, for_end__identifier, iter_type); - TREE_USED (end) = 1; - DECL_ARTIFICIAL (end) = 1; - pushdecl (end); - cp_finish_decl (end, end_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + if (range_decl == error_mark_node) + range_expr = error_mark_node; + tree begin + = cp_build_range_for_decls (input_location, range_expr, &end, false); finish_init_stmt (statement); @@ -15015,8 +15213,10 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, depends on the existence of members begin or end. Returns the type deduced for the iterator expression. */ -static tree -cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) +tree +cp_perform_range_for_lookup (tree range, tree *begin, tree *end, + tsubst_flags_t complain + /* = tf_warning_or_error */) { if (error_operand_p (range)) { @@ -15026,8 +15226,9 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range)))) { - error ("range-based %<for%> expression of type %qT " - "has incomplete type", TREE_TYPE (range)); + if (complain & tf_error) + error ("range-based %<for%> expression of type %qT " + "has incomplete type", TREE_TYPE (range)); *begin = *end = error_mark_node; return error_mark_node; } @@ -15053,16 +15254,16 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) id_end = get_identifier ("end"); member_begin = lookup_member (TREE_TYPE (range), id_begin, /*protect=*/2, /*want_type=*/false, - tf_warning_or_error); + complain); member_end = lookup_member (TREE_TYPE (range), id_end, /*protect=*/2, /*want_type=*/false, - tf_warning_or_error); + complain); if (member_begin != NULL_TREE && member_end != NULL_TREE) { /* Use the member functions. */ - *begin = cp_parser_range_for_member_function (range, id_begin); - *end = cp_parser_range_for_member_function (range, id_end); + *begin = cp_range_for_member_function (range, id_begin); + *end = cp_range_for_member_function (range, id_end); } else { @@ -15072,13 +15273,20 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) vec_safe_push (vec, range); member_begin = perform_koenig_lookup (id_begin, vec, - tf_warning_or_error); + complain); + if ((complain & tf_error) == 0 && member_begin == id_begin) + return error_mark_node; *begin = finish_call_expr (member_begin, &vec, false, true, - tf_warning_or_error); + complain); member_end = perform_koenig_lookup (id_end, vec, tf_warning_or_error); + if ((complain & tf_error) == 0 && member_end == id_end) + { + *begin = error_mark_node; + return error_mark_node; + } *end = finish_call_expr (member_end, &vec, false, true, - tf_warning_or_error); + complain); } /* Last common checks. */ @@ -15109,7 +15317,7 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) /* P0184R0 allows __begin and __end to have different types, but make sure they are comparable so we can give a better diagnostic. */; - else + else if (complain & tf_error) error ("inconsistent begin/end types in range-based %<for%> " "statement: %qT and %qT", TREE_TYPE (*begin), TREE_TYPE (*end)); @@ -15119,11 +15327,11 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) } } -/* Helper function for cp_parser_perform_range_for_lookup. +/* Helper function for cp_perform_range_for_lookup. Builds a tree for RANGE.IDENTIFIER(). */ static tree -cp_parser_range_for_member_function (tree range, tree identifier) +cp_range_for_member_function (tree range, tree identifier) { tree member, res; @@ -15342,6 +15550,183 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) return false; } +/* Parse an expansion-statement. + + expansion-statement: + template for ( init-statement[opt] + for-range-declaration : expansion-initializer ) + statement + + expansion-initializer: + expression + expansion-init-list + + expansion-init-list: + { expression-list } */ + +static tree +cp_parser_expansion_statement (cp_parser* parser, bool *if_p) +{ + /* Peek at the next token. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + gcc_assert (token->keyword == RID_TEMPLATE); + gcc_assert (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR)); + cp_lexer_consume_token (parser->lexer); + cp_token *for_token = cp_lexer_peek_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + + if (cxx_dialect < cxx26) + pedwarn (make_location (token->location, token->location, + for_token->location), OPT_Wc__26_extensions, + "%<template for%> only available with %<-std=c++2c%> " + "or %<-std=gnu++2c%>"); + + token_indent_info guard_tinfo = get_token_indent_info (token); + + /* Remember whether or not we are already within an iteration + statement. */ + unsigned char in_statement = parser->in_statement; + /* And whether we are already in expansion-statement. */ + auto save_in_expansion_stmt = in_expansion_stmt; + + /* Look for the `('. */ + matching_parens parens; + parens.require_open (parser); + + tree init; + tree scope = begin_template_for_scope (&init); + + /* Maybe parse the optional init-statement in a expansion-statement. */ + if (cp_parser_range_based_for_with_init_p (parser) + /* Checked for diagnostic purposes only. */ + && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + tree dummy; + cp_parser_init_statement (parser, &dummy); + } + + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + + /* A colon is used in expansion-statement. */ + parser->colon_corrects_to_scope_p = false; + + /* Parse the declaration. */ + tree range_decl; + cp_parser_simple_declaration (parser, + /*function_definition_allowed_p=*/false, + &range_decl); + if (range_decl == NULL_TREE) + range_decl = error_mark_node; + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + + cp_parser_require (parser, CPP_COLON, RT_COLON); + + auto_vec <cxx_binding *> bindings; + auto_vec <tree> names; + cp_decomp decomp_d; + + /* Get the range declaration momentarily out of the way so that + the range expression doesn't clash with it. */ + cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings, + names); + + tree expansion_init; + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + expansion_init = cp_parser_braced_list (parser); + if (TREE_CODE (expansion_init) == CONSTRUCTOR + && CONSTRUCTOR_IS_DESIGNATED_INIT (expansion_init)) + error_at (EXPR_LOC_OR_LOC (expansion_init, token->location), + "designators in %<template for%> initializer"); + } + else + expansion_init = cp_parser_expression (parser); + + /* Put the range declaration(s) back into scope. */ + for (unsigned int i = 0; i < names.length (); i++) + { + cxx_binding *binding = bindings[i]; + binding->previous = IDENTIFIER_BINDING (names[i]); + IDENTIFIER_BINDING (names[i]) = binding; + } + + /* Look for the `)'. */ + parens.require_close (parser); + + if (processing_template_decl + && check_for_bare_parameter_packs (expansion_init)) + expansion_init = error_mark_node; + + if (expansion_init != error_mark_node + && !type_dependent_expression_p (expansion_init) + && TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE + && !BRACE_ENCLOSED_INITIALIZER_P (expansion_init)) + do_range_for_auto_deduction (range_decl, expansion_init, decomp, + true); + + bool outside_of_template = !processing_template_decl; + if (outside_of_template) + { + ++processing_template_decl; + current_template_parms + = tree_cons (size_int (current_template_depth + 1), + make_tree_vec (0), current_template_parms); + } + in_expansion_stmt = true; + + tree r = build_stmt (token->location, TEMPLATE_FOR_STMT, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + + current_binding_level->this_entity = r; + TEMPLATE_FOR_INIT_STMT (r) = init; + TEMPLATE_FOR_SCOPE (r) = scope; + if (!outside_of_template) + TEMPLATE_FOR_INIT_STMT (r) = pop_stmt_list (TEMPLATE_FOR_INIT_STMT (r)); + TEMPLATE_FOR_DECL (r) = range_decl; + TEMPLATE_FOR_EXPR (r) = expansion_init; + TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block); + + /* Parse the body of the expansion-statement. */ + parser->in_statement = IN_EXPANSION_STMT; + bool prev = note_iteration_stmt_body_start (); + cp_parser_already_scoped_statement (parser, if_p, guard_tinfo); + note_iteration_stmt_body_end (prev); + parser->in_statement = in_statement; + in_expansion_stmt = save_in_expansion_stmt; + + TEMPLATE_FOR_BODY (r) = do_poplevel (TEMPLATE_FOR_BODY (r)); + + if (outside_of_template) + { + current_template_parms = TREE_CHAIN (current_template_parms); + --processing_template_decl; + } + + if (VAR_P (range_decl) && DECL_DECLARED_CONSTINIT_P (range_decl)) + error_at (DECL_SOURCE_LOCATION (range_decl), + "for-range-declaration cannot be 'constinit'"); + + if (decomp) + { + tree v = make_tree_vec (decomp->count + 1); + TREE_VEC_ELT (v, 0) = TEMPLATE_FOR_DECL (r); + tree d = decomp->decl; + for (unsigned i = 0; i < decomp->count; ++i, d = DECL_CHAIN (d)) + TREE_VEC_ELT (v, decomp->count - i) = d; + TEMPLATE_FOR_DECL (r) = v; + } + + if (processing_template_decl) + add_stmt (r); + else + finish_expansion_stmt (r, NULL_TREE, tf_warning_or_error, NULL_TREE); + + add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (r))); + TEMPLATE_FOR_SCOPE (r) = NULL_TREE; + + return r; +} + /* Parse a jump-statement. jump-statement: @@ -15386,7 +15771,8 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) break; default: gcc_assert ((in_statement & IN_SWITCH_STMT) - || in_statement == IN_ITERATION_STMT); + || in_statement == IN_ITERATION_STMT + || in_statement == IN_EXPANSION_STMT); statement = finish_break_stmt (); if (in_statement == IN_ITERATION_STMT) break_maybe_infinite_loop (); @@ -15409,6 +15795,7 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) break; /* Fall through. */ case IN_ITERATION_STMT: + case IN_EXPANSION_STMT: case IN_OMP_FOR: statement = finish_continue_stmt (); break; @@ -16843,7 +17230,7 @@ cp_parser_simple_declaration (cp_parser* parser, } /* Helper of cp_parser_simple_declaration, parse a decomposition declaration. - decl-specifier-seq ref-qualifier [opt] [ identifier-list ] + decl-specifier-seq ref-qualifier [opt] [ sb-identifier-list ] initializer ; */ static tree @@ -16856,21 +17243,45 @@ cp_parser_decomposition_declaration (cp_parser *parser, location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE); - /* Parse the identifier-list. */ + /* Parse the sb-identifier-list. */ auto_vec<cp_expr, 10> v; bool attr_diagnosed = false; int first_attr = -1; + int pack = -1; unsigned int cnt = 0; if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) while (true) { + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + location_t elloc = cp_lexer_peek_token (parser->lexer)->location; + if (!processing_template_decl) + error_at (elloc, "structured binding pack outside of template"); + else if (pack != -1) + error_at (elloc, + "multiple packs in structured binding declaration"); + else + { + if (keyword == RID_MAX + && cxx_dialect >= cxx17 + && cxx_dialect < cxx26) + pedwarn (elloc, OPT_Wc__26_extensions, + "structured binding packs only available with " + "%<-std=c++2c%> or %<-std=gnu++2c%>"); + pack = cnt; + } + cp_lexer_consume_token (parser->lexer); + } cp_expr e = cp_parser_identifier (parser); if (e.get_value () == error_mark_node) break; tree attr = NULL_TREE; if (cp_next_tokens_can_be_std_attribute_p (parser)) { - if (cxx_dialect >= cxx17 && cxx_dialect < cxx26 && !attr_diagnosed) + if (keyword == RID_MAX + && cxx_dialect >= cxx17 + && cxx_dialect < cxx26 + && !attr_diagnosed) { pedwarn (cp_lexer_peek_token (parser->lexer)->location, OPT_Wc__26_extensions, @@ -16931,7 +17342,7 @@ cp_parser_decomposition_declaration (cp_parser *parser, &pushed_scope); tree orig_decl = decl; - unsigned int i; + unsigned int i, j; cp_expr e; cp_decl_specifier_seq decl_specs; clear_decl_specs (&decl_specs); @@ -16939,6 +17350,7 @@ cp_parser_decomposition_declaration (cp_parser *parser, if (decl_specifiers->storage_class == sc_static) decl_specs.storage_class = sc_static; tree prev = decl; + j = 0; FOR_EACH_VEC_ELT (v, i, e) { if (i == 0) @@ -16967,11 +17379,29 @@ cp_parser_decomposition_declaration (cp_parser *parser, else { prev = decl2; - DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl); - DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl); + if (decl != error_mark_node) + { + DECL_DECLARED_CONSTEXPR_P (decl2) + = DECL_DECLARED_CONSTEXPR_P (decl); + DECL_DECLARED_CONSTINIT_P (decl2) + = DECL_DECLARED_CONSTINIT_P (decl); + } + if (j == (unsigned) pack) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = decl2; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + tree type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = decl2; + TREE_TYPE (decl2) = type; + } } if (elt_pushed_scope) pop_scope (elt_pushed_scope); + ++j; } if (v.is_empty ()) @@ -27086,6 +27516,10 @@ cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/) location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; auto oas = make_temp_override (parser->omp_array_section_p, false); + /* Within a brace-enclosed initializer list, a `>' token is always the + greater-than operator. */ + auto gto = make_temp_override (parser->greater_than_is_operator_p, true); + /* Consume the `{' token. */ matching_braces braces; bool found_opening_brace = braces.require_open (parser); @@ -32975,9 +33409,12 @@ cp_parser_compound_requirement (cp_parser *parser) } } else - /* P1452R2 removed the trailing-return-type option. */ - error_at (type_loc, - "return-type-requirement is not a type-constraint"); + { + /* P1452R2 removed the trailing-return-type option. */ + error_at (type_loc, + "return-type-requirement is not a type-constraint"); + type = NULL_TREE; + } } location_t loc = make_location (expr_token->location, @@ -36746,7 +37183,11 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) case CPP_CLOSE_SQUARE: if (depth == 0 /* Handle correctly int n = sizeof ... ( p ); */ - && token->type != CPP_ELLIPSIS) + && (token->type != CPP_ELLIPSIS + /* For int n = 42 ...) handle ... as variadic arguments. */ + || (!nsdmi + && cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)))) done = true; /* Update DEPTH, if necessary. */ else if (token->type == CPP_CLOSE_PAREN @@ -46300,8 +46741,16 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl, decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; decomp->decl = decl; } + else if (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))) + { + d = TREE_VEC_ELT (v, 0); + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1; + decomp->decl = decl; + } } - do_range_for_auto_deduction (d, init, decomp); + do_range_for_auto_deduction (d, init, decomp, false); } cond = global_namespace; incr = NULL_TREE; @@ -46357,8 +46806,8 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl, range_temp_decl = range_temp; range_temp = convert_from_reference (range_temp); } - iter_type = cp_parser_perform_range_for_lookup (range_temp, - &begin_expr, &end_expr); + iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr, + &end_expr); } tree end_iter_type = iter_type; @@ -46423,6 +46872,15 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl, decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; decomp->decl = d; } + else if (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))) + { + tree d = orig_decl; + orig_decl = TREE_VEC_ELT (v, 0); + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1; + decomp->decl = d; + } } tree auto_node = type_uses_auto (TREE_TYPE (orig_decl)); @@ -51186,41 +51644,41 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, append_args_tree); } } while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)); + if (variant != error_mark_node && !has_match) + { + cp_parser_error (parser, "expected %<match%> clause"); + variant = error_mark_node; + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); - if ((ctx != error_mark_node && variant != error_mark_node) - && (has_adjust_args || append_args_tree)) + /* At this point, we have completed parsing of the pragma, now it's + on to error checking. */ + if (variant == error_mark_node || ctx == error_mark_node) + /* Previously diagnosed error. */ + return attrs; + + if (has_adjust_args || append_args_tree) { - if (!has_match) + if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, + OMP_TRAIT_CONSTRUCT_DISPATCH)) { error_at (has_adjust_args ? adjust_args_loc : append_args_loc, - "an %qs clause requires a %<match%> clause", + "an %qs clause can only be specified if the %<dispatch%> " + "selector of the construct selector set appears " + "in the %<match%> clause", has_adjust_args ? "adjust_args" : "append_args"); + return attrs; } - else - { - gcc_assert (TREE_PURPOSE (attrs) - == get_identifier ("omp declare variant base")); - gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant); - ctx = TREE_VALUE (TREE_VALUE (attrs)); - if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, - OMP_TRAIT_CONSTRUCT_DISPATCH)) - error_at (has_adjust_args ? adjust_args_loc : append_args_loc, - "an %qs clause can only be specified if the %<dispatch%> " - "selector of the construct selector set appears " - "in the %<match%> clause", - has_adjust_args ? "adjust_args" : "append_args"); - // We might not have a DECL for the variant yet. So we store the - // need_device_ptr list in the base function attribute, after loc - // nodes. - tree t = build_tree_list (need_device_ptr_list, - NULL_TREE /* need_device_addr */); - TREE_CHAIN (t) = append_args_tree; - TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs), - build_tree_list ( NULL_TREE, t)); - } + // We might not have a DECL for the variant yet. So we store the + // need_device_ptr list in the base function attribute, after loc + // nodes. + tree t = build_tree_list (need_device_ptr_list, + NULL_TREE /* need_device_addr */); + TREE_CHAIN (t) = append_args_tree; + TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs), + build_tree_list (NULL_TREE, t)); } - cp_parser_skip_to_pragma_eol (parser, pragma_tok); return attrs; } |