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 : /* True iff the FUNCTION_DECL NODE currently has any contracts. */
87 : #define DECL_HAS_CONTRACTS_P(NODE) \
88 : (get_fn_contract_specifiers (NODE) != NULL_TREE)
89 :
90 : /* The wrapper of the original source location of a list of contracts. */
91 : #define CONTRACT_SOURCE_LOCATION_WRAPPER(NODE) \
92 : (TREE_PURPOSE (TREE_VALUE (NODE)))
93 :
94 : /* The original source location of a list of contracts. */
95 : #define CONTRACT_SOURCE_LOCATION(NODE) \
96 : (EXPR_LOCATION (CONTRACT_SOURCE_LOCATION_WRAPPER (NODE)))
97 :
98 : /* The actual code _STMT for a contract specifier. */
99 : #define CONTRACT_STATEMENT(NODE) \
100 : (TREE_VALUE (TREE_VALUE (NODE)))
101 :
102 : /* The parsed condition of the contract. */
103 : #define CONTRACT_CONDITION(NODE) \
104 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 2))
105 :
106 : /* True iff the condition of the contract NODE is not yet parsed. */
107 : #define CONTRACT_CONDITION_DEFERRED_P(NODE) \
108 : (TREE_CODE (CONTRACT_CONDITION (NODE)) == DEFERRED_PARSE)
109 :
110 : /* The raw comment of the contract. */
111 : #define CONTRACT_COMMENT(NODE) \
112 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 3))
113 :
114 : /* A std::source_location, if provided. */
115 : #define CONTRACT_STD_SOURCE_LOC(NODE) \
116 : (TREE_OPERAND (CONTRACT_CHECK (NODE), 4))
117 :
118 : /* The VAR_DECL of a postcondition result. For deferred contracts, this
119 : is an IDENTIFIER. */
120 : #define POSTCONDITION_IDENTIFIER(NODE) \
121 : (TREE_OPERAND (POSTCONDITION_STMT_CHECK (NODE), 5))
122 :
123 : /* For a FUNCTION_DECL of a guarded function, this holds the function decl
124 : where pre contract checks are emitted. */
125 : #define DECL_PRE_FN(NODE) \
126 : (get_precondition_function ((NODE)))
127 :
128 : /* For a FUNCTION_DECL of a guarded function, this holds the function decl
129 : where post contract checks are emitted. */
130 : #define DECL_POST_FN(NODE) \
131 : (get_postcondition_function ((NODE)))
132 :
133 : /* True iff the FUNCTION_DECL is the pre function for a guarded function. */
134 : #define DECL_IS_PRE_FN_P(NODE) \
135 : (DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
136 : && CONTRACT_HELPER (NODE) == ldf_contract_pre)
137 :
138 : /* True iff the FUNCTION_DECL is the post function for a guarded function. */
139 : #define DECL_IS_POST_FN_P(NODE) \
140 : (DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
141 : && CONTRACT_HELPER (NODE) == ldf_contract_post)
142 :
143 : #define DECL_IS_WRAPPER_FN_P(NODE) \
144 : (DECL_DECLARES_FUNCTION_P (NODE) && DECL_LANG_SPECIFIC (NODE) && \
145 : DECL_CONTRACT_WRAPPER (NODE))
146 :
147 : /* Allow specifying a sub-set of contract kinds to copy. */
148 : enum contract_match_kind
149 : {
150 : cmk_all,
151 : cmk_pre,
152 : cmk_post
153 : };
154 :
155 : /* contracts.cc */
156 :
157 : extern void init_contracts (void);
158 :
159 : extern tree grok_contract (tree, tree, tree, cp_expr, location_t);
160 : extern tree finish_contract_specifier (tree, tree);
161 : extern tree finish_contract_condition (cp_expr);
162 : extern void update_late_contract (tree, tree, cp_expr);
163 : extern void check_redecl_contract (tree, tree);
164 : extern tree invalidate_contract (tree);
165 : extern tree copy_and_remap_contracts (tree, tree, contract_match_kind = cmk_all);
166 : extern tree constify_contract_access (tree);
167 : extern tree view_as_const (tree);
168 :
169 : extern void set_fn_contract_specifiers (tree, tree);
170 : extern void update_fn_contract_specifiers (tree, tree);
171 : extern tree get_fn_contract_specifiers (tree);
172 : extern void remove_decl_with_fn_contracts_specifiers (tree);
173 : extern void remove_fn_contract_specifiers (tree);
174 : extern void update_contract_arguments (tree, tree);
175 :
176 : extern tree make_postcondition_variable (cp_expr);
177 : extern tree make_postcondition_variable (cp_expr, tree);
178 : extern void check_param_in_postcondition (tree, location_t);
179 : extern void check_postconditions_in_redecl (tree, tree);
180 : extern void maybe_update_postconditions (tree);
181 : extern void rebuild_postconditions (tree);
182 : extern bool check_postcondition_result (tree, tree, location_t);
183 :
184 : extern bool contract_any_deferred_p (tree);
185 :
186 : extern tree get_precondition_function (tree);
187 : extern tree get_postcondition_function (tree);
188 : extern tree get_orig_for_outlined (tree);
189 :
190 : extern void start_function_contracts (tree);
191 : extern void maybe_apply_function_contracts (tree);
192 : extern void finish_function_outlined_contracts (tree);
193 : extern void set_contract_functions (tree, tree, tree);
194 :
195 : extern tree maybe_contract_wrap_call (tree, tree);
196 : extern bool emit_contract_wrapper_func (bool);
197 : extern void maybe_emit_violation_handler_wrappers (void);
198 :
199 : extern tree build_contract_check (tree);
200 :
201 : /* Test if EXP is a contract const wrapper node. */
202 :
203 : inline bool
204 7544861 : contract_const_wrapper_p (const_tree exp)
205 : {
206 : /* A wrapper node has code VIEW_CONVERT_EXPR, and the flag base.private_flag
207 : is set. The wrapper node is used to used to constify entities inside
208 : contract assertions. */
209 1102652 : return ((TREE_CODE (exp) == VIEW_CONVERT_EXPR) && CONST_WRAPPER_P (exp));
210 : }
211 :
212 : /* If EXP is a contract_const_wrapper_p, return the wrapped expression.
213 : Otherwise, do nothing. */
214 :
215 : inline tree
216 7543224 : strip_contract_const_wrapper (tree exp)
217 : {
218 7543224 : if (contract_const_wrapper_p (exp))
219 24 : return TREE_OPERAND (exp, 0);
220 : else
221 : return exp;
222 : }
223 :
224 : /* TODO : decide if we should push the tests into contracts.cc */
225 : extern contract_evaluation_semantic get_evaluation_semantic (const_tree);
226 :
227 : /* Will this contract be ignored. */
228 :
229 : inline bool
230 12 : contract_ignored_p (const_tree contract)
231 : {
232 12 : return (get_evaluation_semantic (contract) <= CES_IGNORE);
233 : }
234 :
235 : /* Will this contract be evaluated? */
236 :
237 : inline bool
238 : contract_evaluated_p (const_tree contract)
239 : {
240 : return (get_evaluation_semantic (contract) >= CES_OBSERVE);
241 : }
242 :
243 : /* Is the contract terminating? */
244 :
245 : inline bool
246 12 : contract_terminating_p (const_tree contract)
247 : {
248 12 : return (get_evaluation_semantic (contract) == CES_ENFORCE
249 12 : || get_evaluation_semantic (contract) == CES_QUICK);
250 : }
251 :
252 : #endif /* ! GCC_CP_CONTRACT_H */
|