Skip to content

Commit 05e1e1d

Browse files
committed
c++, contracts: Use the saved_scope to carry state not globals.
This uses state local to the contract scopes to carry the information on const-ification and whether the current contract is a post. Note that if, for example, we had a lambda with a precondition in the defintion of a post-condition, the use of increment/decrement of a "postcondition" variable is not going to work properly. We also use a contract scope during template substitution so that we can check for that scope when deciding how to process. Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
1 parent d023152 commit 05e1e1d

File tree

5 files changed

+65
-71
lines changed

5 files changed

+65
-71
lines changed

gcc/cp/contracts.cc

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -606,14 +606,16 @@ make_postcondition_variable (cp_expr id, tree type)
606606
{
607607
if (id == error_mark_node)
608608
return id;
609+
gcc_checking_assert (scope_chain && scope_chain->bindings
610+
&& scope_chain->bindings->kind == sk_contract);
609611

610612
tree decl = build_lang_decl (PARM_DECL, id, type);
611613
DECL_ARTIFICIAL (decl) = true;
612614
DECL_SOURCE_LOCATION (decl) = id.get_location ();
613615

614-
// constify the postcondition variable
615-
if (flag_contracts_nonattr && !flag_contracts_nonattr_noconst)
616-
TREE_READONLY(decl) = true;
616+
/* Maybe constify the postcondition variable. */
617+
if (flag_contracts_nonattr && should_constify_contract)
618+
TREE_READONLY(decl) = true;
617619

618620
pushdecl (decl);
619621
return decl;
@@ -711,16 +713,24 @@ rebuild_postconditions (tree fndecl)
711713
t = TREE_CHAIN (t))
712714
register_local_identity (t);
713715

716+
begin_scope (sk_contract, fndecl);
717+
bool old_pc = processing_postcondition;
718+
bool old_const = should_constify_contract;
719+
processing_postcondition = true;
720+
should_constify_contract = get_contract_const (contract);
714721
register_local_specialization (newvar, oldvar);
715722

716-
++processing_contract_condition;
717723
condition = tsubst_expr (condition, make_tree_vec (0),
718724
tf_warning_or_error, fndecl);
719-
--processing_contract_condition;
720725

721726
/* Update the contract condition and result. */
722727
POSTCONDITION_IDENTIFIER (contract) = newvar;
723728
CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
729+
processing_postcondition = old_pc;
730+
should_constify_contract = old_const;
731+
gcc_checking_assert (scope_chain && scope_chain->bindings
732+
&& scope_chain->bindings->kind == sk_contract);
733+
pop_bindings_and_leave_scope ();
724734
}
725735
}
726736

@@ -2741,14 +2751,14 @@ constify_contract_access(tree decl)
27412751
/* Do not allow non-const by-value params being used in postconditions. */
27422752

