Skip to content

Commit 63117ea

Browse files
committed
c++, contracts: Move result decls into contract scope.
Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
1 parent 219c3c7 commit 63117ea

File tree

3 files changed

+91
-60
lines changed

3 files changed

+91
-60
lines changed

gcc/cp/parser.cc

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31376,15 +31376,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3137631376
/* Enable location wrappers when parsing contracts. */
3137731377
auto suppression = make_temp_override (suppress_location_wrappers, 0);
3137831378

31379-
/* Build a fake variable for the result identifier. */
31380-
tree result = NULL_TREE;
31381-
if (identifier)
31382-
{
31383-
begin_scope (sk_block, NULL_TREE);
31384-
result = make_postcondition_variable (identifier);
31385-
++processing_template_decl;
31386-
}
31387-
3138831379
bool old_flag_contracts_nonattr_noconst = flag_contracts_nonattr_noconst;
3138931380
/* The should_constify value should account for all the mixed flags. */
3139031381
flag_contracts_nonattr_noconst = !should_constify;
@@ -31401,13 +31392,25 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3140131392
++processing_contract_condition;
3140231393
if (postcondition_p)
3140331394
++processing_contract_postcondition;
31395+
tree result = NULL_TREE;
31396+
if (identifier)
31397+
{
31398+
/* Build a fake variable for the result identifier. */
31399+
result = make_postcondition_variable (identifier);
31400+
++processing_template_decl;
31401+
}
3140431402
processing_postcondition = postcondition_p;
3140531403
should_constify_contract = should_constify;
3140631404
cp_expr condition = cp_parser_conditional_expression (parser);
31405+
/* Build the contract. */
31406+
contract = grok_contract (attribute, mode, result, condition, loc);
31407+
if (identifier)
31408+
--processing_template_decl;
3140731409
if (postcondition_p)
3140831410
--processing_contract_postcondition;
3140931411
--processing_contract_condition;
3141031412
pop_bindings_and_leave_scope ();
31413+
3141131414
/* Revert (any) constification of the current class object. */
3141231415
current_class_ref = current_class_ref_copy;
3141331416
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
@@ -31421,15 +31424,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3142131424
we need to search the condition for errors. */
3142231425
else if (contains_error_p (condition))
3142331426
cp_parser_skip_up_to_closing_square_bracket (parser);
31424-
31425-
/* Build the contract. */
31426-
contract = grok_contract (attribute, mode, result, condition, loc);
31427-
/* Leave our temporary scope for the postcondition result. */
31428-
if (result)
31429-
{
31430-
--processing_template_decl;
31431-
pop_bindings_and_leave_scope ();
31432-
}
3143331427
}
3143431428

3143531429
if (!flag_contracts)
@@ -31463,22 +31457,16 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3146331457
if (TREE_CODE (contract) == POSTCONDITION_STMT)
3146431458
identifier = POSTCONDITION_IDENTIFIER (contract);
3146531459

31466-
/* Build a fake variable for the result identifier. */
31467-
tree result = NULL_TREE;
31460+
tree type = TREE_TYPE (TREE_TYPE (fn));
3146831461
if (identifier)
3146931462
{
3147031463
/* TODO: Can we guarantee that the identifier has a location? */
3147131464
location_t loc = cp_expr_location (contract);
31472-
tree type = TREE_TYPE (TREE_TYPE (fn));
3147331465
if (!check_postcondition_result (fn, type, loc))
3147431466
{
3147531467
invalidate_contract (contract);
3147631468
return;
3147731469
}
31478-
31479-
begin_scope (sk_block, NULL_TREE);
31480-
result = make_postcondition_variable (identifier, type);
31481-
++processing_template_decl;
3148231470
}
3148331471

3148431472
/* In C++20 contracts, 'this' is not allowed in preconditions of
@@ -31524,15 +31512,28 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3152431512
++processing_contract_condition;
3152531513
if (POSTCONDITION_P (contract))
3152631514
++processing_contract_postcondition;
31515+
/* Build a fake variable for the result identifier. */
31516+
tree result = NULL_TREE;
31517+
if (identifier)
31518+
{
31519+
result = make_postcondition_variable (identifier, type);
31520+
++processing_template_decl;
31521+
}
3152731522
condition = cp_parser_conditional_expression (parser);
31523+
/* Commit to changes. */
31524+
update_late_contract (contract, result, condition);
31525+
/* Leave our temporary scope for the postcondition result. */
31526+
if (result)
31527+
--processing_template_decl;
3152831528
if (POSTCONDITION_P (contract))
3152931529
--processing_contract_postcondition;
3153031530
--processing_contract_condition;
3153131531
pop_bindings_and_leave_scope ();
3153231532

31533+
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
31534+
3153331535
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
31534-
error_at (input_location,
31535-
"expected conditional-expression");
31536+
error_at (input_location, "expected conditional-expression");
3153631537

3153731538
/* Revert to the main lexer. */
3153831539
cp_parser_pop_lexer (parser);
@@ -31543,17 +31544,6 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3154331544
current_class_ref = saved_ccr;
3154431545
current_class_ptr = saved_ccp;
3154531546
contract_class_ptr = saved_contract_ccp;
31546-
31547-
/* Commit to changes. */
31548-
update_late_contract (contract, result, condition);
31549-
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
31550-
31551-
/* Leave our temporary scope for the postcondition result. */
31552-
if (result)
31553-
{
31554-
--processing_template_decl;
31555-
pop_bindings_and_leave_scope ();
31556-
}
3155731547
}
3155831548

