Skip to content

Commit 47b88d8

Browse files
Merge pull request gcc-mirror#57 from NinaRanns/contract_client_check
Contract client check
2 parents e5d9e45 + 8e8888c commit 47b88d8

File tree

6 files changed

+95
-7
lines changed

6 files changed

+95
-7
lines changed

gcc/c-family/c.opt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,10 @@ fcontracts-nonattr-client-contracts=
19641964
C++ Joined RejectNegative Enum(client_contract_check) Var(flag_contract_nonattr_client_check) Init (0)
19651965
-fcontracts-nonattr-client-check=[none|pre|all] Select which contracts will be checked on the client side for non virtual functions
19661966

1967+
fcontracts-nonattr-definition-check=
1968+
C++ Joined RejectNegative Enum(on_off) Var(flag_contracts_nonattr_definition_check) Init(1)
1969+
-fcontracts-nonattr-definition-check=[on|off] Enable or disable contract checks on the definition side for all functions (default on).
1970+
19671971
fcoroutines
19681972
C++ LTO Var(flag_coroutines)
19691973
Enable C++ coroutines (experimental).

gcc/cp/contracts.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,9 @@ build_contract_wrapper_function (tree fndecl, bool is_cvh, bool check_post = tru
18671867
/* no function body at present * */
18681868
DECL_INITIAL (wrapdecl) = error_mark_node;
18691869

1870+
/* This declaration is a contract wrapper function. */
1871+
DECL_CONTRACT_WRAPPER(wrapdecl) = true;
1872+
18701873
/* Build our result decl. */
18711874
tree resdecl = build_decl (loc, RESULT_DECL, 0, wrapper_return_type);
18721875
DECL_CONTEXT (resdecl) = wrapdecl;
@@ -2769,6 +2772,12 @@ start_function_contracts (tree decl1)
27692772
if (!handle_contracts_p (decl1))
27702773
return;
27712774

2775+
/* If this is not a client side check and definition side checks are
2776+
disabled, do nothing. */
2777+
if (!flag_contracts_nonattr_definition_check &&
2778+
!DECL_CONTRACT_WRAPPER(decl1))
2779+
return;
2780+
27722781
/* Check that the user did not try to shadow a function parameter with the
27732782
specified postcondition result name. */
27742783
if (flag_contracts_nonattr)
@@ -2884,6 +2893,12 @@ maybe_apply_function_contracts (tree fndecl)
28842893
popped by our caller. */
28852894
return;
28862895

2896+
/* If this is not a client side check and definition side checks are
2897+
disabled, do nothing. */
2898+
if (!flag_contracts_nonattr_definition_check &&
2899+
!DECL_CONTRACT_WRAPPER(fndecl))
2900+
return;
2901+
28872902
bool do_pre = has_active_preconditions (fndecl);
28882903
bool do_post = has_active_postconditions (fndecl);
28892904
/* We should not have reached here with nothing to do... */
@@ -3017,6 +3032,12 @@ finish_function_contracts (tree fndecl)
30173032
|| !outline_contracts_p (fndecl))
30183033
return;
30193034

