/* Definitions for C++26 contracts.
Copyright (C) 2020-2026 Free Software Foundation, Inc.
Originally by Jeff Chapman II (jchapman@lock3software.com) for proposed
C++20 contracts.
Rewritten for C++26 contracts by:
Nina Ranns (dinka.ranns@googlemail.com)
Iain Sandoe (iain@sandoe.co.uk)
Ville Voutilainen (ville.voutilainen@gmail.com).
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
. */
#ifndef GCC_CP_CONTRACT_H
#define GCC_CP_CONTRACT_H
#include
/* Contract assertion kind */
/* Must match relevant enums in header */
enum contract_assertion_kind : uint16_t {
CAK_INVALID = 0 ,
CAK_PRE = 1 ,
CAK_POST = 2 ,
CAK_ASSERT = 3,
};
/* Per P2900R14 + D3290R3 + extensions. */
enum contract_evaluation_semantic : uint16_t {
CES_INVALID = 0,
CES_IGNORE = 1,
CES_OBSERVE = 2,
CES_ENFORCE = 3,
CES_QUICK = 4,
};
enum detection_mode : uint16_t {
CDM_UNSPECIFIED = 0,
CDM_PREDICATE_FALSE = 1,
CDM_EVAL_EXCEPTION = 2
};
/* Contract evaluation_semantic */
#define CONTRACT_EVALUATION_SEMANTIC(NODE) \
(TREE_OPERAND (CONTRACT_CHECK (NODE), 0))
#define CONTRACT_ASSERTION_KIND(NODE) \
(TREE_OPERAND (CONTRACT_CHECK (NODE), 1))
#define CONTRACT_CHECK(NODE) \
(TREE_CHECK3 (NODE, ASSERTION_STMT, PRECONDITION_STMT, POSTCONDITION_STMT))
/* True if NODE is any kind of contract. */
#define CONTRACT_P(NODE) \
(TREE_CODE (NODE) == ASSERTION_STMT \
|| TREE_CODE (NODE) == PRECONDITION_STMT \
|| TREE_CODE (NODE) == POSTCONDITION_STMT)
/* True if NODE is a contract condition. */
#define CONTRACT_CONDITION_P(NODE) \
(TREE_CODE (NODE) == PRECONDITION_STMT \
|| TREE_CODE (NODE) == POSTCONDITION_STMT)
/* True if NODE is a precondition. */
#define PRECONDITION_P(NODE) \
(TREE_CODE (NODE) == PRECONDITION_STMT)
/* True if NODE is a postcondition. */
#define POSTCONDITION_P(NODE) \
(TREE_CODE (NODE) == POSTCONDITION_STMT)
/* True iff the FUNCTION_DECL NODE currently has any contracts. */
#define DECL_HAS_CONTRACTS_P(NODE) \
(get_fn_contract_specifiers (NODE) != NULL_TREE)
/* The wrapper of the original source location of a list of contracts. */
#define CONTRACT_SOURCE_LOCATION_WRAPPER(NODE) \
(TREE_PURPOSE (TREE_VALUE (NODE)))
/* The original source location of a list of contracts. */
#define CONTRACT_SOURCE_LOCATION(NODE) \
(EXPR_LOCATION (CONTRACT_SOURCE_LOCATION_WRAPPER (NODE)))
/* The actual code _STMT for a contract specifier. */
#define CONTRACT_STATEMENT(NODE) \
(TREE_VALUE (TREE_VALUE (NODE)))
/* The parsed condition of the contract. */
#define CONTRACT_CONDITION(NODE) \
(TREE_OPERAND (CONTRACT_CHECK (NODE), 2))
/* True iff the condition of the contract NODE is not yet parsed. */
#define CONTRACT_CONDITION_DEFERRED_P(NODE) \
(TREE_CODE (CONTRACT_CONDITION (NODE)) == DEFERRED_PARSE)
/* The raw comment of the contract. */
#define CONTRACT_COMMENT(NODE) \
(TREE_OPERAND (CONTRACT_CHECK (NODE), 3))
/* A std::source_location, if provided. */
#define CONTRACT_STD_SOURCE_LOC(NODE) \
(TREE_OPERAND (CONTRACT_CHECK (NODE), 4))
/* The VAR_DECL of a postcondition result. For deferred contracts, this
is an IDENTIFIER. */
#define POSTCONDITION_IDENTIFIER(NODE) \
(TREE_OPERAND (POSTCONDITION_STMT_CHECK (NODE), 5))
/* For a FUNCTION_DECL of a guarded function, this holds the function decl
where pre contract checks are emitted. */
#define DECL_PRE_FN(NODE) \
(get_precondition_function ((NODE)))
/* For a FUNCTION_DECL of a guarded function, this holds the function decl
where post contract checks are emitted. */
#define DECL_POST_FN(NODE) \
(get_postcondition_function ((NODE)))
/* True iff the FUNCTION_DECL is the pre function for a guarded function. */
#define DECL_IS_PRE_FN_P(NODE) \
(DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
&& CONTRACT_HELPER (NODE) == ldf_contract_pre)
/* True iff the FUNCTION_DECL is the post function for a guarded function. */
#define DECL_IS_POST_FN_P(NODE) \
(DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
&& CONTRACT_HELPER (NODE) == ldf_contract_post)
#define DECL_IS_WRAPPER_FN_P(NODE) \
(DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) && \
DECL_CONTRACT_WRAPPER (NODE))
/* Allow specifying a sub-set of contract kinds to copy. */
enum contract_match_kind
{
cmk_all,
cmk_pre,
cmk_post
};
/* contracts.cc */
extern void init_contracts (void);
extern tree grok_contract (tree, tree, tree, cp_expr, location_t);
extern tree finish_contract_specifier (tree, tree);
extern tree finish_contract_condition (cp_expr);
extern void update_late_contract (tree, tree, cp_expr);
extern void check_redecl_contract (tree, tree);
extern tree invalidate_contract (tree);
extern tree copy_and_remap_contracts (tree, tree, contract_match_kind = cmk_all);
extern tree constify_contract_access (tree);
extern tree view_as_const (tree);
extern void set_fn_contract_specifiers (tree, tree);
extern void update_fn_contract_specifiers (tree, tree);
extern tree get_fn_contract_specifiers (tree);
extern void remove_decl_with_fn_contracts_specifiers (tree);
extern void remove_fn_contract_specifiers (tree);
extern void update_contract_arguments (tree, tree);
extern tree make_postcondition_variable (cp_expr);
extern tree make_postcondition_variable (cp_expr, tree);
extern void check_param_in_postcondition (tree, location_t);
extern void check_postconditions_in_redecl (tree, tree);
extern void maybe_update_postconditions (tree);
extern void rebuild_postconditions (tree);
extern bool check_postcondition_result (tree, tree, location_t);
extern bool contract_any_deferred_p (tree);
extern tree get_precondition_function (tree);
extern tree get_postcondition_function (tree);
extern tree get_orig_for_outlined (tree);
extern void start_function_contracts (tree);
extern void maybe_apply_function_contracts (tree);
extern void finish_function_outlined_contracts (tree);
extern void set_contract_functions (tree, tree, tree);
extern tree maybe_contract_wrap_call (tree, tree);
extern bool emit_contract_wrapper_func (bool);
extern void maybe_emit_violation_handler_wrappers (void);
extern tree build_contract_check (tree);
/* Test if EXP is a contract const wrapper node. */
inline bool
contract_const_wrapper_p (const_tree exp)
{
/* A wrapper node has code VIEW_CONVERT_EXPR, and the flag base.private_flag
is set. The wrapper node is used to used to constify entities inside
contract assertions. */
return ((TREE_CODE (exp) == VIEW_CONVERT_EXPR) && CONST_WRAPPER_P (exp));
}
/* If EXP is a contract_const_wrapper_p, return the wrapped expression.
Otherwise, do nothing. */
inline tree
strip_contract_const_wrapper (tree exp)
{
if (contract_const_wrapper_p (exp))
return TREE_OPERAND (exp, 0);
else
return exp;
}
/* TODO : decide if we should push the tests into contracts.cc */
extern contract_evaluation_semantic get_evaluation_semantic (const_tree);
/* Will this contract be ignored. */
inline bool
contract_ignored_p (const_tree contract)
{
return (get_evaluation_semantic (contract) <= CES_IGNORE);
}
/* Will this contract be evaluated? */
inline bool
contract_evaluated_p (const_tree contract)
{
return (get_evaluation_semantic (contract) >= CES_OBSERVE);
}
/* Is the contract terminating? */
inline bool
contract_terminating_p (const_tree contract)
{
return (get_evaluation_semantic (contract) == CES_ENFORCE
|| get_evaluation_semantic (contract) == CES_QUICK);
}
#endif /* ! GCC_CP_CONTRACT_H */