Skip to content

Commit a3a3c5d

Browse files
Merge pull request gcc-mirror#101 from NinaRanns/contracts_ICE_github_issue_29
addressing an ICE due to folding of original contracts
2 parents f7e7116 + 0a7bd2e commit a3a3c5d

File tree

5 files changed

+132
-38
lines changed

5 files changed

+132
-38
lines changed

gcc/cp/contracts.cc

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,26 +2651,6 @@ emit_contract_attr (tree attr)
26512651
emit_contract_statement (CONTRACT_STATEMENT (attr));
26522652
}
26532653

2654-
/* Add the statements of contract attributes ATTRS of the type specified
2655-
with CODE to the current block. */
2656-
2657-
static void
2658-
emit_contract_conditions (tree attrs, tree_code code)
2659-
{
2660-
if (!attrs) return;
2661-
gcc_checking_assert (TREE_CODE (attrs) == TREE_LIST);
2662-
gcc_checking_assert (code == PRECONDITION_STMT
2663-
|| code == POSTCONDITION_STMT);
2664-
for (attrs = find_contract (attrs); attrs;
2665-
attrs = CONTRACT_CHAIN (attrs))
2666-
{
2667-
tree contract = CONTRACT_STATEMENT (attrs);
2668-
if (TREE_CODE (contract) != code)
2669-
continue;
2670-
emit_contract_attr (attrs);
2671-
}
2672-
}
2673-
26742654
/* Emit the statement for an assertion attribute. */
26752655

26762656
void
@@ -2691,22 +2671,6 @@ emit_assertion (tree attr)
26912671
}
26922672
}
26932673

2694-
/* Emit statements for precondition attributes. */
2695-
2696-
static void
2697-
emit_preconditions (tree attr)
2698-
{
2699-
return emit_contract_conditions (attr, PRECONDITION_STMT);
2700-
}
2701-
2702-
/* Emit statements for postcondition attributes. */
2703-
2704-
static void
2705-
emit_postconditions (tree attr)
2706-
{
2707-
return emit_contract_conditions (attr, POSTCONDITION_STMT);
2708-
}
2709-
27102674
/* We're compiling the pre/postcondition function CONDFN; remap any FN
27112675
attributes that match CODE and emit them. */
27122676

@@ -3010,6 +2974,72 @@ add_post_condition_fn_call (tree fndecl)
30102974
finish_expr_stmt (call);
30112975
}
30122976

2977+
/* Returns a copy of FNDECL contracts. This is used when emiting a contract.
2978+
If we were to emit the original contract tree, any folding of the contract
2979+
condition would affect the original contract too. The original contract
2980+
tree needs to be preserved in case it is used to apply to a different
2981+
function (for inheritance or wrapping reasons). */
2982+
2983+
tree
2984+
copy_contracts (tree fndecl, contract_match_kind remap_kind = cmk_all )
2985+
{
2986+
tree last = NULL_TREE, contract_attrs = NULL_TREE;
2987+
for (tree a = DECL_CONTRACTS (fndecl);
2988+
a != NULL_TREE;
2989+
a = CONTRACT_CHAIN (a))
2990+
{
2991+
if ((remap_kind == cmk_pre
2992+
&& (TREE_CODE (CONTRACT_STATEMENT (a)) == POSTCONDITION_STMT))
2993+
|| (remap_kind == cmk_post
2994+
&& (TREE_CODE (CONTRACT_STATEMENT (a)) == PRECONDITION_STMT)))
2995+
continue;
2996+
2997+
tree c = copy_node (a);
2998+
TREE_VALUE (c) = build_tree_list (TREE_PURPOSE (TREE_VALUE (c)),
2999+
copy_node (CONTRACT_STATEMENT (c)));
3000+
3001+
copy_body_data id;
3002+
hash_map<tree, tree> decl_map;
3003+
3004+
memset (&id, 0, sizeof (id));
3005+
3006+
id.src_fn = fndecl;
3007+
id.dst_fn = fndecl;
3008+
id.src_cfun = DECL_STRUCT_FUNCTION (fndecl);
3009+
id.decl_map = &decl_map;
3010+
3011+
id.copy_decl = retain_decl;
3012+
3013+
id.transform_call_graph_edges = CB_CGE_DUPLICATE;
3014+
id.transform_new_cfg = false;
3015+
id.transform_return_to_modify = false;
3016+
id.transform_parameter = true;
3017+
3018+
/* Make sure not to unshare trees behind the front-end's back
3019+
since front-end specific mechanisms may rely on sharing. */
3020+
id.regimplify = false;
3021+
id.do_not_unshare = true;
3022+
id.do_not_fold = true;
3023+
3024+
/* We're not inside any EH region. */
3025+
id.eh_lp_nr = 0;
3026+
walk_tree (&CONTRACT_CONDITION (CONTRACT_STATEMENT (c)),
3027+
copy_tree_body_r, &id, NULL);
3028+
3029+
3030+
CONTRACT_COMMENT (CONTRACT_STATEMENT (c))
3031+
= copy_node (CONTRACT_COMMENT (CONTRACT_STATEMENT (c)));
3032+
3033+
chainon (last, c);
3034+
last = c;
3035+
if (!contract_attrs)
3036+
contract_attrs = c;
3037+
}
3038+
3039+
return contract_attrs;
3040+
}
3041+
3042+
30133043
/* Add a call or a direct evaluation of the pre checks. */
30143044