3035+
/* If this is not a client side check and definition side checks are
3036+
disabled, do nothing. */
3037+
if (!flag_contracts_nonattr_definition_check &&
3038+
!DECL_CONTRACT_WRAPPER(fndecl))
3039+
return;
3040+
30203041
for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
30213042
{
30223043
tree contract = CONTRACT_STATEMENT (ca);

gcc/cp/cp-tree.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3039,9 +3039,11 @@ struct GTY(()) lang_decl_fn {
30393039
unsigned coroutine_p : 1;
30403040
unsigned implicit_constexpr : 1;
30413041
unsigned escalated_p : 1;
3042+
30423043
unsigned xobj_func : 1;
3044+
unsigned contract_wrapper : 1;
30433045

3044-
unsigned spare : 7;
3046+
unsigned spare : 6;
30453047

30463048
/* 32-bits padding on 64-bit host. */
30473049

@@ -3462,6 +3464,11 @@ struct GTY(()) lang_decl {
34623464
(TREE_CODE (STRIP_TEMPLATE (NODE)) == FUNCTION_DECL \
34633465
&& DECL_FUNCTION_XOBJ_FLAG (NODE) == 1)
34643466

3467+
/* Nonzero for FUNCTION_DECL means that this decl is a contract
3468+
wrapper function. */
3469+
#define DECL_CONTRACT_WRAPPER(NODE) \
3470+
LANG_DECL_FN_CHECK (NODE)->contract_wrapper
3471+
34653472
/* Nonzero if NODE is a member function with an object argument,
34663473
in other words, a non-static member function. */
34673474
#define DECL_OBJECT_MEMBER_FUNCTION_P(NODE) \

gcc/cp/decl.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19059,9 +19059,6 @@ finish_function (bool inline_p)
1905919059
if (fndecl == NULL_TREE || fndecl == error_mark_node)
1906019060
return error_mark_node;
1906119061

19062-
bool do_contracts = (DECL_HAS_CONTRACTS_P (fndecl)
19063-
&& !processing_template_decl);
19064-
1906519062
if (!DECL_OMP_DECLARE_REDUCTION_P (fndecl))
1906619063
finish_lambda_scope ();
1906719064

@@ -19104,7 +19101,7 @@ finish_function (bool inline_p)
1910419101
current_eh_spec_block);
1910519102

1910619103
/* If outlining succeeded, then add contracts handling if needed. */
19107-
if (coroutine->cp_valid_coroutine () && do_contracts)
19104+
if (coroutine->cp_valid_coroutine ())
1910819105
maybe_apply_function_contracts (fndecl);
1910919106
}
1911019107
else
@@ -19122,8 +19119,7 @@ finish_function (bool inline_p)
1912219119
(TREE_TYPE (current_function_decl)),
1912319120
current_eh_spec_block);
1912419121

19125-
if (do_contracts)
19126-
maybe_apply_function_contracts (current_function_decl);
19122+
maybe_apply_function_contracts (current_function_decl);
1912719123

1912819124
}
1912919125

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check that an invocation of a virtual function through the base class does not
2+
// check contracts of the derived function, which are definition side contracts
3+
// { dg-do run }
4+
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontracts-nonattr-definition-check=off " }
5+
6+
struct Base
7+
{
8+
virtual int f(const int a){ return 0;};
9+
};
10+
11+
struct Child : Base
12+
{
13+
virtual int f(const int a) pre (a > 14) post(r:r >2){ return 1;}
14+
};
15+
16+
int fooBase(Base& b)
17+
{
18+
return b.f(1);
19+
}
20+
21+
int main(int, char**)
22+
{
23+
Base b;
24+
Child c;
25+
26+
fooBase (c);
27+
28+
return 0;
29+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// check that an invocation of a virtual function through the base class checks
2+
// the base class contracts when definition side contracts are turned off
3+
// { dg-do run }
4+
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontracts-nonattr-definition-check=off -fcontract-continuation-mode=on" }
5+
6+
struct Base
7+
{
8+
virtual int f(const int a) pre (a > 14) post(r:r > 2){ return 0;};
9+
};
10+
11+
struct Child : Base
12+
{
13+
virtual int f(const int a) pre (a > 14) post(r:r > 2){ return 1;}
14+
};
15+
16+
int fooBase(Base& b)
17+
{
18+
return b.f(1);
19+
}
20+
21+
int main(int, char**)
22+
{
23+
Base b;
24+
Child c;
25+
26+
fooBase (c);
27+
28+
return 0;
29+
}
30+
// { dg-output "contract violation in function .*contract_wrapper at .*: a > 14.*(\n|\r\n|\r)" }
31+
// { dg-output "contract violation in function .*contract_wrapper at .*: r > 2.*(\n|\r\n|\r)" }

0 commit comments

Comments
 (0)