3155931549
static contract_modifier

gcc/cp/pt.cc

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12025,12 +12025,13 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
1202512025

1202612026
tree r = copy_node (t);
1202712027

12028-
/* Rebuild the result variable. */
12028+
/* Rebuild the result variable, if present. */
12029+
tree oldvar = NULL_TREE;
12030+
tree newvar = NULL_TREE;
1202912031
if (type && POSTCONDITION_P (t) && POSTCONDITION_IDENTIFIER (t))
1203012032
{
12031-
tree oldvar = POSTCONDITION_IDENTIFIER (t);
12032-
12033-
tree newvar = copy_node (oldvar);
12033+
oldvar = POSTCONDITION_IDENTIFIER (t);
12034+
newvar = copy_node (oldvar);
1203412035
TREE_TYPE (newvar) = type;
1203512036
DECL_CONTEXT (newvar) = decl;
1203612037
POSTCONDITION_IDENTIFIER (r) = newvar;
@@ -12040,34 +12041,38 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
1204012041
if (!auto_p)
1204112042
if (!check_postcondition_result (decl, type, loc))
1204212043
return invalidate_contract (r);
12043-
12044-
/* Make the variable available for lookup. */
12045-
register_local_specialization (newvar, oldvar);
1204612044
}
1204712045

12048-
/* Instantiate the condition. If the return type is undeduced, process
12049-
the expression as if inside a template to avoid spurious type errors. */
12050-
bool const_p = get_contract_const (t);
12046+
/* Should we const-ify this condition? */
1205112047
bool old_flag_contracts_nonattr_noconst = flag_contracts_nonattr_noconst;
12048+
bool const_p = get_contract_const (t);
1205212049
flag_contracts_nonattr_noconst = !const_p;
1205312050

12051+
/* Instantiate the condition. If the return type is undeduced, process
12052+
the expression as if inside a template to avoid spurious type errors. */
12053+
begin_scope (sk_contract, decl);
12054+
++processing_contract_condition;
1205412055
if (auto_p)
1205512056
++processing_template_decl;
12056-
++processing_contract_condition;
1205712057
if (POSTCONDITION_P (t))
1205812058
++processing_contract_postcondition;
12059+
if (newvar)
12060+
/* Make the variable available for lookup. */
12061+
register_local_specialization (newvar, oldvar);
1205912062

1206012063
CONTRACT_CONDITION (r)
1206112064
= tsubst_expr (CONTRACT_CONDITION (t), args, complain, in_decl);
12062-
if (POSTCONDITION_P (t))
12063-
--processing_contract_postcondition;
12064-
--processing_contract_condition;
12065-
if (auto_p)
12066-
--processing_template_decl;
1206712065

1206812066
/* And the comment. */
1206912067
CONTRACT_COMMENT (r)
1207012068
= tsubst_expr (CONTRACT_COMMENT (r), args, complain, in_decl);
12069+
12070+
if (POSTCONDITION_P (t))
12071+
--processing_contract_postcondition;
12072+
if (auto_p)
12073+
--processing_template_decl;
12074+
--processing_contract_condition;
12075+
pop_bindings_and_leave_scope ();
1207112076
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
1207212077

1207312078
return r;
@@ -12120,14 +12125,12 @@ tsubst_contract_attribute (tree decl, tree t, tree args,
1212012125
as needed. */
1212112126

1212212127
void
12123-
tsubst_contract_attributes (tree decl, tree args, tsubst_flags_t complain, tree in_decl)
12128+
tsubst_contract_attributes (tree decl, tree args, tsubst_flags_t complain,
12129+
tree in_decl)
1212412130
{
1212512131
tree list = copy_list (DECL_ATTRIBUTES (decl));
12126-
for (tree attr = list; attr; attr = CONTRACT_CHAIN (attr))
12127-
{
12128-
if (cxx_contract_attribute_p (attr))
12129-
tsubst_contract_attribute (decl, attr, args, complain, in_decl);
12130-
}
12132+
for (tree attr = find_contract (list); attr; attr = CONTRACT_CHAIN (attr))
12133+
tsubst_contract_attribute (decl, attr, args, complain, in_decl);
1213112134
DECL_ATTRIBUTES (decl) = list;
1213212135
}
1213312136

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// { dg-options "-std=c++23 -fcontracts -fcontracts-nonattr" }
2+
3+
// Check that result vars are not visible in function bodies.
4+
5+
int free_fn (int x)
6+
post (r: r > 5);
7+
8+
int free_fn (int x)
9+
post (r: r > 5)
10+
{ r += 1; return r;} // { dg-error {'r' was not declared in this scope} }
11+
12+
struct X {
13+
int fn0 (int x)
14+
post (res: res > 5)
15+
{ res = 15; return res; } // { dg-error {'res' was not declared in this scope} }
16+
17+
int fn1 (int x)
18+
post (res: res > 5);
19+
};
20+
21+
int
22+
X::fn1 (int y)
23+
post (ans: ans > 5)
24+
{ ans = 15; return 1; } // { dg-error {'ans' was not declared in this scope} }
25+
26+
template <class T>
27+
int
28+
postcond (T x) post (res: res > 3);
29+
30+
template <class T>
31+
int
32+
postcond (T x) post (out: out > 3)
33+
{ out = 5; return x; } // { dg-error {'out' was not declared in this scope} }
34+
35+
int foo (int x)
36+
{
37+
return postcond (4);
38+
}

0 commit comments

Comments
 (0)