Skip to content

Commit eda89da

Browse files
committed
split p2900 and c++20 contract parsing
1 parent e85fb6e commit eda89da

File tree

1 file changed

+143
-80
lines changed

1 file changed

+143
-80
lines changed

gcc/cp/parser.cc

Lines changed: 143 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,7 +2951,7 @@ struct contract_modifier {
29512951
};
29522952

29532953
static contract_modifier cp_parser_function_contract_modifier_opt
2954-
(cp_parser *, bool);
2954+
(cp_parser *);
29552955

29562956
static 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

3146131460
static 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

3173331678
static 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

Comments
 (0)