Line data Source code
1 : /* Definitions for C++26 contracts.
2 :
3 : Copyright (C) 2020-2026 Free Software Foundation, Inc.
4 : Originally by Jeff Chapman II (jchapman@lock3software.com) for proposed
5 : C++20 contracts.
6 : Rewritten for C++26 contracts by:
7 : Nina Ranns (dinka.ranns@googlemail.com)
8 : Iain Sandoe (iain@sandoe.co.uk)
9 : Ville Voutilainen (ville.voutilainen@gmail.com).
10 :
11 : This file is part of GCC.
12 :
13 : GCC is free software; you can redistribute it and/or modify
14 : it under the terms of the GNU General Public License as published by
15 : the Free Software Foundation; either version 3, or (at your option)
16 : any later version.
17 :
18 : GCC is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : GNU General Public License for more details.
22 :
23 : You should have received a copy of the GNU General Public License
24 : along with GCC; see the file COPYING3. If not see
25 : <http://www.gnu.org/licenses/>. */
26 :
27 : #ifndef GCC_CP_CONTRACT_H
28 : #define GCC_CP_CONTRACT_H
29 :
30 : #include <cstdint>
31 :
32 : /* Contract assertion kind */
33 : /* Must match relevant enums in <contracts> header */
34 :
35 : enum contract_assertion_kind : uint16_t {
36 : CAK_INVALID = 0 ,
37 : CAK_PRE = 1 ,
38 : CAK_POST = 2 ,
39 : CAK_ASSERT = 3,
40 : };
41 :
42 : /* Per P2900R14 + D3290R3 + extensions. */
43 : enum contract_evaluation_semantic : uint16_t {
44 : CES_INVALID = 0,
45 : CES_IGNORE = 1,
46 : CES_OBSERVE = 2,
47 : CES_ENFORCE = 3,
48 : CES_QUICK = 4,
49 : };
50 :
51 : enum detection_mode : uint16_t {
52 : CDM_UNSPECIFIED = 0,
53 : CDM_PREDICATE_FALSE = 1,
54 : CDM_EVAL_EXCEPTION = 2
55 : };
56 :
57 : /* Contract evaluation_semantic */
58 : #define CONTRACT_EVALUATION_SEMANTIC(NODE) \
59 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 0))
60 :
61 : #define CONTRACT_ASSERTION_KIND(NODE) \
62 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 1))
63 :
64 : #define CONTRACT_CHECK(NODE) \
65 : (TREE_CHECK3 (NODE, ASSERTION_STMT, PRECONDITION_STMT, POSTCONDITION_STMT))
66 :
67 : /* True if NODE is any kind of contract. */
68 : #define CONTRACT_P(NODE) \
69 : (TREE_CODE (NODE) == ASSERTION_STMT \
70 : || TREE_CODE (NODE) == PRECONDITION_STMT \
71 : || TREE_CODE (NODE) == POSTCONDITION_STMT)
72 :
73 : /* True if NODE is a contract condition. */
74 : #define CONTRACT_CONDITION_P(NODE) \
75 : (TREE_CODE (NODE) == PRECONDITION_STMT \
76 : || TREE_CODE (NODE) == POSTCONDITION_STMT)
77 :
78 : /* True if NODE is a precondition. */
79 : #define PRECONDITION_P(NODE) \
80 : (TREE_CODE (NODE) == PRECONDITION_STMT)
81 :
82 : /* True if NODE is a postcondition. */
83 : #define POSTCONDITION_P(NODE) \
84 : (TREE_CODE (NODE) == POSTCONDITION_STMT)
85 :
86 : /* The contract specifiers of a function are held in a TREE_VEC, each element
87 : of which is a PRECONDITION_STMT or a POSTCONDITION_STMT. A function with
88 : no contracts has NULL_TREE rather than an empty vector. */
89 :
90 : /* True iff the FUNCTION_DECL NODE currently has any contracts. */
91 : #define DECL_HAS_CONTRACTS_P(NODE) \
92 : (get_fn_contract_specifiers (NODE) != NULL_TREE)
93 :
94 : /* The parsed condition of the contract. */
95 : #define CONTRACT_CONDITION(NODE) \
96 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 2))
97 :
98 : /* True iff the condition of the contract NODE is not yet parsed. */
99 : #define CONTRACT_CONDITION_DEFERRED_P(NODE) \
100 : (TREE_CODE (CONTRACT_CONDITION (NODE)) == DEFERRED_PARSE)
101 :
102 : /* The raw comment of the contract. */
103 : #define CONTRACT_COMMENT(NODE) \
104 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 3))
105 :
106 : /* A std::source_location, if provided. */
107 : #define CONTRACT_STD_SOURCE_LOC(NODE) \
108 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 4))
109 :
110 : /* The VAR_DECL of a postcondition result. For deferred contracts, this
111 : is an IDENTIFIER. */
112 : #define POSTCONDITION_IDENTIFIER(NODE) \
113 : (TREE_OPERAND (POSTCONDITION_STMT_CHECK (NODE), 5))
114 :
115 : /* For a FUNCTION_DECL of a guarded function, this holds the function decl
116 : where pre contract checks are emitted. */
117 : #define DECL_PRE_FN(NODE) \
118 : (get_precondition_function ((NODE)))
119 :
120 : /* For a FUNCTION_DECL of a guarded function, this holds the function decl
121 : where post contract checks are emitted. */
122 : #define DECL_POST_FN(NODE) \
123 : (get_postcondition_function ((NODE)))
124 :
125 : /* True iff the FUNCTION_DECL is the pre function for a guarded function. */
126 : #define DECL_IS_PRE_FN_P(NODE) \
127 : (DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
128 : && CONTRACT_HELPER (NODE) == ldf_contract_pre)
129 :
130 : /* True iff the FUNCTION_DECL is the post function for a guarded function. */
131 : #define DECL_IS_POST_FN_P(NODE) \
132 : (DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
133 : && CONTRACT_HELPER (NODE) == ldf_contract_post)
134 :
135 : #define DECL_IS_WRAPPER_FN_P(NODE) \
136 : (DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) && \
137 : DECL_CONTRACT_WRAPPER (NODE))
138 :
139 : /* Allow specifying a sub-set of contract kinds to copy. */
140 : enum contract_match_kind
141 : {
142 : cmk_all,
143 : cmk_pre,
144 : cmk_post
145 : };
146 :
147 : /* contracts.cc */
148 :
149 : extern void init_contracts (void);
150 :
151 : extern tree grok_contract (tree, tree, tree, cp_expr, location_t);
152 : extern tree build_contract_specifiers (vec<tree, va_gc> *);
153 : extern tree contract_specifiers_concat (tree, tree);
154 : extern tree finish_contract_condition (cp_expr);
155 : extern void update_late_contract (tree, tree, cp_expr);
156 : extern void check_redecl_contract (tree, tree);
157 : extern tree invalidate_contract (tree);
158 : extern tree copy_and_remap_contracts (tree, tree, contract_match_kind = cmk_all);
159 : extern tree constify_contract_access (tree);
160 : extern tree view_as_const (tree);
161 :
162 : extern void set_fn_contract_specifiers (tree, tree);
163 : extern void update_fn_contract_specifiers (tree, tree);
164 : extern tree get_fn_contract_specifiers (tree);
165 : extern void remove_decl_with_fn_contracts_specifiers (tree);
166 : extern void remove_fn_contract_specifiers (tree);
167 : extern void update_contract_arguments (tree, tree);
168 :
169 : extern tree make_postcondition_variable (cp_expr);
170 : extern tree make_postcondition_variable (cp_expr, tree);
171 : extern void check_param_in_postcondition (tree, location_t);
172 : extern void check_postconditions_in_redecl (tree, tree);
173 : extern void maybe_update_postconditions (tree);
174 : extern void rebuild_postconditions (tree);
175 : extern bool check_postcondition_result (tree, tree, location_t);
176 :
177 : extern bool contract_any_deferred_p (tree);
178 :
179 : extern tree get_precondition_function (tree);
180 : extern tree get_postcondition_function (tree);
181 : extern tree get_orig_for_outlined (tree);
182 :
183 : extern void start_function_contracts (tree);
184 : extern void maybe_apply_function_contracts (tree);
185 : extern void finish_function_outlined_contracts (tree);
186 : extern void set_contract_functions (tree, tree, tree);
187 :
188 : extern tree maybe_contract_wrap_call (tree, tree);
189 : extern bool emit_contract_wrapper_func (bool);
190 : extern void maybe_emit_violation_handler_wrappers (void);
191 :
192 : extern tree build_contract_check (tree);
193 :
194 : /* Test if EXP is a contract const wrapper node. */
195 :
196 : inline bool
197 3896822 : contract_const_wrapper_p (const_tree exp)
198 : {
199 : /* A wrapper node has code VIEW_CONVERT_EXPR, and the flag base.private_flag
200 : is set. The wrapper node is used to used to constify entities inside
201 : contract assertions. */
202 853588 : return ((TREE_CODE (exp) == VIEW_CONVERT_EXPR) && CONST_WRAPPER_P (exp));
203 : }
204 :
205 : /* If EXP is a contract_const_wrapper_p, return the wrapped expression.
206 : Otherwise, do nothing. */
207 :
208 : inline tree
209 3894468 : strip_contract_const_wrapper (tree exp)
210 : {
211 3894468 : if (contract_const_wrapper_p (exp))
212 36 : return TREE_OPERAND (exp, 0);
213 : else
214 : return exp;
215 : }
216 :
217 : /* TODO : decide if we should push the tests into contracts.cc */
218 : extern contract_evaluation_semantic get_evaluation_semantic (const_tree);
219 :
220 : /* Will this contract be ignored. */
221 :
222 : inline bool
223 30 : contract_ignored_p (const_tree contract)
224 : {
225 30 : return (get_evaluation_semantic (contract) <= CES_IGNORE);
226 : }
227 :
228 : /* Will this contract be evaluated? */
229 :
230 : inline bool
231 : contract_evaluated_p (const_tree contract)
232 : {
233 : return (get_evaluation_semantic (contract) >= CES_OBSERVE);
234 : }
235 :
236 : /* Is the contract terminating? */
237 :
238 : inline bool
239 27 : contract_terminating_p (const_tree contract)
240 : {
241 27 : return (get_evaluation_semantic (contract) == CES_ENFORCE
242 27 : || get_evaluation_semantic (contract) == CES_QUICK);
243 : }
244 :
245 : #endif /* ! GCC_CP_CONTRACT_H */
|