Skip to content

Commit 47f1e7c

Browse files
committed
c++, contract: Only attach contracts to wrappers once the callee is non-dependent.
When a non-dependent expression appears as part of a template declaration, it seems that it can be parsed into an expression form that still requires tsubst- ing. We currently tsubst contract conditions unconditionally, so that it is getting done when functions with contracts are instantiated. We need to defer the attachment of callee contracts to client-side wrappers until the callee is non-dependent (in practice, doing this in the TU finalisation seems sufficient, but perhaps we might add an additional "try again" flag to the instantiation loop (TBD, TODO)).
1 parent d0a7414 commit 47f1e7c

File tree

1 file changed

+25
-28
lines changed

1 file changed

+25
-28
lines changed

gcc/cp/contracts.cc

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,11 +1848,13 @@ set_contract_wrapper_function (tree fndecl, tree wrapper)
18481848
If is_cvh is true, we're wrapping a contract violation handler
18491849
in a noexcept wrapper. Otherwise, we're making a caller side
18501850
contract check wrapper. For caller side contract check, postconditions
1851-
are only checked if check_post is true. */
1851+
are only checked if check_post is true.
1852+
Defer the attachment of the contracts to this function until the callee
1853+
is non-dependent, or we get cases where the conditions can be non-dependent
1854+
but still need tsubst-ing. */
18521855

18531856
static tree
1854-
build_contract_wrapper_function (tree fndecl, bool is_cvh,
1855-
bool check_post = true)
1857+
build_contract_wrapper_function (tree fndecl, bool is_cvh)
18561858
{
18571859
if (error_operand_p (fndecl))
18581860
return error_mark_node;
@@ -1939,11 +1941,6 @@ build_contract_wrapper_function (tree fndecl, bool is_cvh,
19391941
/* Copy any alignment the user added. */
19401942
DECL_USER_ALIGN (wrapdecl) = DECL_USER_ALIGN (fndecl);
19411943

1942-
/* Apply contracts from the original fn if this isn't a contract
1943-
violation handler. */
1944-
if (!is_cvh)
1945-
copy_and_remap_contracts (wrapdecl, fndecl, true, check_post);
1946-
19471944
/* Make this function internal. */
19481945
TREE_PUBLIC (wrapdecl) = false;
19491946
DECL_EXTERNAL (wrapdecl) = false;
@@ -3111,6 +3108,8 @@ finish_function_contracts (tree fndecl)
31113108
|| DECL_INITIAL (fndecl) == error_mark_node)
31123109
return;
31133110

3111+
/* If there are no contracts here, or we're building them in-line then we
3112+
do not need to build the outlined functions. */
31143113
if (!handle_contracts_p (fndecl)
31153114
|| !outline_contracts_p (fndecl))
31163115
return;
@@ -3160,20 +3159,6 @@ finish_function_contracts (tree fndecl)
31603159
post = finish_function (false);
31613160
expand_or_defer_fn (post);
31623161
}
3163-
3164-
/* Check if we need to update wrapper function contracts. */
3165-
tree wrapdecl = get_contract_wrapper_function (fndecl);
3166-
if (wrapdecl)
3167-
{
3168-
/* We copy postconditions on virtual function wrapper calls or if
3169-
postcondition checks are enabled on the caller side. */
3170-
bool copy_post
3171-
= (flag_contract_nonattr_client_check > 1)
3172-
|| ((DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
3173-
&& DECL_VIRTUAL_P (fndecl)));
3174-
3175-
copy_and_remap_contracts (wrapdecl, fndecl, true, copy_post);
3176-
}
31773162
}
31783163

31793164
static location_t
@@ -3435,19 +3420,19 @@ maybe_contract_wrap_call (tree fndecl, tree call)
34353420
if (!should_contract_wrap_call (do_pre, do_post, is_virtual))
34363421
return call;
34373422

3423+
/* We should not have reached here with nothing to do. */
34383424
/* We check postconditions on virtual function calls or if postcondition
34393425
checks are enabled for all clients. */
3440-
bool check_post = (flag_contract_nonattr_client_check > 1) || is_virtual;
3441-
3442-
/* We should not have reached here with nothing to do. */
3443-
gcc_checking_assert (do_pre || (check_post && do_post));
3426+
gcc_checking_assert (do_pre
3427+
|| (do_post
3428+
&& ((flag_contract_nonattr_client_check > 1)
3429+
|| is_virtual)));
34443430

34453431
/* Build the declaration of the wrapper, if we need to. */
34463432
tree wrapdecl = get_contract_wrapper_function (fndecl);
34473433
if (!wrapdecl)
34483434
{
3449-
wrapdecl = build_contract_wrapper_function (fndecl, /*is_cvh*/false,
3450-
check_post);
3435+
wrapdecl = build_contract_wrapper_function (fndecl, /*is_cvh*/false);
34513436
set_contract_wrapper_function (fndecl, wrapdecl);
34523437
}
34533438

@@ -3477,6 +3462,18 @@ define_contract_wrapper_func (const tree& fndecl, const tree& wrapdecl, void*)
34773462
if (DECL_INITIAL (wrapdecl) && DECL_INITIAL (wrapdecl) != error_mark_node)
34783463
return true;
34793464

3465+
/* FIXME: Maybe we should check if fndecl is still dependent? */
3466+
3467+
/* FIXME: We should not really have any. */
3468+
remove_contract_attributes (wrapdecl);
3469+
bool is_virtual = DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
3470+
&& DECL_VIRTUAL_P (fndecl);
3471+
/* We check postconditions on virtual function calls or if postcondition
3472+
checks are enabled for all clients. We should not get here unless there
3473+
are some checks to make. */
3474+
bool check_post = (flag_contract_nonattr_client_check > 1) || is_virtual;
3475+
copy_and_remap_contracts (wrapdecl, fndecl, /*remap_result*/true, check_post);
3476+
34803477
start_preparsed_function (wrapdecl, /*DECL_ATTRIBUTES*/NULL_TREE,
34813478
SF_DEFAULT | SF_PRE_PARSED);
34823479
tree body = begin_function_body ();

0 commit comments

Comments
 (0)