Skip to content

Commit a5b530a

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

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
@@ -31507,15 +31507,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3150731507
/* Enable location wrappers when parsing contracts. */
3150831508
auto suppression = make_temp_override (suppress_location_wrappers, 0);
3150931509

31510-
/* Build a fake variable for the result identifier. */
31511-
tree result = NULL_TREE;
31512-
if (identifier)
31513-
{
31514-
begin_scope (sk_block, NULL_TREE);
31515-
result = make_postcondition_variable (identifier);
31516-
++processing_template_decl;
31517-
}
31518-
3151931510
bool old_flag_contracts_nonattr_noconst = flag_contracts_nonattr_noconst;
3152031511
/* The should_constify value should account for all the mixed flags. */
3152131512
flag_contracts_nonattr_noconst = !should_constify;
@@ -31532,13 +31523,25 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3153231523
++processing_contract_condition;
3153331524
if (postcondition_p)
3153431525
++processing_contract_postcondition;
31526+
tree result = NULL_TREE;
31527+
if (identifier)
31528+
{
31529+
/* Build a fake variable for the result identifier. */
31530+
result = make_postcondition_variable (identifier);
31531+
++processing_template_decl;
31532+
}
3153531533
processing_postcondition = postcondition_p;
3153631534
should_constify_contract = should_constify;
3153731535
cp_expr condition = cp_parser_conditional_expression (parser);
31536+
/* Build the contract. */
31537+
contract = grok_contract (attribute, mode, result, condition, loc);
31538+
if (identifier)
31539+
--processing_template_decl;
3153831540
if (postcondition_p)
3153931541
--processing_contract_postcondition;
3154031542
--processing_contract_condition;
3154131543
pop_bindings_and_leave_scope ();
31544+
3154231545
/* Revert (any) constification of the current class object. */
3154331546
current_class_ref = current_class_ref_copy;
3154431547
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
@@ -31552,15 +31555,6 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute,
3155231555
we need to search the condition for errors. */
3155331556
else if (contains_error_p (condition))
3155431557
cp_parser_skip_up_to_closing_square_bracket (parser);
31555-
31556-
/* Build the contract. */
31557-
contract = grok_contract (attribute, mode, result, condition, loc);
31558-
/* Leave our temporary scope for the postcondition result. */
31559-
if (result)
31560-
{
31561-
--processing_template_decl;
31562-
pop_bindings_and_leave_scope ();
31563-
}
3156431558
}
3156531559

3156631560
if (!flag_contracts)
@@ -31594,22 +31588,16 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3159431588
if (TREE_CODE (contract) == POSTCONDITION_STMT)
3159531589
identifier = POSTCONDITION_IDENTIFIER (contract);
3159631590

31597-
/* Build a fake variable for the result identifier. */
31598-
tree result = NULL_TREE;
31591+
tree type = TREE_TYPE (TREE_TYPE (fn));
3159931592
if (identifier)
3160031593
{
3160131594
/* TODO: Can we guarantee that the identifier has a location? */
3160231595
location_t loc = cp_expr_location (contract);
31603-
tree type = TREE_TYPE (TREE_TYPE (fn));
3160431596
if (!check_postcondition_result (fn, type, loc))
3160531597
{
3160631598
invalidate_contract (contract);
3160731599
return;
3160831600
}
31609-
31610-
begin_scope (sk_block, NULL_TREE);
31611-
result = make_postcondition_variable (identifier, type);
31612-
++processing_template_decl;
3161331601
}
3161431602

3161531603
/* In C++20 contracts, 'this' is not allowed in preconditions of
@@ -31655,15 +31643,28 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3165531643
++processing_contract_condition;
3165631644
if (POSTCONDITION_P (contract))
3165731645
++processing_contract_postcondition;
31646+
/* Build a fake variable for the result identifier. */
31647+
tree result = NULL_TREE;
31648+
if (identifier)
31649+
{
31650+
result = make_postcondition_variable (identifier, type);
31651+
++processing_template_decl;
31652+
}
3165831653
condition = cp_parser_conditional_expression (parser);
31654+
/* Commit to changes. */
31655+
update_late_contract (contract, result, condition);
31656+
/* Leave our temporary scope for the postcondition result. */
31657+
if (result)
31658+
--processing_template_decl;
3165931659
if (POSTCONDITION_P (contract))
3166031660
--processing_contract_postcondition;
3166131661
--processing_contract_condition;
3166231662
pop_bindings_and_leave_scope ();
3166331663

31664+
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
31665+
3166431666
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
31665-
error_at (input_location,
31666-
"expected conditional-expression");
31667+
error_at (input_location, "expected conditional-expression");
3166731668

3166831669
/* Revert to the main lexer. */
3166931670
cp_parser_pop_lexer (parser);
@@ -31674,17 +31675,6 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3167431675
current_class_ref = saved_ccr;
3167531676
current_class_ptr = saved_ccp;
3167631677
contract_class_ptr = saved_contract_ccp;
31677-
31678-
/* Commit to changes. */
31679-
update_late_contract (contract, result, condition);
31680-
flag_contracts_nonattr_noconst = old_flag_contracts_nonattr_noconst;
31681-
31682-
/* Leave our temporary scope for the postcondition result. */
31683-
if (result)
31684-
{
31685-
--processing_template_decl;
31686-
pop_bindings_and_leave_scope ();
31687-
}
3168831678
}
3168931679

3169031680
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)