27432753
bool
2744-
maybe_reject_param_in_postcondition(tree decl)
2754+
maybe_reject_param_in_postcondition (tree decl)
27452755
{
27462756
if (flag_contracts_nonattr
2747-
&& processing_contract_postcondition
2748-
&& !dependent_type_p (TREE_TYPE (decl))
27492757
&& !TREE_READONLY (decl)
2750-
&& !CP_TYPE_CONST_P (TREE_TYPE (decl))
27512758
&& TREE_CODE (decl) == PARM_DECL
2759+
&& processing_postcondition
2760+
&& !dependent_type_p (TREE_TYPE (decl))
2761+
&& !CP_TYPE_CONST_P (TREE_TYPE (decl))
27522762
&& !(REFERENCE_REF_P (decl)
27532763
&& TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL))
27542764
{

gcc/cp/cp-tree.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,8 +1951,6 @@ struct GTY(()) saved_scope {
19511951
int x_processing_template_decl;
19521952
int x_processing_specialization;
19531953
int x_processing_constraint;
1954-
int x_processing_contract_condition;
1955-
int x_processing_contract_postcondition;
19561954
int suppress_location_wrappers;
19571955
BOOL_BITFIELD x_processing_postcondition : 1;
19581956
BOOL_BITFIELD x_should_constify_contract : 1;
@@ -2033,12 +2031,11 @@ extern GTY(()) struct saved_scope *scope_chain;
20332031
#define processing_omp_trait_property_expr scope_chain->x_processing_omp_trait_property_expr
20342032

20352033
/* Nonzero if we are parsing the conditional expression of a contract
2036-
condition. These expressions appear outside the paramter list (like a
2034+
condition. These expressions appear outside the parameter list (like a
20372035
trailing return type), but are potentially evaluated. */
20382036

2039-
#define processing_contract_condition scope_chain->x_processing_contract_condition
2040-
2041-
#define processing_contract_postcondition scope_chain->x_processing_contract_postcondition
2037+
#define processing_contract_condition \
2038+
(scope_chain->bindings->kind == sk_contract)
20422039

20432040
#define processing_postcondition scope_chain->x_processing_postcondition
20442041
#define should_constify_contract scope_chain->x_should_constify_contract

gcc/cp/parser.cc

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13120,16 +13120,12 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
1312013120
0);
1312113121

1312213122
/* Do we have an override for const-ification? */
13123-
bool old_flag_contracts_nonattr_noconst
13124-
= flag_contracts_nonattr_noconst;
13125-
1312613123
bool should_constify = !flag_contracts_nonattr_noconst;
1312713124
if (!modifier.error_p
1312813125
&& (modifier.mutable_p
1312913126
|| (flag_contracts_nonattr_const_keyword
1313013127
&& !modifier.const_p)))
1313113128
should_constify = false;
13132-
flag_contracts_nonattr_noconst = !should_constify;
1313313129

1313413130
/* If we have a current class object, see if we need to consider
1313513131
it const when processing the contract condition. */
@@ -13138,28 +13134,30 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
1313813134
current_class_ref = view_as_const (current_class_ref_copy);
1313913135

1314013136
/* Parse the condition. */
13137+
tree contract = error_mark_node;
1314113138
begin_scope (sk_contract, current_function_decl);
13142-
++processing_contract_condition;
13139+
bool old_pc = processing_postcondition;
13140+
bool old_const = should_constify_contract;
1314313141
processing_postcondition = false;
1314413142
should_constify_contract = should_constify;
1314513143
cp_expr condition = cp_parser_conditional_expression (parser);
13146-
--processing_contract_condition;
13144+
gcc_checking_assert (scope_chain && scope_chain->bindings
13145+
&& scope_chain->bindings->kind == sk_contract);
13146+
/* Build the contract. */
13147+
contract
13148+
= grok_contract (cont_assert, /*mode*/NULL_TREE,
13149+
/*result*/NULL_TREE, condition, loc);
13150+
processing_postcondition = old_pc;
13151+
should_constify_contract = old_const;
1314713152
pop_bindings_and_leave_scope ();
1314813153

1314913154
/* Revert (any) constification of the current class object. */
1315013155
current_class_ref = current_class_ref_copy;
1315113156

13152-
flag_contracts_nonattr_noconst
13153-
= old_flag_contracts_nonattr_noconst;
13154-
1315513157
parens.require_close (parser);
13156-
/* Build the contract. */
13157-
tree contract
13158-
= grok_contract (cont_assert, /*mode*/NULL_TREE,
13159-
/*result*/NULL_TREE, condition, loc);
13158+
1316013159
if (contract != error_mark_node)
1316113160
set_contract_const (contract, should_constify);
13162-
1316313161
std_attrs = finish_contract_attribute (cont_assert, contract);
1316413162

1316513163
/* If there are errors in the contract, we do not create the
@@ -31376,10 +31374,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3137631374
/* Enable location wrappers when parsing contracts. */
3137731375
auto suppression = make_temp_override (suppress_location_wrappers, 0);
3137831376

31379-
bool old_flag_contracts_nonattr_noconst = flag_contracts_nonattr_noconst;
31380-
/* The should_constify value should account for all the mixed flags. */
31381-
flag_contracts_nonattr_noconst = !should_constify;
31382-
3138331377
/* If we have a current class object, see if we need to consider
3138431378
it const when processing the contract condition. */
3138531379
tree current_class_ref_copy = current_class_ref;
@@ -31389,31 +31383,30 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3138931383
/* Parse the condition, ensuring that parameters or the return variable
3139031384
aren't flagged for use outside the body of a function. */
3139131385
begin_scope (sk_contract, current_function_decl);
31392-
++processing_contract_condition;
31393-
if (postcondition_p)
31394-
++processing_contract_postcondition;
31386+
bool old_pc = processing_postcondition;
31387+
bool old_const = should_constify_contract;
31388+
processing_postcondition = postcondition_p;
31389+
should_constify_contract = should_constify;
3139531390
tree result = NULL_TREE;
3139631391
if (identifier)
3139731392
{
3139831393
/* Build a fake variable for the result identifier. */
3139931394
result = make_postcondition_variable (identifier);
3140031395
++processing_template_decl;
3140131396
}
31402-
processing_postcondition = postcondition_p;
31403-
should_constify_contract = should_constify;
3140431397
cp_expr condition = cp_parser_conditional_expression (parser);
3140531398
/* Build the contract. */
3140631399
contract = grok_contract (attribute, mode, result, condition, loc);
3140731400
if (identifier)
3140831401
--processing_template_decl;
31409-
if (postcondition_p)
31410-
--processing_contract_postcondition;
31411-
--processing_contract_condition;
31402+
processing_postcondition = old_pc;
31403+
should_constify_contract = old_const;
31404+
gcc_checking_assert (scope_chain && scope_chain->bindings
31405+
&& scope_chain->bindings->kind == sk_contract);
3141231406
pop_bindings_and_leave_scope ();
3141331407

3141431408
/* Revert (any) constification of the current class object. */
3141531409
current_class_ref = current_class_ref_copy;
31416-
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
3141731410

3141831411
/* For natural syntax, we eat the parens here. For the attribute
3141931412
syntax, it will be done one level up, we just need to skip to it. */
@@ -31498,7 +31491,6 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3149831491
cp_token_cache *tokens = DEFPARSE_TOKENS (condition);
3149931492
cp_parser_push_lexer_for_tokens (parser, tokens);
3150031493

31501-
bool old_flag_contracts_nonattr_noconst = flag_contracts_nonattr_noconst;
3150231494
bool should_constify = get_contract_const (contract);
3150331495
/* If we have a current class object, see if we need to consider
3150431496
it const when processing the contract condition. */
@@ -31509,9 +31501,10 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3150931501
/* Parse the condition, ensuring that parameters or the return variable
3151031502
aren't flagged for use outside the body of a function. */
3151131503
begin_scope (sk_contract, fn);
31512-
++processing_contract_condition;
31513-
if (POSTCONDITION_P (contract))
31514-
++processing_contract_postcondition;
31504+
bool old_pc = processing_postcondition;
31505+
bool old_const = should_constify_contract;
31506+
processing_postcondition = POSTCONDITION_P (contract);
31507+
should_constify_contract = should_constify;
3151531508
/* Build a fake variable for the result identifier. */
3151631509
tree result = NULL_TREE;
3151731510
if (identifier)
@@ -31523,15 +31516,14 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3152331516
/* Commit to changes. */
3152431517
update_late_contract (contract, result, condition);
3152531518
/* Leave our temporary scope for the postcondition result. */
31526-
if (result)
31519+
if (identifier)
3152731520
--processing_template_decl;
31528-
if (POSTCONDITION_P (contract))
31529-
--processing_contract_postcondition;
31530-
--processing_contract_condition;
31521+
processing_postcondition = old_pc;
31522+
should_constify_contract = old_const;
31523+
gcc_checking_assert (scope_chain && scope_chain->bindings
31524+
&& scope_chain->bindings->kind == sk_contract);
3153131525
pop_bindings_and_leave_scope ();
3153231526

31533-
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
31534-
3153531527
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
3153631528
error_at (input_location, "expected conditional-expression");
3153731529

gcc/cp/pt.cc

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12043,19 +12043,16 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
1204312043
return invalidate_contract (r);
1204412044
}
1204512045

12046-
/* Should we const-ify this condition? */
12047-
bool old_flag_contracts_nonattr_noconst = flag_contracts_nonattr_noconst;
12048-
bool const_p = get_contract_const (t);
12049-
flag_contracts_nonattr_noconst = !const_p;
12050-
1205112046
/* Instantiate the condition. If the return type is undeduced, process
1205212047
the expression as if inside a template to avoid spurious type errors. */
1205312048
begin_scope (sk_contract, decl);
12054-
++processing_contract_condition;
12049+
bool old_pc = processing_postcondition;
12050+
bool old_const = should_constify_contract;
12051+
processing_postcondition = POSTCONDITION_P (t);
12052+
/* Should we const-ify this condition? */
12053+
should_constify_contract = get_contract_const (t);
1205512054
if (auto_p)
1205612055
++processing_template_decl;
12057-
if (POSTCONDITION_P (t))
12058-
++processing_contract_postcondition;
1205912056
if (newvar)
1206012057
/* Make the variable available for lookup. */
1206112058
register_local_specialization (newvar, oldvar);
@@ -12067,13 +12064,13 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
1206712064
CONTRACT_COMMENT (r)
1206812065
= tsubst_expr (CONTRACT_COMMENT (r), args, complain, in_decl);
1206912066

12070-
if (POSTCONDITION_P (t))
12071-
--processing_contract_postcondition;
1207212067
if (auto_p)
1207312068
--processing_template_decl;
12074-
--processing_contract_condition;
12069+
processing_postcondition = old_pc;
12070+
should_constify_contract = old_const;
12071+
gcc_checking_assert (scope_chain && scope_chain->bindings
12072+
&& scope_chain->bindings->kind == sk_contract);
1207512073
pop_bindings_and_leave_scope ();
12076-
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
1207712074

1207812075
return r;
1207912076
}
@@ -21957,7 +21954,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
2195721954
declaration (such as in a late-specified return type). Just
2195821955
make a dummy decl, since it's only used for its type. */
2195921956
gcc_assert (cp_unevaluated_operand
21960-
|| processing_contract_postcondition);
21957+
|| processing_postcondition);
2196121958
r = tsubst_decl (t, args, complain);
2196221959
/* Give it the template pattern as its context; its true context
2196321960
hasn't been instantiated yet and this is good enough for
@@ -22362,7 +22359,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
2236222359

2236322360
maybe_reject_param_in_postcondition (op);
2236422361

22365-
if (flag_contracts_nonattr && !flag_contracts_nonattr_noconst
22362+
if (flag_contracts_nonattr && should_constify_contract
2236622363
&& processing_contract_condition)
2236722364
op = constify_contract_access(op);
2236822365

gcc/cp/semantics.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4932,12 +4932,10 @@ finish_id_expression_1 (tree id_expression,
49324932
}
49334933

49344934
maybe_reject_param_in_postcondition (decl);
4935-
4936-
if (flag_contracts_nonattr && !flag_contracts_nonattr_noconst
4935+
if (flag_contracts_nonattr && should_constify_contract
49374936
&& processing_contract_condition)
4938-
{
4939-
decl = constify_contract_access(decl);
4940-
}
4937+
decl = constify_contract_access(decl);
4938+
49414939
return cp_expr (decl, location);
49424940
}
49434941

0 commit comments

Comments
 (0)