30153045
static void
@@ -3018,7 +3048,11 @@ apply_preconditions (tree fndecl)
30183048
if (outline_contracts_p (fndecl))
30193049
add_pre_condition_fn_call (fndecl);
30203050
else
3021-
emit_preconditions (DECL_CONTRACTS (fndecl));
3051+
{
3052+
tree contract_copy = copy_contracts (fndecl, cmk_pre);
3053+
for (; contract_copy; contract_copy = CONTRACT_CHAIN (contract_copy))
3054+
emit_contract_attr (contract_copy);
3055+
}
30223056
}
30233057

30243058
/* Add a call or a direct evaluation of the post checks. */
@@ -3029,7 +3063,11 @@ apply_postconditions (tree fndecl)
30293063
if (outline_contracts_p (fndecl))
30303064
add_post_condition_fn_call (fndecl);
30313065
else
3032-
emit_postconditions (DECL_CONTRACTS (fndecl));
3066+
{
3067+
tree contract_copy = copy_contracts (fndecl, cmk_post);
3068+
for (; contract_copy; contract_copy = CONTRACT_CHAIN (contract_copy))
3069+
emit_contract_attr (contract_copy);
3070+
}
30333071
}
30343072

30353073
/* Add contract handling to the function in FNDECL.

gcc/cp/cp-gimplify.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,7 +1528,15 @@ cp_fold_function (tree fndecl)
15281528
&data, NULL);
15291529
data.pset.empty ();
15301530
}
1531+
1532+
/* The attribute tree contains the original contracts which could be emitted
1533+
in multiple locations (e.g. caller side or definition side). They may also
1534+
be copied onto different functions. We do not want to fold contract trees
1535+
at this point in time. They will get folded when they are emitted.
1536+
*/
1537+
tree contracts = extract_contract_attributes (fndecl);
15311538
cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &data, NULL);
1539+
set_contract_attributes (fndecl, contracts);
15321540

15331541
/* This is merely an optimization: if FNDECL has no i-e expressions,
15341542
we'll not save c_f_d, and we can safely say that FNDECL will not

gcc/cp/cp-tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8970,6 +8970,7 @@ extern void check_param_in_redecl (tree, tree);
89708970
extern tree view_as_const (tree);
89718971
extern tree maybe_contract_wrap_call (tree, tree);
89728972
extern bool emit_contract_wrapper_func (bool);
8973+
extern tree extract_contract_attributes (tree);
89738974
extern void set_contract_attributes (tree, tree);
89748975

89758976
/* Return the first contract in ATTRS, or NULL_TREE if there are none. */
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Test that there is no ICE with outlined contracts on a virtual function with Nontrivial types
2+
// in precondition checks
3+
// { dg-do compile }
4+
// { dg-options "-std=c++2b -fcontracts -fcontracts-nonattr -fno-contract-checks-outlined -fcontracts-on-virtual-functions=P2900R13" }
5+
struct NonTrivial{
6+
NonTrivial(){};
7+
NonTrivial(const NonTrivial&){}
8+
~NonTrivial(){};
9+
int x = 0;
10+
};
11+
12+
struct S
13+
{
14+
15+
virtual void f(const NonTrivial s) pre(s.x >0 );
16+
17+
};
18+
19+
void S::f(const NonTrivial g) pre(g.x >0 ){};
20+
21+
int main()
22+
{
23+
NonTrivial nt;
24+
S s;
25+
s.f(nt);
26+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Test that there is no ICE with outlined contracts, caller side checks and Nontrivial types
2+
// in precondition checks
3+
// { dg-do compile }
4+
// { dg-options "-std=c++2b -fcontracts -fcontracts-nonattr -fno-contract-checks-outlined -fcontracts-nonattr-client-check=all" }
5+
struct NonTrivial{
6+
NonTrivial(){};
7+
NonTrivial(const NonTrivial&){}
8+
~NonTrivial(){};
9+
int x = 0;
10+
};
11+
12+
void f(const NonTrivial s) pre(s.x >0);
13+
14+
void f(const NonTrivial g) {};
15+
16+
17+
int main()
18+
{
19+
NonTrivial nt;
20+
f(nt);
21+
}

0 commit comments

Comments
 (0)