Skip to content

Commit

Permalink
Merge pull request gcc-mirror#57 from NinaRanns/contract_client_check
Browse files Browse the repository at this point in the history
Contract client check
  • Loading branch information
villevoutilainen authored Jan 22, 2025
2 parents e5d9e45 + 8e8888c commit 47b88d8
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 7 deletions.
4 changes: 4 additions & 0 deletions gcc/c-family/c.opt
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,10 @@ fcontracts-nonattr-client-contracts=
C++ Joined RejectNegative Enum(client_contract_check) Var(flag_contract_nonattr_client_check) Init (0)
-fcontracts-nonattr-client-check=[none|pre|all] Select which contracts will be checked on the client side for non virtual functions

fcontracts-nonattr-definition-check=
C++ Joined RejectNegative Enum(on_off) Var(flag_contracts_nonattr_definition_check) Init(1)
-fcontracts-nonattr-definition-check=[on|off] Enable or disable contract checks on the definition side for all functions (default on).

fcoroutines
C++ LTO Var(flag_coroutines)
Enable C++ coroutines (experimental).
Expand Down
21 changes: 21 additions & 0 deletions gcc/cp/contracts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,9 @@ build_contract_wrapper_function (tree fndecl, bool is_cvh, bool check_post = tru
/* no function body at present * */
DECL_INITIAL (wrapdecl) = error_mark_node;

/* This declaration is a contract wrapper function. */
DECL_CONTRACT_WRAPPER(wrapdecl) = true;

/* Build our result decl. */
tree resdecl = build_decl (loc, RESULT_DECL, 0, wrapper_return_type);
DECL_CONTEXT (resdecl) = wrapdecl;
Expand Down Expand Up @@ -2769,6 +2772,12 @@ start_function_contracts (tree decl1)
if (!handle_contracts_p (decl1))
return;

/* If this is not a client side check and definition side checks are
disabled, do nothing. */
if (!flag_contracts_nonattr_definition_check &&
!DECL_CONTRACT_WRAPPER(decl1))
return;

/* Check that the user did not try to shadow a function parameter with the
specified postcondition result name. */
if (flag_contracts_nonattr)
Expand Down Expand Up @@ -2884,6 +2893,12 @@ maybe_apply_function_contracts (tree fndecl)
popped by our caller. */
return;

/* If this is not a client side check and definition side checks are
disabled, do nothing. */
if (!flag_contracts_nonattr_definition_check &&
!DECL_CONTRACT_WRAPPER(fndecl))
return;

bool do_pre = has_active_preconditions (fndecl);
bool do_post = has_active_postconditions (fndecl);
/* We should not have reached here with nothing to do... */
Expand Down Expand Up @@ -3017,6 +3032,12 @@ finish_function_contracts (tree fndecl)
|| !outline_contracts_p (fndecl))
return;

/* If this is not a client side check and definition side checks are
disabled, do nothing. */
if (!flag_contracts_nonattr_definition_check &&
!DECL_CONTRACT_WRAPPER(fndecl))
return;

for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
{
tree contract = CONTRACT_STATEMENT (ca);
Expand Down
9 changes: 8 additions & 1 deletion gcc/cp/cp-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3039,9 +3039,11 @@ struct GTY(()) lang_decl_fn {
unsigned coroutine_p : 1;
unsigned implicit_constexpr : 1;
unsigned escalated_p : 1;

unsigned xobj_func : 1;
unsigned contract_wrapper : 1;

unsigned spare : 7;
unsigned spare : 6;

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

Expand Down Expand Up @@ -3462,6 +3464,11 @@ struct GTY(()) lang_decl {
(TREE_CODE (STRIP_TEMPLATE (NODE)) == FUNCTION_DECL \
&& DECL_FUNCTION_XOBJ_FLAG (NODE) == 1)

/* Nonzero for FUNCTION_DECL means that this decl is a contract
wrapper function. */
#define DECL_CONTRACT_WRAPPER(NODE) \
LANG_DECL_FN_CHECK (NODE)->contract_wrapper

/* Nonzero if NODE is a member function with an object argument,
in other words, a non-static member function. */
#define DECL_OBJECT_MEMBER_FUNCTION_P(NODE) \
Expand Down
8 changes: 2 additions & 6 deletions gcc/cp/decl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19059,9 +19059,6 @@ finish_function (bool inline_p)
if (fndecl == NULL_TREE || fndecl == error_mark_node)
return error_mark_node;

bool do_contracts = (DECL_HAS_CONTRACTS_P (fndecl)
&& !processing_template_decl);

if (!DECL_OMP_DECLARE_REDUCTION_P (fndecl))
finish_lambda_scope ();

Expand Down Expand Up @@ -19104,7 +19101,7 @@ finish_function (bool inline_p)
current_eh_spec_block);

/* If outlining succeeded, then add contracts handling if needed. */
if (coroutine->cp_valid_coroutine () && do_contracts)
if (coroutine->cp_valid_coroutine ())
maybe_apply_function_contracts (fndecl);
}
else
Expand All @@ -19122,8 +19119,7 @@ finish_function (bool inline_p)
(TREE_TYPE (current_function_decl)),
current_eh_spec_block);

if (do_contracts)
maybe_apply_function_contracts (current_function_decl);
maybe_apply_function_contracts (current_function_decl);

}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// check that an invocation of a virtual function through the base class does not
// check contracts of the derived function, which are definition side contracts
// { dg-do run }
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontracts-nonattr-definition-check=off " }

struct Base
{
virtual int f(const int a){ return 0;};
};

struct Child : Base
{
virtual int f(const int a) pre (a > 14) post(r:r >2){ return 1;}
};

int fooBase(Base& b)
{
return b.f(1);
}

int main(int, char**)
{
Base b;
Child c;

fooBase (c);

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// check that an invocation of a virtual function through the base class checks
// the base class contracts when definition side contracts are turned off
// { dg-do run }
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontracts-nonattr-definition-check=off -fcontract-continuation-mode=on" }

struct Base
{
virtual int f(const int a) pre (a > 14) post(r:r > 2){ return 0;};
};

struct Child : Base
{
virtual int f(const int a) pre (a > 14) post(r:r > 2){ return 1;}
};

int fooBase(Base& b)
{
return b.f(1);
}

int main(int, char**)
{
Base b;
Child c;

fooBase (c);

return 0;
}
// { dg-output "contract violation in function .*contract_wrapper at .*: a > 14.*(\n|\r\n|\r)" }
// { dg-output "contract violation in function .*contract_wrapper at .*: r > 2.*(\n|\r\n|\r)" }

0 comments on commit 47b88d8

Please sign in to comment.