@@ -2951,7 +2951,7 @@ struct contract_modifier {
2951
2951
};
2952
2952
2953
2953
static contract_modifier cp_parser_function_contract_modifier_opt
2954
- (cp_parser *, bool );
2954
+ (cp_parser *);
2955
2955
2956
2956
static tree cp_parser_function_contract_specifier
2957
2957
(cp_parser *);
@@ -13211,8 +13211,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
13211
13211
cp_token *token = cp_lexer_consume_token (parser->lexer);
13212
13212
location_t loc = token->location;
13213
13213
contract_modifier modifier
13214
- = cp_parser_function_contract_modifier_opt (parser,
13215
- /*attr_mode*/false);
13214
+ = cp_parser_function_contract_modifier_opt (parser);
13216
13215
13217
13216
matching_parens parens;
13218
13217
parens.require_open (parser);
@@ -31459,8 +31458,7 @@ contains_error_p (tree t)
31459
31458
placeholder. */
31460
31459
31461
31460
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)
31464
31462
{
31465
31463
gcc_assert (contract_attribute_p (attribute));
31466
31464
cp_token *token = cp_lexer_consume_token (parser->lexer);
@@ -31471,16 +31469,9 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31471
31469
31472
31470
/* For C++20 contract attributes, parse the optional mode. */
31473
31471
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);
31480
31473
31481
31474
matching_parens parens;
31482
- if (flag_contracts_nonattr && !attr_mode)
31483
- parens.require_open (parser);
31484
31475
31485
31476
/* Check for postcondition identifiers. */
31486
31477
cp_expr identifier;
@@ -31490,22 +31481,7 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31490
31481
if (identifier == error_mark_node)
31491
31482
return error_mark_node;
31492
31483
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);
31509
31485
31510
31486
tree contract;
31511
31487
if (!assertion_p &&
@@ -31514,32 +31490,21 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31514
31490
{
31515
31491
/* Defer the parsing of pre/post contracts inside class definitions. */
31516
31492
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. */
31535
31503
31536
31504
cp_token *last = cp_lexer_peek_token (parser->lexer);
31537
31505
location_t end = last->location;
31538
31506
loc = make_location (loc, loc, end);
31539
31507
31540
- if (!attr_mode)
31541
- parens.require_close (parser);
31542
-
31543
31508
/* Build a deferred-parse node. */
31544
31509
tree condition = make_node (DEFERRED_PARSE);
31545
31510
DEFPARSE_TOKENS (condition) = cp_token_cache_new (first, last);
@@ -31555,19 +31520,11 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31555
31520
/* Enable location wrappers when parsing contracts. */
31556
31521
auto suppression = make_temp_override (suppress_location_wrappers, 0);
31557
31522
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
-
31564
31523
/* Parse the condition, ensuring that parameters or the return variable
31565
31524
aren't flagged for use outside the body of a function. */
31566
31525
begin_scope (sk_contract, current_function_decl);
31567
31526
bool old_pc = processing_postcondition;
31568
- bool old_const = should_constify_contract;
31569
31527
processing_postcondition = postcondition_p;
31570
- should_constify_contract = should_constify;
31571
31528
tree result = NULL_TREE;
31572
31529
if (identifier)
31573
31530
{
@@ -31581,30 +31538,22 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31581
31538
if (identifier)
31582
31539
--processing_template_decl;
31583
31540
processing_postcondition = old_pc;
31584
- should_constify_contract = old_const;
31585
31541
gcc_checking_assert (scope_chain && scope_chain->bindings
31586
31542
&& scope_chain->bindings->kind == sk_contract);
31587
31543
pop_bindings_and_leave_scope ();
31588
31544
31589
- /* Revert (any) constification of the current class object. */
31590
- current_class_ref = current_class_ref_copy;
31591
-
31592
31545
if (contract != error_mark_node)
31593
31546
{
31594
31547
location_t end = cp_lexer_peek_token (parser->lexer)->location;
31595
31548
loc = make_location (loc, loc, end);
31596
31549
SET_EXPR_LOCATION (contract, loc);
31597
31550
}
31598
31551
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);
31603
31552
/* Try to recover from errors by scanning up to the end of the
31604
31553
attribute. Sometimes we get partially parsed expressions, so
31605
31554
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);
31608
31557
}
31609
31558
31610
31559
if (!flag_contracts)
@@ -31613,10 +31562,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
31613
31562
return error_mark_node;
31614
31563
}
31615
31564
31616
- /* Save the decision about const-ification. */
31617
- if (contract != error_mark_node)
31618
- set_contract_const (contract, should_constify);
31619
-
31620
31565
return finish_contract_attribute (attribute, contract);
31621
31566
}
31622
31567
@@ -31731,10 +31676,8 @@ void cp_parser_late_contract_condition (cp_parser *parser,
31731
31676
}
31732
31677
31733
31678
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)
31735
31680
{
31736
- if (!flag_contracts_nonattr || attr_mode)
31737
- return {};
31738
31681
31739
31682
contract_modifier mod{};
31740
31683
location_t first_const = UNKNOWN_LOCATION;
@@ -31837,10 +31780,130 @@ cp_parser_function_contract_specifier (cp_parser *parser)
31837
31780
31838
31781
// this does not currently handle attribute-specifier-seqopt for
31839
31782
// 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);
31844
31907
}
31845
31908
31846
31909
/* Parse a natural syntax contract specifier seq. Returns a list of
@@ -31939,7 +32002,7 @@ cp_parser_std_attribute_spec (cp_parser *parser)
31939
32002
/* Handle contract-attribute-specs specially. */
31940
32003
if (attr_name && contract_attribute_p (attr_name))
31941
32004
{
31942
- tree attrs = cp_parser_contract_attribute_spec (parser, attr_name, true );
32005
+ tree attrs = cp_parser_contract_attribute_spec (parser, attr_name);
31943
32006
if (attrs != error_mark_node)
31944
32007
attributes = attrs;
31945
32008
goto finish_attrs;
0 commit comments