@@ -2951,7 +2951,7 @@ struct contract_modifier {
29512951};
29522952
29532953static contract_modifier cp_parser_function_contract_modifier_opt
2954- (cp_parser *, bool );
2954+ (cp_parser *);
29552955
29562956static tree cp_parser_function_contract_specifier
29572957 (cp_parser *);
@@ -13211,8 +13211,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
1321113211 cp_token *token = cp_lexer_consume_token (parser->lexer);
1321213212 location_t loc = token->location;
1321313213 contract_modifier modifier
13214- = cp_parser_function_contract_modifier_opt (parser,
13215- /*attr_mode*/false);
13214+ = cp_parser_function_contract_modifier_opt (parser);
1321613215
1321713216 matching_parens parens;
1321813217 parens.require_open (parser);
@@ -31459,8 +31458,7 @@ contains_error_p (tree t)
3145931458 placeholder. */
3146031459
3146131460static tree
31462- cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31463- bool attr_mode)
31461+ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute)
3146431462{
3146531463 gcc_assert (contract_attribute_p (attribute));
3146631464 cp_token *token = cp_lexer_consume_token (parser->lexer);
@@ -31471,16 +31469,9 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3147131469
3147231470 /* For C++20 contract attributes, parse the optional mode. */
3147331471 tree mode = NULL_TREE;
31474- if (attr_mode)
31475- mode = cp_parser_contract_mode_opt (parser, postcondition_p);
31476-
31477- /* For experimental modifiers on C++26 contracts. */
31478- contract_modifier modifier
31479- = cp_parser_function_contract_modifier_opt (parser, attr_mode);
31472+ mode = cp_parser_contract_mode_opt (parser, postcondition_p);
3148031473
3148131474 matching_parens parens;
31482- if (flag_contracts_nonattr && !attr_mode)
31483- parens.require_open (parser);
3148431475
3148531476 /* Check for postcondition identifiers. */
3148631477 cp_expr identifier;
@@ -31490,22 +31481,7 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3149031481 if (identifier == error_mark_node)
3149131482 return error_mark_node;
3149231483
31493- /* e.g. [[ pre assume: .... ]] or pre: (...) */
31494- if (attr_mode || identifier)
31495- cp_parser_require (parser, CPP_COLON, RT_COLON);
31496-
31497- bool should_constify = false;
31498- /* When we have P2900 semantics in force.
31499- Do we have an override for const-ification? This applies equally to
31500- deferred or immediate parses. */
31501- if (flag_contracts_nonattr)
31502- {
31503- should_constify = !flag_contracts_nonattr_noconst;
31504- if (!modifier.error_p
31505- && (modifier.mutable_p
31506- || (flag_contracts_nonattr_const_keyword && !modifier.const_p)))
31507- should_constify = false;
31508- }
31484+ cp_parser_require (parser, CPP_COLON, RT_COLON);
3150931485
3151031486 tree contract;
3151131487 if (!assertion_p &&
@@ -31514,32 +31490,21 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3151431490 {
3151531491 /* Defer the parsing of pre/post contracts inside class definitions. */
3151631492 cp_token *first = cp_lexer_peek_token (parser->lexer);
31517- if (attr_mode)
31518- {
31519- /* Skip until we reach a closing token ]. */
31520- cp_parser_skip_to_closing_parenthesis_1 (parser,
31521- /*recovering=*/false,
31522- CPP_CLOSE_SQUARE,
31523- /*consume_paren=*/false);
31524- if (cp_lexer_peek_token (parser->lexer)->type != CPP_CLOSE_SQUARE
31525- || cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_CLOSE_SQUARE)
31526- return error_mark_node;
31527- /* Otherwise the closing ]] will be consumed by the caller. */
31528- }
31529- else
31530- /* Skip until we reach a closing token ). */
31531- cp_parser_skip_to_closing_parenthesis_1 (parser,
31532- /*recovering=*/false,
31533- CPP_CLOSE_PAREN,
31534- /*consume_paren=*/false);
31493+
31494+ /* Skip until we reach a closing token ]. */
31495+ cp_parser_skip_to_closing_parenthesis_1 (parser,
31496+ /*recovering=*/false,
31497+ CPP_CLOSE_SQUARE,
31498+ /*consume_paren=*/false);
31499+ if (cp_lexer_peek_token (parser->lexer)->type != CPP_CLOSE_SQUARE
31500+ || cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_CLOSE_SQUARE)
31501+ return error_mark_node;
31502+ /* Otherwise the closing ]] will be consumed by the caller. */
3153531503
3153631504 cp_token *last = cp_lexer_peek_token (parser->lexer);
3153731505 location_t end = last->location;
3153831506 loc = make_location (loc, loc, end);
3153931507
31540- if (!attr_mode)
31541- parens.require_close (parser);
31542-
3154331508 /* Build a deferred-parse node. */
3154431509 tree condition = make_node (DEFERRED_PARSE);
3154531510 DEFPARSE_TOKENS (condition) = cp_token_cache_new (first, last);
@@ -31555,19 +31520,11 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3155531520 /* Enable location wrappers when parsing contracts. */
3155631521 auto suppression = make_temp_override (suppress_location_wrappers, 0);
3155731522
31558- /* If we have a current class object, see if we need to consider
31559- it const when processing the contract condition. */
31560- tree current_class_ref_copy = current_class_ref;
31561- if (should_constify && current_class_ref_copy)
31562- current_class_ref = view_as_const (current_class_ref_copy);
31563-
3156431523 /* Parse the condition, ensuring that parameters or the return variable
3156531524 aren't flagged for use outside the body of a function. */
3156631525 begin_scope (sk_contract, current_function_decl);
3156731526 bool old_pc = processing_postcondition;
31568- bool old_const = should_constify_contract;
3156931527 processing_postcondition = postcondition_p;
31570- should_constify_contract = should_constify;
3157131528 tree result = NULL_TREE;
3157231529 if (identifier)
3157331530 {
@@ -31581,30 +31538,22 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3158131538 if (identifier)
3158231539 --processing_template_decl;
3158331540 processing_postcondition = old_pc;
31584- should_constify_contract = old_const;
3158531541 gcc_checking_assert (scope_chain && scope_chain->bindings
3158631542 && scope_chain->bindings->kind == sk_contract);
3158731543 pop_bindings_and_leave_scope ();
3158831544
31589- /* Revert (any) constification of the current class object. */
31590- current_class_ref = current_class_ref_copy;
31591-
3159231545 if (contract != error_mark_node)
3159331546 {
3159431547 location_t end = cp_lexer_peek_token (parser->lexer)->location;
3159531548 loc = make_location (loc, loc, end);
3159631549 SET_EXPR_LOCATION (contract, loc);
3159731550 }
3159831551
31599- /* For natural syntax, we eat the parens here. For the attribute
31600- syntax, it will be done one level up, we just need to skip to it. */
31601- if (!attr_mode)
31602- parens.require_close (parser);
3160331552 /* Try to recover from errors by scanning up to the end of the
3160431553 attribute. Sometimes we get partially parsed expressions, so
3160531554 we need to search the condition for errors. */
31606- else if (contains_error_p (condition))
31607- cp_parser_skip_up_to_closing_square_bracket (parser);
31555+ if (contains_error_p (condition))
31556+ cp_parser_skip_up_to_closing_square_bracket (parser);
3160831557 }
3160931558
3161031559 if (!flag_contracts)
@@ -31613,10 +31562,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3161331562 return error_mark_node;
3161431563 }
3161531564
31616- /* Save the decision about const-ification. */
31617- if (contract != error_mark_node)
31618- set_contract_const (contract, should_constify);
31619-
3162031565 return finish_contract_attribute (attribute, contract);
3162131566}
3162231567
@@ -31731,10 +31676,8 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3173131676}
3173231677
3173331678static contract_modifier
31734- cp_parser_function_contract_modifier_opt (cp_parser * parser, bool attr_mode )
31679+ cp_parser_function_contract_modifier_opt (cp_parser * parser)
3173531680{
31736- if (!flag_contracts_nonattr || attr_mode)
31737- return {};
3173831681
3173931682 contract_modifier mod{};
3174031683 location_t first_const = UNKNOWN_LOCATION;
@@ -31837,10 +31780,130 @@ cp_parser_function_contract_specifier (cp_parser *parser)
3183731780
3183831781 // this does not currently handle attribute-specifier-seqopt for
3183931782 // a natural contract syntax.
31840- tree contract_attribute = cp_parser_contract_attribute_spec (parser,
31841- contract_name,
31842- false);
31843- return contract_attribute;
31783+
31784+ cp_lexer_consume_token (parser->lexer);
31785+ location_t loc = token->location;
31786+ bool postcondition_p = is_attribute_p ("post", contract_name);
31787+
31788+ /* Decide if the contract needs to be constified */
31789+ bool should_constify = true;
31790+
31791+ /* Parse experimental modifiers on C++26 contracts. */
31792+ contract_modifier modifier = cp_parser_function_contract_modifier_opt (
31793+ parser);
31794+
31795+ if (!modifier.error_p
31796+ && (modifier.mutable_p
31797+ || (flag_contracts_nonattr_const_keyword && !modifier.const_p)))
31798+ should_constify = false;
31799+
31800+ matching_parens parens;
31801+ parens.require_open (parser);
31802+
31803+ /* Check for postcondition identifiers. */
31804+ cp_expr identifier;
31805+ if (postcondition_p && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
31806+ && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON)
31807+ identifier = cp_parser_identifier (parser);
31808+ if (identifier == error_mark_node)
31809+ return error_mark_node;
31810+ else if (identifier)
31811+ cp_parser_require (parser, CPP_COLON, RT_COLON);
31812+
31813+ // Todo check what happens if we get error_mark_node in identifier. Do we recover gracefully ?
31814+
31815+ tree contract;
31816+ if (current_class_type &&
31817+ TYPE_BEING_DEFINED (current_class_type))
31818+ {
31819+ /* Defer the parsing of pre/post contracts inside class definitions. */
31820+ cp_token *first = cp_lexer_peek_token (parser->lexer);
31821+
31822+ /* Skip until we reach a closing token ). */
31823+ cp_parser_skip_to_closing_parenthesis_1 (parser,
31824+ /*recovering=*/false,
31825+ CPP_CLOSE_PAREN,
31826+ /*consume_paren=*/false);
31827+
31828+ cp_token *last = cp_lexer_peek_token (parser->lexer);
31829+ location_t end = last->location;
31830+ loc = make_location (loc, loc, end);
31831+
31832+ parens.require_close (parser);
31833+
31834+ /* Build a deferred-parse node. */
31835+ tree condition = make_node (DEFERRED_PARSE);
31836+ DEFPARSE_TOKENS (condition) = cp_token_cache_new (first, last);
31837+ DEFPARSE_INSTANTIATIONS (condition) = NULL;
31838+
31839+ /* And its corresponding contract. */
31840+ if (identifier)
31841+ identifier.maybe_add_location_wrapper ();
31842+ contract = grok_contract (contract_name, /*mode*/NULL_TREE, identifier,
31843+ condition, loc);
31844+ }
31845+ else
31846+ {
31847+ /* Enable location wrappers when parsing contracts. */
31848+ auto suppression = make_temp_override (suppress_location_wrappers, 0);
31849+
31850+ /* If we have a current class object, see if we need to consider
31851+ it const when processing the contract condition. */
31852+ tree current_class_ref_copy = current_class_ref;
31853+ if (should_constify && current_class_ref_copy)
31854+ current_class_ref = view_as_const (current_class_ref_copy);
31855+
31856+ /* Parse the condition, ensuring that parameters or the return variable
31857+ aren't flagged for use outside the body of a function. */
31858+ begin_scope (sk_contract, current_function_decl);
31859+ bool old_pc = processing_postcondition;
31860+ bool old_const = should_constify_contract;
31861+ processing_postcondition = postcondition_p;
31862+ should_constify_contract = should_constify;
31863+ tree result = NULL_TREE;
31864+ if (identifier)
31865+ {
31866+ /* Build a fake variable for the result identifier. */
31867+ result = make_postcondition_variable (identifier);
31868+ ++processing_template_decl;
31869+ }
31870+ cp_expr condition = cp_parser_conditional_expression (parser);
31871+ /* Build the contract. */
31872+ contract = grok_contract (contract_name, /*mode*/NULL_TREE, result,
31873+ condition, loc);
31874+ if (identifier)
31875+ --processing_template_decl;
31876+ processing_postcondition = old_pc;
31877+ should_constify_contract = old_const;
31878+ gcc_checking_assert (scope_chain && scope_chain->bindings
31879+ && scope_chain->bindings->kind == sk_contract);
31880+ pop_bindings_and_leave_scope ();
31881+
31882+ /* Revert (any) constification of the current class object. */
31883+ current_class_ref = current_class_ref_copy;
31884+
31885+ if (contract != error_mark_node)
31886+ {
31887+ location_t end = cp_lexer_peek_token (parser->lexer)->location;
31888+ loc = make_location (loc, loc, end);
31889+ SET_EXPR_LOCATION (contract, loc);
31890+ }
31891+
31892+ parens.require_close (parser);
31893+ }
31894+
31895+ if (!flag_contracts || !flag_contracts_nonattr)
31896+ {
31897+ error_at (loc, "P2900 contracts are only available with %<-fcontracts%>"
31898+ " and %<--fcontracts-nonattr%>");
31899+ return error_mark_node;
31900+ }
31901+
31902+ /* Save the decision about const-ification. */
31903+ if (contract != error_mark_node)
31904+ set_contract_const (contract, should_constify);
31905+
31906+ return finish_contract_attribute (contract_name, contract);
3184431907}
3184531908
3184631909/* Parse a natural syntax contract specifier seq. Returns a list of
@@ -31939,7 +32002,7 @@ cp_parser_std_attribute_spec (cp_parser *parser)
3193932002 /* Handle contract-attribute-specs specially. */
3194032003 if (attr_name && contract_attribute_p (attr_name))
3194132004 {
31942- tree attrs = cp_parser_contract_attribute_spec (parser, attr_name, true );
32005+ tree attrs = cp_parser_contract_attribute_spec (parser, attr_name);
3194332006 if (attrs != error_mark_node)
3194432007 attributes = attrs;
3194532008 goto finish_attrs;
0 commit comments