Branch data Line data Source code
1 : : /* Definitions for C++ contract levels
2 : : Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 : : Contributed by Jeff Chapman II (jchapman@lock3software.com)
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful,
13 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : GNU General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : /* Design Notes
22 : :
23 : : A function is called a "guarded" function if it has pre or post contract
24 : : attributes. A contract is considered an "active" contract if runtime code is
25 : : needed for the contract under the current contract configuration.
26 : :
27 : : pre and post contract attributes are parsed and stored in DECL_ATTRIBUTES.
28 : : assert contracts are parsed and wrapped in statements. When genericizing, all
29 : : active and assumed contracts are transformed into an if block. An observed
30 : : contract:
31 : :
32 : : [[ pre: v > 0 ]]
33 : :
34 : : is transformed into:
35 : :
36 : : if (!(v > 0)) {
37 : : handle_contract_violation(__pseudo_contract_violation{
38 : : 5, // line_number,
39 : : "main.cpp", // file_name,
40 : : "fun", // function_name,
41 : : "v > 0", // comment,
42 : : "default", // assertion_level,
43 : : "default", // assertion_role,
44 : : maybe_continue, // continuation_mode
45 : : });
46 : : terminate (); // if never_continue
47 : : }
48 : :
49 : : We use an internal type with the same layout as contract_violation rather
50 : : than try to define the latter internally and somehow deal with its actual
51 : : definition in a TU that includes <contract>.
52 : :
53 : : ??? is it worth factoring out the calls to handle_contract_violation and
54 : : terminate into a local function?
55 : :
56 : : Assumed contracts use the same implementation as C++23 [[assume]].
57 : :
58 : : Parsing of pre and post contract conditions need to be deferred when the
59 : : contracts are attached to a member function. The postcondition identifier
60 : : cannot be used before the deduced return type of an auto function is used,
61 : : except when used in a defining declaration in which case they conditions are
62 : : fully parsed once the body is finished (see cpp2a/contracts-deduced{1,2}.C).
63 : :
64 : : A list of pre and post contracts can either be repeated in their entirety or
65 : : completely absent in subsequent declarations. If contract lists appear on two
66 : : matching declarations, their contracts have to be equivalent. In general this
67 : : means that anything before the colon have to be token equivalent and the
68 : : condition must be cp_tree_equal (primarily to allow for parameter renaming).
69 : :
70 : : Contracts on overrides must match those present on (all of) the overridee(s).
71 : :
72 : : Template specializations may have their own contracts. If no contracts are
73 : : specified on the initial specialization they're assumed to be the same as
74 : : the primary template. Specialization redeclarations must then match either
75 : : the primary template (if they were unspecified originally), or those
76 : : specified on the specialization.
77 : :
78 : :
79 : : For non-cdtors two functions are generated for ease of implementation and to
80 : : avoid some cases where code bloat may occurr. These are the DECL_PRE_FN and
81 : : DECL_POST_FN. Each handles checking either the set of pre or post contracts
82 : : of a guarded function.
83 : :
84 : : int fun(int v)
85 : : [[ pre: v > 0 ]]
86 : : [[ post r: r < 0 ]]
87 : : {
88 : : return -v;
89 : : }
90 : :
91 : : We implement the checking as follows:
92 : :
93 : : For functions with no post-conditions we wrap the original function body as
94 : : follows:
95 : :
96 : : {
97 : : handle_pre_condition_checking ();
98 : : original_function_body ();
99 : : }
100 : :
101 : : This implements the intent that the preconditions are processed after the
102 : : function parameters are initialised but before any other actions.
103 : :
104 : : For functions with post-conditions:
105 : :
106 : : if (preconditions_exist)
107 : : handle_pre_condition_checking ();
108 : : try
109 : : {
110 : : original_function_body ();
111 : : }
112 : : finally
113 : : {
114 : : handle_post_condition_checking ();
115 : : }
116 : : else [only if the function is not marked noexcept(true) ]
117 : : {
118 : : ;
119 : : }
120 : :
121 : : In this, post-conditions [that might apply to the return value etc.] are
122 : : evaluated on every non-exceptional edge out of the function.
123 : :
124 : : FIXME outlining contract checks into separate functions was motivated
125 : : partly by wanting to call the postcondition function at each return
126 : : statement, which we no longer do; at this point outlining doesn't seem to
127 : : have any advantage over emitting the contracts directly in the function
128 : : body.
129 : :
130 : : More helpful for optimization might be to make the contracts a wrapper
131 : : function that could be inlined into the caller, the callee, or both. */
132 : :
133 : : #include "config.h"
134 : : #include "system.h"
135 : : #include "coretypes.h"
136 : : #include "cp-tree.h"
137 : : #include "stringpool.h"
138 : : #include "diagnostic.h"
139 : : #include "options.h"
140 : : #include "contracts.h"
141 : : #include "tree.h"
142 : : #include "tree-inline.h"
143 : : #include "attribs.h"
144 : : #include "tree-iterator.h"
145 : : #include "print-tree.h"
146 : : #include "stor-layout.h"
147 : : #include "intl.h"
148 : : #include "cgraph.h"
149 : :
150 : : const int max_custom_roles = 32;
151 : : static contract_role contract_build_roles[max_custom_roles] = {
152 : : };
153 : :
154 : : bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = {
155 : : { 0, 0, 0, 0, 0, },
156 : : { 0, 1, 0, 0, 0, },
157 : : { 0, 1, 1, 1, 1, },
158 : : { 0, 1, 1, 1, 1, },
159 : : { 0, 1, 0, 0, 1, },
160 : : };
161 : :
162 : : void
163 : 28 : validate_contract_role (contract_role *role)
164 : : {
165 : 28 : gcc_assert (role);
166 : 28 : if (!unchecked_contract_p (role->axiom_semantic))
167 : 0 : error ("axiom contract semantic must be %<assume%> or %<ignore%>");
168 : :
169 : 28 : if (!valid_configs[role->default_semantic][role->audit_semantic] )
170 : 0 : warning (0, "the %<audit%> semantic should be at least as strong as "
171 : : "the %<default%> semantic");
172 : 28 : }
173 : :
174 : : contract_semantic
175 : 78 : lookup_concrete_semantic (const char *name)
176 : : {
177 : 78 : if (strcmp (name, "ignore") == 0)
178 : : return CCS_IGNORE;
179 : 32 : if (strcmp (name, "assume") == 0)
180 : : return CCS_ASSUME;
181 : 31 : if (strcmp (name, "check_never_continue") == 0
182 : 31 : || strcmp (name, "never") == 0
183 : 28 : || strcmp (name, "abort") == 0)
184 : : return CCS_NEVER;
185 : 28 : if (strcmp (name, "check_maybe_continue") == 0
186 : 28 : || strcmp (name, "maybe") == 0)
187 : : return CCS_MAYBE;
188 : 0 : error ("'%s' is not a valid explicit concrete semantic", name);
189 : 0 : return CCS_INVALID;
190 : : }
191 : :
192 : : /* Compare role and name up to either the NUL terminator or the first
193 : : occurrence of colon. */
194 : :
195 : : static bool
196 : 1065 : role_name_equal (const char *role, const char *name)
197 : : {
198 : 1065 : size_t role_len = strcspn (role, ":");
199 : 1065 : size_t name_len = strcspn (name, ":");
200 : 1065 : if (role_len != name_len)
201 : : return false;
202 : 899 : return strncmp (role, name, role_len) == 0;
203 : : }
204 : :
205 : : static bool
206 : 2982 : role_name_equal (contract_role *role, const char *name)
207 : : {
208 : 0 : if (role->name == NULL)
209 : : return false;
210 : 0 : return role_name_equal (role->name, name);
211 : : }
212 : :
213 : : contract_role *
214 : 815 : get_contract_role (const char *name)
215 : : {
216 : 2922 : for (int i = 0; i < max_custom_roles; ++i)
217 : : {
218 : 2858 : contract_role *potential = contract_build_roles + i;
219 : 2858 : if (role_name_equal (potential, name))
220 : : return potential;
221 : : }
222 : 64 : if (role_name_equal (name, "default") || role_name_equal (name, "review"))
223 : : {
224 : 57 : setup_default_contract_role (false);
225 : 57 : return get_contract_role (name);
226 : : }
227 : : return NULL;
228 : : }
229 : :
230 : : contract_role *
231 : 261 : add_contract_role (const char *name,
232 : : contract_semantic des,
233 : : contract_semantic aus,
234 : : contract_semantic axs,
235 : : bool update)
236 : : {
237 : 383 : for (int i = 0; i < max_custom_roles; ++i)
238 : : {
239 : 383 : contract_role *potential = contract_build_roles + i;
240 : 505 : if (potential->name != NULL
241 : 383 : && !role_name_equal (potential, name))
242 : 122 : continue;
243 : 261 : if (potential->name != NULL && !update)
244 : : return potential;
245 : 261 : potential->name = name;
246 : 261 : potential->default_semantic = des;
247 : 261 : potential->audit_semantic = aus;
248 : 261 : potential->axiom_semantic = axs;
249 : 261 : return potential;
250 : : }
251 : : return NULL;
252 : : }
253 : :
254 : : enum contract_build_level { OFF, DEFAULT, AUDIT };
255 : : static bool flag_contract_continuation_mode = false;
256 : : static bool flag_contract_assumption_mode = true;
257 : : static int flag_contract_build_level = DEFAULT;
258 : :
259 : : static bool contracts_p1332_default = false, contracts_p1332_review = false,
260 : : contracts_std = false, contracts_p1429 = false;
261 : :
262 : : static contract_semantic
263 : 118 : get_concrete_check ()
264 : : {
265 : 0 : return flag_contract_continuation_mode ? CCS_MAYBE : CCS_NEVER;
266 : : }
267 : :
268 : : static contract_semantic
269 : 118 : get_concrete_axiom_semantic ()
270 : : {
271 : 0 : return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE;
272 : : }
273 : :
274 : : void
275 : 118 : setup_default_contract_role (bool update)
276 : : {
277 : 118 : contract_semantic check = get_concrete_check ();
278 : 118 : contract_semantic axiom = get_concrete_axiom_semantic ();
279 : 118 : switch (flag_contract_build_level)
280 : : {
281 : 1 : case OFF:
282 : 1 : add_contract_role ("default", CCS_IGNORE, CCS_IGNORE, axiom, update);
283 : 1 : add_contract_role ("review", CCS_IGNORE, CCS_IGNORE, CCS_IGNORE, update);
284 : 1 : break;
285 : 114 : case DEFAULT:
286 : 114 : add_contract_role ("default", check, CCS_IGNORE, axiom, update);
287 : 114 : add_contract_role ("review", check, CCS_IGNORE, CCS_IGNORE, update);
288 : 114 : break;
289 : 3 : case AUDIT:
290 : 3 : add_contract_role ("default", check, check, axiom, update);
291 : 3 : add_contract_role ("review", check, check, CCS_IGNORE, update);
292 : 3 : break;
293 : : }
294 : 118 : }
295 : :
296 : : contract_semantic
297 : 200 : map_contract_semantic (const char *ident)
298 : : {
299 : 200 : if (strcmp (ident, "ignore") == 0)
300 : : return CCS_IGNORE;
301 : 178 : else if (strcmp (ident, "assume") == 0)
302 : : return CCS_ASSUME;
303 : 146 : else if (strcmp (ident, "check_never_continue") == 0)
304 : : return CCS_NEVER;
305 : 136 : else if (strcmp (ident, "check_maybe_continue") == 0)
306 : 20 : return CCS_MAYBE;
307 : : return CCS_INVALID;
308 : : }
309 : :
310 : : contract_level
311 : 232 : map_contract_level (const char *ident)
312 : : {
313 : 232 : if (strcmp (ident, "default") == 0)
314 : : return CONTRACT_DEFAULT;
315 : 197 : else if (strcmp (ident, "audit") == 0)
316 : : return CONTRACT_AUDIT;
317 : 149 : else if (strcmp (ident, "axiom") == 0)
318 : 30 : return CONTRACT_AXIOM;
319 : : return CONTRACT_INVALID;
320 : : }
321 : :
322 : :
323 : : void
324 : 4 : handle_OPT_fcontract_build_level_ (const char *arg)
325 : : {
326 : 4 : if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
327 : : {
328 : 0 : error ("%<-fcontract-build-level=%> cannot be mixed with p1332/p1429");
329 : 0 : return;
330 : : }
331 : : else
332 : 4 : contracts_std = true;
333 : :
334 : 4 : if (strcmp (arg, "off") == 0)
335 : 1 : flag_contract_build_level = OFF;
336 : 3 : else if (strcmp (arg, "default") == 0)
337 : 1 : flag_contract_build_level = DEFAULT;
338 : 2 : else if (strcmp (arg, "audit") == 0)
339 : 2 : flag_contract_build_level = AUDIT;
340 : : else
341 : 0 : error ("%<-fcontract-build-level=%> must be off|default|audit");
342 : :
343 : 4 : setup_default_contract_role ();
344 : : }
345 : :
346 : : void
347 : 0 : handle_OPT_fcontract_assumption_mode_ (const char *arg)
348 : : {
349 : 0 : if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
350 : : {
351 : 0 : error ("%<-fcontract-assumption-mode=%> cannot be mixed with p1332/p1429");
352 : 0 : return;
353 : : }
354 : : else
355 : 0 : contracts_std = true;
356 : :
357 : 0 : if (strcmp (arg, "on") == 0)
358 : 0 : flag_contract_assumption_mode = true;
359 : 0 : else if (strcmp (arg, "off") == 0)
360 : 0 : flag_contract_assumption_mode = false;
361 : : else
362 : 0 : error ("%<-fcontract-assumption-mode=%> must be %<on%> or %<off%>");
363 : :
364 : 0 : setup_default_contract_role ();
365 : : }
366 : :
367 : : void
368 : 57 : handle_OPT_fcontract_continuation_mode_ (const char *arg)
369 : : {
370 : 57 : if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
371 : : {
372 : 0 : error ("%<-fcontract-continuation-mode=%> cannot be mixed with p1332/p1429");
373 : 0 : return;
374 : : }
375 : : else
376 : 57 : contracts_std = true;
377 : :
378 : 57 : if (strcmp (arg, "on") == 0)
379 : 57 : flag_contract_continuation_mode = true;
380 : 0 : else if (strcmp (arg, "off") == 0)
381 : 0 : flag_contract_continuation_mode = false;
382 : : else
383 : 0 : error ("%<-fcontract-continuation-mode=%> must be %<on%> or %<off%>");
384 : :
385 : 57 : setup_default_contract_role ();
386 : : }
387 : :
388 : : void
389 : 25 : handle_OPT_fcontract_role_ (const char *arg)
390 : : {
391 : 25 : const char *name = arg;
392 : 25 : const char *vals = strchr (name, ':');
393 : 25 : if (vals == NULL)
394 : : {
395 : 0 : error ("%<-fcontract-role=%> must be in the form role:semantics");
396 : 0 : return;
397 : : }
398 : :
399 : 25 : contract_semantic dess = CCS_INVALID, auss = CCS_INVALID, axss = CCS_INVALID;
400 : 25 : char *des = NULL, *aus = NULL, *axs = NULL;
401 : 25 : des = xstrdup (vals + 1);
402 : :
403 : 25 : aus = strchr (des, ',');
404 : 25 : if (aus == NULL)
405 : : {
406 : 0 : error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
407 : 0 : goto validate;
408 : : }
409 : 25 : *aus = '\0'; // null terminate des
410 : 25 : aus = aus + 1; // move past null
411 : :
412 : 25 : axs = strchr (aus, ',');
413 : 25 : if (axs == NULL)
414 : : {
415 : 0 : error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
416 : 0 : goto validate;
417 : : }
418 : 25 : *axs = '\0'; // null terminate aus
419 : 25 : axs = axs + 1; // move past null
420 : :
421 : 25 : dess = lookup_concrete_semantic (des);
422 : 25 : auss = lookup_concrete_semantic (aus);
423 : 25 : axss = lookup_concrete_semantic (axs);
424 : 25 : validate:
425 : 25 : free (des);
426 : 25 : if (dess == CCS_INVALID || auss == CCS_INVALID || axss == CCS_INVALID)
427 : : return;
428 : :
429 : 25 : bool is_defalult_role = role_name_equal (name, "default");
430 : 25 : bool is_review_role = role_name_equal (name, "review");
431 : 25 : bool is_std_role = is_defalult_role || is_review_role;
432 : 25 : if ((contracts_std && is_std_role) || (contracts_p1429 && is_defalult_role))
433 : : {
434 : 0 : error ("%<-fcontract-role=%> cannot be mixed with std/p1429 contract flags");
435 : 0 : return;
436 : : }
437 : 25 : else if (is_std_role)
438 : : {
439 : 23 : contracts_p1332_default |= is_defalult_role;
440 : 23 : contracts_p1332_review |= is_review_role;
441 : : }
442 : :
443 : 25 : contract_role *role = add_contract_role (name, dess, auss, axss);
444 : :
445 : 25 : if (role == NULL)
446 : : {
447 : : // TODO: not enough space?
448 : 0 : error ("%<-fcontract-level=%> too many custom roles");
449 : 0 : return;
450 : : }
451 : : else
452 : 25 : validate_contract_role (role);
453 : : }
454 : :
455 : : void
456 : 3 : handle_OPT_fcontract_semantic_ (const char *arg)
457 : : {
458 : 3 : if (!strchr (arg, ':'))
459 : : {
460 : 0 : error ("%<-fcontract-semantic=%> must be in the form level:semantic");
461 : 0 : return;
462 : : }
463 : :
464 : 3 : if (contracts_std || contracts_p1332_default)
465 : : {
466 : 0 : error ("%<-fcontract-semantic=%> cannot be mixed with std/p1332 contract flags");
467 : 0 : return;
468 : : }
469 : 3 : contracts_p1429 = true;
470 : :
471 : 3 : contract_role *role = get_contract_role ("default");
472 : 3 : if (!role)
473 : : {
474 : 0 : error ("%<-fcontract-semantic=%> cannot find default role");
475 : 0 : return;
476 : : }
477 : :
478 : 3 : const char *semantic = strchr (arg, ':') + 1;
479 : 3 : contract_semantic sem = lookup_concrete_semantic (semantic);
480 : 3 : if (sem == CCS_INVALID)
481 : : return;
482 : :
483 : 3 : if (strncmp ("default:", arg, 8) == 0)
484 : 1 : role->default_semantic = sem;
485 : 2 : else if (strncmp ("audit:", arg, 6) == 0)
486 : 1 : role->audit_semantic = sem;
487 : 1 : else if (strncmp ("axiom:", arg, 6) == 0)
488 : 1 : role->axiom_semantic = sem;
489 : : else
490 : 0 : error ("%<-fcontract-semantic=%> level must be default, audit, or axiom");
491 : 3 : validate_contract_role (role);
492 : : }
493 : :
494 : : /* Convert a contract CONFIG into a contract_mode. */
495 : :
496 : : static contract_mode
497 : 847 : contract_config_to_mode (tree config)
498 : : {
499 : 847 : if (config == NULL_TREE)
500 : 731 : return contract_mode (CONTRACT_DEFAULT, get_default_contract_role ());
501 : :
502 : : /* TREE_LIST has TREE_VALUE is a level and TREE_PURPOSE is role. */
503 : 116 : if (TREE_CODE (config) == TREE_LIST)
504 : : {
505 : 74 : contract_role *role = NULL;
506 : 74 : if (TREE_PURPOSE (config))
507 : 31 : role = get_contract_role (IDENTIFIER_POINTER (TREE_PURPOSE (config)));
508 : 31 : if (!role)
509 : 50 : role = get_default_contract_role ();
510 : :
511 : 74 : contract_level level =
512 : 74 : map_contract_level (IDENTIFIER_POINTER (TREE_VALUE (config)));
513 : 74 : return contract_mode (level, role);
514 : : }
515 : :
516 : : /* Literal semantic. */
517 : 42 : gcc_assert (TREE_CODE (config) == IDENTIFIER_NODE);
518 : 42 : contract_semantic semantic =
519 : 42 : map_contract_semantic (IDENTIFIER_POINTER (config));
520 : 42 : return contract_mode (semantic);
521 : : }
522 : :
523 : : /* Convert a contract's config into a concrete semantic using the current
524 : : contract semantic mapping. */
525 : :
526 : : static contract_semantic
527 : 847 : compute_concrete_semantic (tree contract)
528 : : {
529 : 847 : contract_mode mode = contract_config_to_mode (CONTRACT_MODE (contract));
530 : : /* Compute the concrete semantic for the contract. */
531 : 847 : if (!flag_contract_mode)
532 : : /* If contracts are off, treat all contracts as ignore. */
533 : : return CCS_IGNORE;
534 : 844 : else if (mode.kind == contract_mode::cm_invalid)
535 : : return CCS_INVALID;
536 : 844 : else if (mode.kind == contract_mode::cm_explicit)
537 : 42 : return mode.get_semantic ();
538 : : else
539 : : {
540 : 802 : gcc_assert (mode.get_role ());
541 : 802 : gcc_assert (mode.get_level () != CONTRACT_INVALID);
542 : 802 : contract_level level = mode.get_level ();
543 : 802 : contract_role *role = mode.get_role ();
544 : 802 : if (level == CONTRACT_DEFAULT)
545 : 763 : return role->default_semantic;
546 : 39 : else if (level == CONTRACT_AUDIT)
547 : 24 : return role->audit_semantic;
548 : 15 : else if (level == CONTRACT_AXIOM)
549 : 15 : return role->axiom_semantic;
550 : : }
551 : 0 : gcc_assert (false);
552 : : }
553 : :
554 : : /* Return true if any contract in CONTRACT_ATTRs is not yet parsed. */
555 : :
556 : : bool
557 : 20 : contract_any_deferred_p (tree contract_attr)
558 : : {
559 : 50 : for (; contract_attr; contract_attr = CONTRACT_CHAIN (contract_attr))
560 : 30 : if (CONTRACT_CONDITION_DEFERRED_P (CONTRACT_STATEMENT (contract_attr)))
561 : : return true;
562 : : return false;
563 : : }
564 : :
565 : : /* Returns true if all attributes are contracts. */
566 : :
567 : : bool
568 : 29 : all_attributes_are_contracts_p (tree attributes)
569 : : {
570 : 31 : for (; attributes; attributes = TREE_CHAIN (attributes))
571 : 29 : if (!cxx_contract_attribute_p (attributes))
572 : : return false;
573 : : return true;
574 : : }
575 : :
576 : : /* Mark most of a contract as being invalid. */
577 : :
578 : : tree
579 : 23 : invalidate_contract (tree t)
580 : : {
581 : 23 : if (TREE_CODE (t) == POSTCONDITION_STMT && POSTCONDITION_IDENTIFIER (t))
582 : 6 : POSTCONDITION_IDENTIFIER (t) = error_mark_node;
583 : 23 : CONTRACT_CONDITION (t) = error_mark_node;
584 : 23 : CONTRACT_COMMENT (t) = error_mark_node;
585 : 23 : return t;
586 : : }
587 : :
588 : : /* Returns an invented parameter declration of the form 'TYPE ID' for the
589 : : purpose of parsing the postcondition.
590 : :
591 : : We use a PARM_DECL instead of a VAR_DECL so that tsubst forces a lookup
592 : : in local specializations when we instantiate these things later. */
593 : :
594 : : tree
595 : 75 : make_postcondition_variable (cp_expr id, tree type)
596 : : {
597 : 75 : if (id == error_mark_node)
598 : : return id;
599 : :
600 : 75 : tree decl = build_lang_decl (PARM_DECL, id, type);
601 : 75 : DECL_ARTIFICIAL (decl) = true;
602 : 75 : DECL_SOURCE_LOCATION (decl) = id.get_location ();
603 : :
604 : 75 : pushdecl (decl);
605 : 75 : return decl;
606 : : }
607 : :
608 : : /* As above, except that the type is unknown. */
609 : :
610 : : tree
611 : 71 : make_postcondition_variable (cp_expr id)
612 : : {
613 : 71 : return make_postcondition_variable (id, make_auto ());
614 : : }
615 : :
616 : : /* Check that the TYPE is valid for a named postcondition variable. Emit a
617 : : diagnostic if it is not. Returns TRUE if the result is OK and false
618 : : otherwise. */
619 : :
620 : : bool
621 : 92 : check_postcondition_result (tree decl, tree type, location_t loc)
622 : : {
623 : : /* Do not be confused by targetm.cxx.cdtor_return_this ();
624 : : conceptually, cdtors have no return value. */
625 : 92 : if (VOID_TYPE_P (type)
626 : 172 : || DECL_CONSTRUCTOR_P (decl)
627 : 178 : || DECL_DESTRUCTOR_P (decl))
628 : : {
629 : 18 : error_at (loc,
630 : 12 : DECL_CONSTRUCTOR_P (decl)
631 : : ? G_("constructor does not return a value to test")
632 : 5 : : DECL_DESTRUCTOR_P (decl)
633 : 5 : ? G_("destructor does not return a value to test")
634 : : : G_("function does not return a value to test"));
635 : 6 : return false;
636 : : }
637 : :
638 : : return true;
639 : : }
640 : :
641 : : /* Instantiate each postcondition with the return type to finalize the
642 : : attribute. */
643 : :
644 : : void
645 : 9116714 : rebuild_postconditions (tree decl)
646 : : {
647 : 9116714 : tree type = TREE_TYPE (TREE_TYPE (decl));
648 : 9116714 : tree attributes = DECL_CONTRACTS (decl);
649 : :
650 : 9117628 : for (; attributes ; attributes = TREE_CHAIN (attributes))
651 : : {
652 : 970 : if (!cxx_contract_attribute_p (attributes))
653 : 857 : continue;
654 : 970 : tree contract = TREE_VALUE (TREE_VALUE (attributes));
655 : 970 : if (TREE_CODE (contract) != POSTCONDITION_STMT)
656 : 830 : continue;
657 : 140 : tree condition = CONTRACT_CONDITION (contract);
658 : :
659 : : /* If any conditions are deferred, they're all deferred. Note that
660 : : we don't have to instantiate postconditions in that case because
661 : : the type is available through the declaration. */
662 : 140 : if (TREE_CODE (condition) == DEFERRED_PARSE)
663 : 56 : return;
664 : :
665 : 106 : tree oldvar = POSTCONDITION_IDENTIFIER (contract);
666 : 106 : if (!oldvar)
667 : 25 : continue;
668 : :
669 : : /* Always update the context of the result variable so that it can
670 : : be remapped by remap_contracts. */
671 : 81 : DECL_CONTEXT (oldvar) = decl;
672 : :
673 : : /* If the return type is undeduced, defer until later. */
674 : 81 : if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
675 : : return;
676 : :
677 : : /* Check the postcondition variable. */
678 : 59 : location_t loc = DECL_SOURCE_LOCATION (oldvar);
679 : 59 : if (!check_postcondition_result (decl, type, loc))
680 : : {
681 : 2 : invalidate_contract (contract);
682 : 2 : continue;
683 : : }
684 : :
685 : : /* "Instantiate" the result variable using the known type. Also update
686 : : the context so the inliner will actually remap this the parameter when
687 : : generating contract checks. */
688 : 57 : tree newvar = copy_node (oldvar);
689 : 57 : TREE_TYPE (newvar) = type;
690 : :
691 : : /* Make parameters and result available for substitution. */
692 : 57 : local_specialization_stack stack (lss_copy);
693 : 113 : for (tree t = DECL_ARGUMENTS (decl); t != NULL_TREE; t = TREE_CHAIN (t))
694 : 56 : register_local_identity (t);
695 : 57 : register_local_specialization (newvar, oldvar);
696 : :
697 : 57 : ++processing_contract_condition;
698 : 57 : condition = tsubst_expr (condition, make_tree_vec (0),
699 : : tf_warning_or_error, decl);
700 : 57 : --processing_contract_condition;
701 : :
702 : : /* Update the contract condition and result. */
703 : 57 : POSTCONDITION_IDENTIFIER (contract) = newvar;
704 : 57 : CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
705 : 57 : }
706 : : }
707 : :
708 : : static tree
709 : 832 : build_comment (cp_expr condition)
710 : : {
711 : : /* Try to get the actual source text for the condition; if that fails pretty
712 : : print the resulting tree. */
713 : 832 : char *str = get_source_text_between (global_dc->get_file_cache (),
714 : : condition.get_start (),
715 : : condition.get_finish ());
716 : 832 : if (!str)
717 : : {
718 : : /* FIXME cases where we end up here
719 : : #line macro usage (oof)
720 : : contracts10.C
721 : : contracts11.C */
722 : 23 : const char *str = expr_to_string (condition);
723 : 23 : return build_string_literal (strlen (str) + 1, str);
724 : : }
725 : :
726 : 809 : tree t = build_string_literal (strlen (str) + 1, str);
727 : 809 : free (str);
728 : 809 : return t;
729 : : }
730 : :
731 : : /* Build a contract statement. */
732 : :
733 : : tree
734 : 856 : grok_contract (tree attribute, tree mode, tree result, cp_expr condition,
735 : : location_t loc)
736 : : {
737 : 856 : if (condition == error_mark_node)
738 : : return error_mark_node;
739 : :
740 : 847 : tree_code code;
741 : 847 : if (is_attribute_p ("assert", attribute))
742 : : code = ASSERTION_STMT;
743 : 689 : else if (is_attribute_p ("pre", attribute))
744 : : code = PRECONDITION_STMT;
745 : 121 : else if (is_attribute_p ("post", attribute))
746 : : code = POSTCONDITION_STMT;
747 : : else
748 : 0 : gcc_unreachable ();
749 : :
750 : : /* Build the contract. The condition is added later. In the case that
751 : : the contract is deferred, result an plain identifier, not a result
752 : : variable. */
753 : 847 : tree contract;
754 : 847 : tree type = void_type_node;
755 : 726 : if (code != POSTCONDITION_STMT)
756 : 726 : contract = build3_loc (loc, code, type, mode, NULL_TREE, NULL_TREE);
757 : : else
758 : 121 : contract = build4_loc (loc, code, type, mode, NULL_TREE, NULL_TREE, result);
759 : :
760 : : /* Determine the concrete semantic. */
761 : 847 : set_contract_semantic (contract, compute_concrete_semantic (contract));
762 : :
763 : : /* If the contract is deferred, don't do anything with the condition. */
764 : 847 : if (TREE_CODE (condition) == DEFERRED_PARSE)
765 : : {
766 : 242 : CONTRACT_CONDITION (contract) = condition;
767 : 242 : return contract;
768 : : }
769 : :
770 : : /* Generate the comment from the original condition. */
771 : 605 : CONTRACT_COMMENT (contract) = build_comment (condition);
772 : :
773 : : /* The condition is converted to bool. */
774 : 605 : condition = finish_contract_condition (condition);
775 : :
776 : 605 : if (condition == error_mark_node)
777 : : return error_mark_node;
778 : :
779 : 597 : CONTRACT_CONDITION (contract) = condition;
780 : :
781 : 597 : return contract;
782 : : }
783 : :
784 : : /* Build the contract attribute specifier where IDENTIFIER is one of 'pre',
785 : : 'post' or 'assert' and CONTRACT is the underlying statement. */
786 : : tree
787 : 853 : finish_contract_attribute (tree identifier, tree contract)
788 : : {
789 : 853 : if (contract == error_mark_node)
790 : : return error_mark_node;
791 : :
792 : 836 : tree attribute = build_tree_list (build_tree_list (NULL_TREE, identifier),
793 : : build_tree_list (NULL_TREE, contract));
794 : :
795 : : /* Mark the attribute as dependent if the condition is dependent.
796 : :
797 : : TODO: I'm not sure this is strictly necessary. It's going to be marked as
798 : : such by a subroutine of cplus_decl_attributes. */
799 : 836 : tree condition = CONTRACT_CONDITION (contract);
800 : 836 : if (TREE_CODE (condition) == DEFERRED_PARSE
801 : 836 : || value_dependent_expression_p (condition))
802 : 340 : ATTR_IS_DEPENDENT (attribute) = true;
803 : :
804 : : return attribute;
805 : : }
806 : :
807 : : /* Update condition of a late-parsed contract and postcondition variable,
808 : : if any. */
809 : :
810 : : void
811 : 227 : update_late_contract (tree contract, tree result, tree condition)
812 : : {
813 : 227 : if (TREE_CODE (contract) == POSTCONDITION_STMT)
814 : 31 : POSTCONDITION_IDENTIFIER (contract) = result;
815 : :
816 : : /* Generate the comment from the original condition. */
817 : 227 : CONTRACT_COMMENT (contract) = build_comment (condition);
818 : :
819 : : /* The condition is converted to bool. */
820 : 227 : condition = finish_contract_condition (condition);
821 : 227 : CONTRACT_CONDITION (contract) = condition;
822 : 227 : }
823 : :
824 : : /* Return TRUE iff ATTR has been parsed by the front-end as a c++2a contract
825 : : attribute. */
826 : :
827 : : bool
828 : 569292752 : cxx_contract_attribute_p (const_tree attr)
829 : : {
830 : 569292752 : if (attr == NULL_TREE
831 : 155994215 : || TREE_CODE (attr) != TREE_LIST)
832 : : return false;
833 : :
834 : 155994159 : if (!TREE_PURPOSE (attr) || TREE_CODE (TREE_PURPOSE (attr)) != TREE_LIST)
835 : : return false;
836 : 73311441 : if (!TREE_VALUE (attr) || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST)
837 : : return false;
838 : 657956 : if (!TREE_VALUE (TREE_VALUE (attr)))
839 : : return false;
840 : :
841 : 657956 : return (TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == PRECONDITION_STMT
842 : 647267 : || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == POSTCONDITION_STMT
843 : 1303674 : || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == ASSERTION_STMT);
844 : : }
845 : :
846 : : /* True if ATTR is an assertion. */
847 : :
848 : : bool
849 : 414097668 : cp_contract_assertion_p (const_tree attr)
850 : : {
851 : : /* This is only an assertion if it is a valid cxx contract attribute and the
852 : : statement is an ASSERTION_STMT. */
853 : 414097668 : return cxx_contract_attribute_p (attr)
854 : 414097972 : && TREE_CODE (CONTRACT_STATEMENT (attr)) == ASSERTION_STMT;
855 : : }
856 : :
857 : : /* Remove all c++2a style contract attributes from the DECL_ATTRIBUTEs of the
858 : : FUNCTION_DECL FNDECL. */
859 : :
860 : : void
861 : 5244328 : remove_contract_attributes (tree fndecl)
862 : : {
863 : 5244328 : if (!flag_contracts)
864 : : return;
865 : :
866 : 3254 : tree list = NULL_TREE;
867 : 3677 : for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
868 : 423 : if (!cxx_contract_attribute_p (p))
869 : : {
870 : 117 : tree nl = copy_node (p);
871 : 117 : TREE_CHAIN (nl) = list;
872 : 117 : list = nl;
873 : : }
874 : 3254 : DECL_ATTRIBUTES (fndecl) = nreverse (list);
875 : : }
876 : :
877 : 0 : static tree find_first_non_contract (tree attributes)
878 : : {
879 : 0 : tree head = attributes;
880 : 0 : tree p = find_contract (attributes);
881 : :
882 : : /* There are no contracts. */
883 : 0 : if (!p)
884 : : return head;
885 : :
886 : : /* There are leading contracts. */
887 : 0 : if (p == head)
888 : : {
889 : 0 : while (cxx_contract_attribute_p (p))
890 : 0 : p = TREE_CHAIN (p);
891 : : head = p;
892 : : }
893 : :
894 : : return head;
895 : : }
896 : :
897 : : /* Remove contracts from ATTRIBUTES. */
898 : :
899 : 0 : tree splice_out_contracts (tree attributes)
900 : : {
901 : 0 : tree head = find_first_non_contract (attributes);
902 : 0 : if (!head)
903 : : return NULL_TREE;
904 : :
905 : : /* Splice out remaining contracts. */
906 : 0 : tree p = TREE_CHAIN (head);
907 : 0 : tree q = head;
908 : 0 : while (p)
909 : : {
910 : 0 : if (cxx_contract_attribute_p (p))
911 : : {
912 : : /* Skip a sequence of contracts and then link q to the next
913 : : non-contract attribute. */
914 : 0 : do
915 : 0 : p = TREE_CHAIN (p);
916 : 0 : while (cxx_contract_attribute_p (p));
917 : 0 : TREE_CHAIN (q) = p;
918 : : }
919 : : else
920 : 0 : p = TREE_CHAIN (p);
921 : : }
922 : :
923 : : return head;
924 : : }
925 : :
926 : : /* Copy contract attributes from NEWDECL onto the attribute list of OLDDECL. */
927 : :
928 : 9116240 : void copy_contract_attributes (tree olddecl, tree newdecl)
929 : : {
930 : 9116240 : tree attrs = NULL_TREE;
931 : 9116553 : for (tree c = DECL_CONTRACTS (newdecl); c; c = TREE_CHAIN (c))
932 : : {
933 : 313 : if (!cxx_contract_attribute_p (c))
934 : 1 : continue;
935 : 312 : attrs = tree_cons (TREE_PURPOSE (c), TREE_VALUE (c), attrs);
936 : : }
937 : 9116240 : attrs = chainon (DECL_ATTRIBUTES (olddecl), nreverse (attrs));
938 : 9116240 : DECL_ATTRIBUTES (olddecl) = attrs;
939 : :
940 : : /* And update DECL_CONTEXT of the postcondition result identifier. */
941 : 9116240 : rebuild_postconditions (olddecl);
942 : 9116240 : }
943 : :
944 : : /* Returns the parameter corresponding to the return value of a guarded
945 : : function D. Returns NULL_TREE if D has no postconditions or is void. */
946 : :
947 : : static tree
948 : 74 : get_postcondition_result_parameter (tree d)
949 : : {
950 : 74 : if (!d || d == error_mark_node)
951 : : return NULL_TREE;
952 : :
953 : 74 : if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (d))))
954 : : return NULL_TREE;
955 : :
956 : 66 : tree post = DECL_POST_FN (d);
957 : 66 : if (!post || post == error_mark_node)
958 : : return NULL_TREE;
959 : :
960 : 130 : for (tree arg = DECL_ARGUMENTS (post); arg; arg = TREE_CHAIN (arg))
961 : 130 : if (!TREE_CHAIN (arg))
962 : : return arg;
963 : :
964 : : return NULL_TREE;
965 : : }
966 : :
967 : :
968 : : /* For use with the tree inliner. This preserves non-mapped local variables,
969 : : such as postcondition result variables, during remapping. */
970 : :
971 : : static tree
972 : 1 : retain_decl (tree decl, copy_body_data *)
973 : : {
974 : 1 : return decl;
975 : : }
976 : :
977 : : /* Rewrite the condition of contract in place, so that references to SRC's
978 : : parameters are updated to refer to DST's parameters. The postcondition
979 : : result variable is left unchanged.
980 : :
981 : : This, along with remap_contracts, are subroutines of duplicate_decls.
982 : : When declarations are merged, we sometimes need to update contracts to
983 : : refer to new parameters.
984 : :
985 : : If DUPLICATE_P is true, this is called by duplicate_decls to rewrite contacts
986 : : in terms of a new set of parameters. In this case, we can retain local
987 : : variables appearing in the contract because the contract is not being
988 : : prepared for insertion into a new function. Importantly, this preserves the
989 : : references to postcondition results, which are not replaced during merging.
990 : :
991 : : If false, we're preparing to emit the contract condition into the body
992 : : of a new function, so we need to make copies of all local variables
993 : : appearing in the contract (e.g., if it includes a lambda expression). Note
994 : : that in this case, postcondition results are mapped to the last parameter
995 : : of DST.
996 : :
997 : : This is also used to reuse a parent type's contracts on virtual methods. */
998 : :
999 : : static void
1000 : 758 : remap_contract (tree src, tree dst, tree contract, bool duplicate_p)
1001 : : {
1002 : 758 : copy_body_data id;
1003 : 758 : hash_map<tree, tree> decl_map;
1004 : :
1005 : 758 : memset (&id, 0, sizeof (id));
1006 : 758 : id.src_fn = src;
1007 : 758 : id.dst_fn = dst;
1008 : 758 : id.src_cfun = DECL_STRUCT_FUNCTION (src);
1009 : 758 : id.decl_map = &decl_map;
1010 : :
1011 : : /* If we're merging contracts, don't copy local variables. */
1012 : 758 : id.copy_decl = duplicate_p ? retain_decl : copy_decl_no_change;
1013 : :
1014 : 758 : id.transform_call_graph_edges = CB_CGE_DUPLICATE;
1015 : 758 : id.transform_new_cfg = false;
1016 : 758 : id.transform_return_to_modify = false;
1017 : 758 : id.transform_parameter = true;
1018 : :
1019 : : /* Make sure not to unshare trees behind the front-end's back
1020 : : since front-end specific mechanisms may rely on sharing. */
1021 : 758 : id.regimplify = false;
1022 : 758 : id.do_not_unshare = true;
1023 : 758 : id.do_not_fold = true;
1024 : :
1025 : : /* We're not inside any EH region. */
1026 : 758 : id.eh_lp_nr = 0;
1027 : :
1028 : 758 : bool do_remap = false;
1029 : :
1030 : : /* Insert parameter remappings. */
1031 : 758 : if (TREE_CODE (src) == FUNCTION_DECL)
1032 : 758 : src = DECL_ARGUMENTS (src);
1033 : 758 : if (TREE_CODE (dst) == FUNCTION_DECL)
1034 : 758 : dst = DECL_ARGUMENTS (dst);
1035 : :
1036 : : for (tree sp = src, dp = dst;
1037 : 2110 : sp || dp;
1038 : 1352 : sp = DECL_CHAIN (sp), dp = DECL_CHAIN (dp))
1039 : : {
1040 : 1425 : if (!sp && dp
1041 : 73 : && TREE_CODE (contract) == POSTCONDITION_STMT
1042 : 1498 : && DECL_CHAIN (dp) == NULL_TREE)
1043 : : {
1044 : 73 : gcc_assert (!duplicate_p);
1045 : 73 : if (tree result = POSTCONDITION_IDENTIFIER (contract))
1046 : : {
1047 : 66 : gcc_assert (DECL_P (result));
1048 : 66 : insert_decl_map (&id, result, dp);
1049 : 66 : do_remap = true;
1050 : : }
1051 : : break;
1052 : : }
1053 : 1352 : gcc_assert (sp && dp);
1054 : :
1055 : 1352 : if (sp == dp)
1056 : 0 : continue;
1057 : :
1058 : 1352 : insert_decl_map (&id, sp, dp);
1059 : 1352 : do_remap = true;
1060 : : }
1061 : 758 : if (!do_remap)
1062 : 22 : return;
1063 : :
1064 : 736 : walk_tree (&CONTRACT_CONDITION (contract), copy_tree_body_r, &id, NULL);
1065 : 758 : }
1066 : :
1067 : : /* Rewrite any references to SRC's PARM_DECLs to the corresponding PARM_DECL in
1068 : : DST in all of the contract attributes in CONTRACTS by calling remap_contract
1069 : : on each.
1070 : :
1071 : : This is used for two purposes: to rewrite contract attributes during
1072 : : duplicate_decls, and to prepare contracts for emission into a function's
1073 : : respective precondition and postcondition functions. DUPLICATE_P is used
1074 : : to determine the context in which this function is called. See above for
1075 : : the behavior described by this flag. */
1076 : :
1077 : : void
1078 : 161 : remap_contracts (tree src, tree dst, tree contracts, bool duplicate_p)
1079 : : {
1080 : 391 : for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
1081 : : {
1082 : 230 : if (!cxx_contract_attribute_p (attr))
1083 : 0 : continue;
1084 : 230 : tree contract = CONTRACT_STATEMENT (attr);
1085 : 230 : if (TREE_CODE (CONTRACT_CONDITION (contract)) != DEFERRED_PARSE)
1086 : 223 : remap_contract (src, dst, contract, duplicate_p);
1087 : : }
1088 : 161 : }
1089 : :
1090 : : /* Helper to replace references to dummy this parameters with references to
1091 : : the first argument of the FUNCTION_DECL DATA. */
1092 : :
1093 : : static tree
1094 : 2545 : remap_dummy_this_1 (tree *tp, int *, void *data)
1095 : : {
1096 : 2545 : if (!is_this_parameter (*tp))
1097 : : return NULL_TREE;
1098 : 47 : tree fn = (tree)data;
1099 : 47 : *tp = DECL_ARGUMENTS (fn);
1100 : 47 : return NULL_TREE;
1101 : : }
1102 : :
1103 : : /* Replace all references to dummy this parameters in EXPR with references to
1104 : : the first argument of the FUNCTION_DECL FN. */
1105 : :
1106 : : static void
1107 : 729 : remap_dummy_this (tree fn, tree *expr)
1108 : : {
1109 : 0 : walk_tree (expr, remap_dummy_this_1, fn, NULL);
1110 : 0 : }
1111 : :
1112 : : /* Contract matching. */
1113 : :
1114 : : /* True if the contract is valid. */
1115 : :
1116 : : static bool
1117 : 224 : contract_valid_p (tree contract)
1118 : : {
1119 : 224 : return CONTRACT_CONDITION (contract) != error_mark_node;
1120 : : }
1121 : :
1122 : : /* True if the contract attribute is valid. */
1123 : :
1124 : : static bool
1125 : 224 : contract_attribute_valid_p (tree attribute)
1126 : : {
1127 : 224 : return contract_valid_p (TREE_VALUE (TREE_VALUE (attribute)));
1128 : : }
1129 : :
1130 : : /* Compare the contract conditions of OLD_ATTR and NEW_ATTR. Returns false
1131 : : if the conditions are equivalent, and true otherwise. */
1132 : :
1133 : : static bool
1134 : 109 : check_for_mismatched_contracts (tree old_attr, tree new_attr,
1135 : : contract_matching_context ctx)
1136 : : {
1137 : 109 : tree old_contract = CONTRACT_STATEMENT (old_attr);
1138 : 109 : tree new_contract = CONTRACT_STATEMENT (new_attr);
1139 : :
1140 : : /* Different kinds of contracts do not match. */
1141 : 109 : if (TREE_CODE (old_contract) != TREE_CODE (new_contract))
1142 : : {
1143 : 0 : auto_diagnostic_group d;
1144 : 0 : error_at (EXPR_LOCATION (new_contract),
1145 : : ctx == cmc_declaration
1146 : : ? "mismatched contract attribute in declaration"
1147 : : : "mismatched contract attribute in override");
1148 : 0 : inform (EXPR_LOCATION (old_contract), "previous contract here");
1149 : 0 : return true;
1150 : 0 : }
1151 : :
1152 : : /* A deferred contract tentatively matches. */
1153 : 109 : if (CONTRACT_CONDITION_DEFERRED_P (new_contract))
1154 : : return false;
1155 : :
1156 : : /* Compare the conditions of the contracts. We fold immediately to avoid
1157 : : issues comparing contracts on overrides that use parameters -- see
1158 : : contracts-pre3. */
1159 : 105 : tree t1 = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
1160 : 105 : tree t2 = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
1161 : :
1162 : : /* Compare the contracts. The fold doesn't eliminate conversions to members.
1163 : : Set the comparing_override_contracts flag to ensure that references
1164 : : through 'this' are equal if they designate the same member, regardless of
1165 : : the path those members. */
1166 : 105 : bool saved_comparing_contracts = comparing_override_contracts;
1167 : 105 : comparing_override_contracts = (ctx == cmc_override);
1168 : 105 : bool matching_p = cp_tree_equal (t1, t2);
1169 : 105 : comparing_override_contracts = saved_comparing_contracts;
1170 : :
1171 : 105 : if (!matching_p)
1172 : : {
1173 : 14 : auto_diagnostic_group d;
1174 : 22 : error_at (EXPR_LOCATION (CONTRACT_CONDITION (new_contract)),
1175 : : ctx == cmc_declaration
1176 : : ? "mismatched contract condition in declaration"
1177 : : : "mismatched contract condition in override");
1178 : 14 : inform (EXPR_LOCATION (CONTRACT_CONDITION (old_contract)),
1179 : : "previous contract here");
1180 : 14 : return true;
1181 : 14 : }
1182 : :
1183 : : return false;
1184 : : }
1185 : :
1186 : : /* Compare the contract attributes of OLDDECL and NEWDECL. Returns true
1187 : : if the contracts match, and false if they differ. */
1188 : :
1189 : : bool
1190 : 88 : match_contract_conditions (location_t oldloc, tree old_attrs,
1191 : : location_t newloc, tree new_attrs,
1192 : : contract_matching_context ctx)
1193 : : {
1194 : : /* Contracts only match if they are both specified. */
1195 : 88 : if (!old_attrs || !new_attrs)
1196 : : return true;
1197 : :
1198 : : /* Compare each contract in turn. */
1199 : 183 : while (old_attrs && new_attrs)
1200 : : {
1201 : : /* If either contract is ill-formed, skip the rest of the comparison,
1202 : : since we've already diagnosed an error. */
1203 : 115 : if (!contract_attribute_valid_p (new_attrs)
1204 : 115 : || !contract_attribute_valid_p (old_attrs))
1205 : : return false;
1206 : :
1207 : 109 : if (check_for_mismatched_contracts (old_attrs, new_attrs, ctx))
1208 : : return false;
1209 : 95 : old_attrs = CONTRACT_CHAIN (old_attrs);
1210 : 95 : new_attrs = CONTRACT_CHAIN (new_attrs);
1211 : : }
1212 : :
1213 : : /* If we didn't compare all attributes, the contracts don't match. */
1214 : 68 : if (old_attrs || new_attrs)
1215 : : {
1216 : 4 : auto_diagnostic_group d;
1217 : 4 : error_at (newloc,
1218 : : ctx == cmc_declaration
1219 : : ? "declaration has a different number of contracts than "
1220 : : "previously declared"
1221 : : : "override has a different number of contracts than "
1222 : : "previously declared");
1223 : 5 : inform (oldloc,
1224 : : new_attrs
1225 : : ? "original declaration with fewer contracts here"
1226 : : : "original declaration with more contracts here");
1227 : 4 : return false;
1228 : 4 : }
1229 : :
1230 : : return true;
1231 : : }
1232 : :
1233 : : /* Deferred contract mapping.
1234 : :
1235 : : This is used to compare late-parsed contracts on overrides with their
1236 : : base class functions.
1237 : :
1238 : : TODO: It seems like this could be replaced by a simple list that maps from
1239 : : overrides to their base functions. It's not clear that we really need
1240 : : a map to a function + a list of contracts. */
1241 : :
1242 : : /* Map from FNDECL to a tree list of contracts that have not been matched or
1243 : : diagnosed yet. The TREE_PURPOSE is the basefn we're overriding, and the
1244 : : TREE_VALUE is the list of contract attrs for BASEFN. */
1245 : :
1246 : : static hash_map<tree_decl_hash, tree> pending_guarded_decls;
1247 : :
1248 : : void
1249 : 24 : defer_guarded_contract_match (tree fndecl, tree fn, tree contracts)
1250 : : {
1251 : 24 : if (!pending_guarded_decls.get (fndecl))
1252 : : {
1253 : 21 : pending_guarded_decls.put (fndecl, build_tree_list (fn, contracts));
1254 : 21 : return;
1255 : : }
1256 : 3 : for (tree pending = *pending_guarded_decls.get (fndecl);
1257 : 6 : pending;
1258 : 3 : pending = TREE_CHAIN (pending))
1259 : : {
1260 : 6 : if (TREE_VALUE (pending) == contracts)
1261 : : return;
1262 : 3 : if (TREE_CHAIN (pending) == NULL_TREE)
1263 : 3 : TREE_CHAIN (pending) = build_tree_list (fn, contracts);
1264 : : }
1265 : : }
1266 : :
1267 : : /* If the FUNCTION_DECL DECL has any contracts that had their matching
1268 : : deferred earlier, do that checking now. */
1269 : :
1270 : : void
1271 : 163 : match_deferred_contracts (tree decl)
1272 : : {
1273 : 163 : tree *tp = pending_guarded_decls.get (decl);
1274 : 163 : if (!tp)
1275 : 163 : return;
1276 : :
1277 : 20 : gcc_assert(!contract_any_deferred_p (DECL_CONTRACTS (decl)));
1278 : :
1279 : 20 : processing_template_decl_sentinel ptds;
1280 : 20 : processing_template_decl = uses_template_parms (decl);
1281 : :
1282 : : /* Do late contract matching. */
1283 : 43 : for (tree pending = *tp; pending; pending = TREE_CHAIN (pending))
1284 : : {
1285 : 23 : tree new_contracts = TREE_VALUE (pending);
1286 : 23 : location_t new_loc = CONTRACT_SOURCE_LOCATION (new_contracts);
1287 : 23 : tree old_contracts = DECL_CONTRACTS (decl);
1288 : 23 : location_t old_loc = CONTRACT_SOURCE_LOCATION (old_contracts);
1289 : 23 : tree base = TREE_PURPOSE (pending);
1290 : 23 : match_contract_conditions (new_loc, new_contracts,
1291 : : old_loc, old_contracts,
1292 : : base ? cmc_override : cmc_declaration);
1293 : : }
1294 : :
1295 : : /* Clear out deferred match list so we don't check it twice. */
1296 : 20 : pending_guarded_decls.remove (decl);
1297 : 20 : }
1298 : :
1299 : : /* Map from FUNCTION_DECL to a FUNCTION_DECL for either the PRE_FN or POST_FN.
1300 : : These are used to parse contract conditions and are called inside the body
1301 : : of the guarded function. */
1302 : : static GTY(()) hash_map<tree, tree> *decl_pre_fn;
1303 : : static GTY(()) hash_map<tree, tree> *decl_post_fn;
1304 : :
1305 : : /* Returns the precondition funtion for D, or null if not set. */
1306 : :
1307 : : tree
1308 : 15420766 : get_precondition_function (tree d)
1309 : : {
1310 : 15420766 : hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1311 : 15420766 : tree *result = decl_pre_fn->get (d);
1312 : 15420766 : return result ? *result : NULL_TREE;
1313 : : }
1314 : :
1315 : : /* Returns the postcondition funtion for D, or null if not set. */
1316 : :
1317 : : tree
1318 : 15419364 : get_postcondition_function (tree d)
1319 : : {
1320 : 15419364 : hash_map_maybe_create<hm_ggc> (decl_post_fn);
1321 : 15419364 : tree *result = decl_post_fn->get (d);
1322 : 15419364 : return result ? *result : NULL_TREE;
1323 : : }
1324 : :
1325 : : /* Makes PRE the precondition function for D. */
1326 : :
1327 : : void
1328 : 357 : set_precondition_function (tree d, tree pre)
1329 : : {
1330 : 357 : gcc_assert (pre);
1331 : 357 : hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1332 : 357 : gcc_assert (!decl_pre_fn->get (d));
1333 : 357 : decl_pre_fn->put (d, pre);
1334 : 357 : }
1335 : :
1336 : : /* Makes POST the postcondition function for D. */
1337 : :
1338 : : void
1339 : 80 : set_postcondition_function (tree d, tree post)
1340 : : {
1341 : 80 : gcc_assert (post);
1342 : 80 : hash_map_maybe_create<hm_ggc> (decl_post_fn);
1343 : 80 : gcc_assert (!decl_post_fn->get (d));
1344 : 80 : decl_post_fn->put (d, post);
1345 : 80 : }
1346 : :
1347 : : /* Set the PRE and POST functions for D. Note that PRE and POST can be
1348 : : null in this case. If so the functions are not recorded. */
1349 : :
1350 : : void
1351 : 323574 : set_contract_functions (tree d, tree pre, tree post)
1352 : : {
1353 : 323574 : if (pre)
1354 : 357 : set_precondition_function (d, pre);
1355 : 323574 : if (post)
1356 : 73 : set_postcondition_function (d, post);
1357 : 323574 : }
1358 : :
1359 : : /* Return a copy of the FUNCTION_DECL IDECL with its own unshared
1360 : : PARM_DECL and DECL_ATTRIBUTEs. */
1361 : :
1362 : : static tree
1363 : 416 : copy_fn_decl (tree idecl)
1364 : : {
1365 : 416 : tree decl = copy_decl (idecl);
1366 : 416 : DECL_ATTRIBUTES (decl) = copy_list (DECL_ATTRIBUTES (idecl));
1367 : :
1368 : 416 : if (DECL_RESULT (idecl))
1369 : : {
1370 : 416 : DECL_RESULT (decl) = copy_decl (DECL_RESULT (idecl));
1371 : 416 : DECL_CONTEXT (DECL_RESULT (decl)) = decl;
1372 : : }
1373 : 416 : if (!DECL_ARGUMENTS (idecl) || VOID_TYPE_P (DECL_ARGUMENTS (idecl)))
1374 : : return decl;
1375 : :
1376 : 396 : tree last = DECL_ARGUMENTS (decl) = copy_decl (DECL_ARGUMENTS (decl));
1377 : 396 : DECL_CONTEXT (last) = decl;
1378 : 612 : for (tree p = TREE_CHAIN (DECL_ARGUMENTS (idecl)); p; p = TREE_CHAIN (p))
1379 : : {
1380 : 216 : if (VOID_TYPE_P (p))
1381 : : {
1382 : 0 : TREE_CHAIN (last) = void_list_node;
1383 : 0 : break;
1384 : : }
1385 : 216 : last = TREE_CHAIN (last) = copy_decl (p);
1386 : 216 : DECL_CONTEXT (last) = decl;
1387 : : }
1388 : : return decl;
1389 : : }
1390 : :
1391 : : /* Build a declaration for the pre- or postcondition of a guarded FNDECL. */
1392 : :
1393 : : static tree
1394 : 416 : build_contract_condition_function (tree fndecl, bool pre)
1395 : : {
1396 : 416 : if (TREE_TYPE (fndecl) == error_mark_node)
1397 : : return error_mark_node;
1398 : 416 : if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
1399 : 416 : && !TYPE_METHOD_BASETYPE (TREE_TYPE (fndecl)))
1400 : : return error_mark_node;
1401 : :
1402 : : /* Create and rename the unchecked function and give an internal name. */
1403 : 416 : tree fn = copy_fn_decl (fndecl);
1404 : 416 : DECL_RESULT (fn) = NULL_TREE;
1405 : 416 : tree value_type = pre ? void_type_node : TREE_TYPE (TREE_TYPE (fn));
1406 : :
1407 : : /* Don't propagate declaration attributes to the checking function,
1408 : : including the original contracts. */
1409 : 416 : DECL_ATTRIBUTES (fn) = NULL_TREE;
1410 : :
1411 : 416 : tree arg_types = NULL_TREE;
1412 : 416 : tree *last = &arg_types;
1413 : :
1414 : : /* FIXME will later optimizations delete unused args to prevent extra arg
1415 : : passing? do we care? */
1416 : 416 : tree class_type = NULL_TREE;
1417 : 416 : for (tree arg_type = TYPE_ARG_TYPES (TREE_TYPE (fn));
1418 : 1028 : arg_type && arg_type != void_list_node;
1419 : 612 : arg_type = TREE_CHAIN (arg_type))
1420 : : {
1421 : 612 : if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
1422 : 612 : && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type)
1423 : : {
1424 : 155 : class_type = TREE_TYPE (TREE_VALUE (arg_type));
1425 : 155 : continue;
1426 : : }
1427 : 457 : *last = build_tree_list (TREE_PURPOSE (arg_type), TREE_VALUE (arg_type));
1428 : 457 : last = &TREE_CHAIN (*last);
1429 : : }
1430 : :
1431 : 416 : if (pre || VOID_TYPE_P (value_type))
1432 : 350 : *last = void_list_node;
1433 : : else
1434 : : {
1435 : 66 : tree name = get_identifier ("__r");
1436 : 66 : tree parm = build_lang_decl (PARM_DECL, name, value_type);
1437 : 66 : DECL_CONTEXT (parm) = fn;
1438 : 66 : DECL_ARTIFICIAL (parm) = true;
1439 : 66 : DECL_ARGUMENTS (fn) = chainon (DECL_ARGUMENTS (fn), parm);
1440 : :
1441 : 66 : *last = build_tree_list (NULL_TREE, value_type);
1442 : 66 : TREE_CHAIN (*last) = void_list_node;
1443 : :
1444 : : /* The handler is a void return. */
1445 : 66 : value_type = void_type_node;
1446 : : }
1447 : :
1448 : 416 : TREE_TYPE (fn) = build_function_type (value_type, arg_types);
1449 : 416 : if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl))
1450 : 155 : TREE_TYPE (fn) = build_method_type (class_type, TREE_TYPE (fn));
1451 : :
1452 : 416 : DECL_NAME (fn) = copy_node (DECL_NAME (fn));
1453 : 416 : DECL_INITIAL (fn) = error_mark_node;
1454 : 416 : DECL_ABSTRACT_ORIGIN (fn) = fndecl;
1455 : :
1456 : 416 : IDENTIFIER_VIRTUAL_P (DECL_NAME (fn)) = false;
1457 : 416 : DECL_VIRTUAL_P (fn) = false;
1458 : :
1459 : : /* Make these functions internal if we can, i.e. if the guarded function is
1460 : : not vague linkage, or if we can put them in a comdat group with the
1461 : : guarded function. */
1462 : 416 : if (!DECL_WEAK (fndecl) || HAVE_COMDAT_GROUP)
1463 : : {
1464 : 416 : TREE_PUBLIC (fn) = false;
1465 : 416 : DECL_EXTERNAL (fn) = false;
1466 : 416 : DECL_WEAK (fn) = false;
1467 : 416 : DECL_COMDAT (fn) = false;
1468 : :
1469 : : /* We may not have set the comdat group on the guarded function yet.
1470 : : If we haven't, we'll add this to the same group in comdat_linkage
1471 : : later. Otherwise, add it to the same comdat group now. */
1472 : 416 : if (DECL_ONE_ONLY (fndecl))
1473 : : {
1474 : 4 : symtab_node *n = symtab_node::get (fndecl);
1475 : 4 : cgraph_node::get_create (fn)->add_to_same_comdat_group (n);
1476 : : }
1477 : :
1478 : 416 : DECL_INTERFACE_KNOWN (fn) = true;
1479 : : }
1480 : :
1481 : 416 : DECL_ARTIFICIAL (fn) = true;
1482 : :
1483 : : /* Update various inline related declaration properties. */
1484 : : //DECL_DECLARED_INLINE_P (fn) = true;
1485 : 416 : DECL_DISREGARD_INLINE_LIMITS (fn) = true;
1486 : 416 : TREE_NO_WARNING (fn) = 1;
1487 : :
1488 : 416 : return fn;
1489 : : }
1490 : :
1491 : : /* Return true if CONTRACT is checked or assumed under the current build
1492 : : configuration. */
1493 : :
1494 : : bool
1495 : 2210 : contract_active_p (tree contract)
1496 : : {
1497 : 2210 : return get_contract_semantic (contract) != CCS_IGNORE;
1498 : : }
1499 : :
1500 : : static bool
1501 : 806493 : has_active_contract_condition (tree d, tree_code c)
1502 : : {
1503 : 807544 : for (tree as = DECL_CONTRACTS (d) ; as != NULL_TREE; as = CONTRACT_CHAIN (as))
1504 : : {
1505 : 1969 : tree contract = TREE_VALUE (TREE_VALUE (as));
1506 : 1969 : if (TREE_CODE (contract) == c && contract_active_p (contract))
1507 : : return true;
1508 : : }
1509 : : return false;
1510 : : }
1511 : :
1512 : : /* True if D has any checked or assumed preconditions. */
1513 : :
1514 : : static bool
1515 : 797 : has_active_preconditions (tree d)
1516 : : {
1517 : 0 : return has_active_contract_condition (d, PRECONDITION_STMT);
1518 : : }
1519 : :
1520 : : /* True if D has any checked or assumed postconditions. */
1521 : :
1522 : : static bool
1523 : 805696 : has_active_postconditions (tree d)
1524 : : {
1525 : 0 : return has_active_contract_condition (d, POSTCONDITION_STMT);
1526 : : }
1527 : :
1528 : : /* Return true if any contract in the CONTRACT list is checked or assumed
1529 : : under the current build configuration. */
1530 : :
1531 : : bool
1532 : 54138 : contract_any_active_p (tree contract)
1533 : : {
1534 : 54156 : for (; contract != NULL_TREE; contract = CONTRACT_CHAIN (contract))
1535 : 1284 : if (contract_active_p (TREE_VALUE (TREE_VALUE (contract))))
1536 : : return true;
1537 : : return false;
1538 : : }
1539 : :
1540 : : /* Do we need to mess with contracts for DECL1? */
1541 : :
1542 : : static bool
1543 : 287913576 : handle_contracts_p (tree decl1)
1544 : : {
1545 : 287913576 : return (flag_contracts
1546 : 130496 : && !processing_template_decl
1547 : 66904 : && DECL_ABSTRACT_ORIGIN (decl1) == NULL_TREE
1548 : 287967714 : && contract_any_active_p (DECL_CONTRACTS (decl1)));
1549 : : }
1550 : :
1551 : : /* Should we break out DECL1's pre/post contracts into separate functions?
1552 : : FIXME I'd like this to default to 0, but that will need an overhaul to the
1553 : : return identifier handling to just refer to the RESULT_DECL. */
1554 : :
1555 : : static bool
1556 : 1707 : outline_contracts_p (tree decl1)
1557 : : {
1558 : 1707 : return (!DECL_CONSTRUCTOR_P (decl1)
1559 : 1707 : && !DECL_DESTRUCTOR_P (decl1));
1560 : : }
1561 : :
1562 : : /* Build the precondition checking function for D. */
1563 : :
1564 : : static tree
1565 : 375 : build_precondition_function (tree d)
1566 : : {
1567 : 375 : if (!has_active_preconditions (d))
1568 : : return NULL_TREE;
1569 : :
1570 : 342 : return build_contract_condition_function (d, /*pre=*/true);
1571 : : }
1572 : :
1573 : : /* Build the postcondition checking function for D. If the return
1574 : : type is undeduced, don't build the function yet. We do that in
1575 : : apply_deduced_return_type. */
1576 : :
1577 : : static tree
1578 : 382 : build_postcondition_function (tree d)
1579 : : {
1580 : 382 : if (!has_active_postconditions (d))
1581 : : return NULL_TREE;
1582 : :
1583 : 81 : tree type = TREE_TYPE (TREE_TYPE (d));
1584 : 81 : if (is_auto (type))
1585 : : return NULL_TREE;
1586 : :
1587 : 74 : return build_contract_condition_function (d, /*pre=*/false);
1588 : : }
1589 : :
1590 : : static void
1591 : 375 : build_contract_function_decls (tree d)
1592 : : {
1593 : : /* Constructors and destructors have their contracts inserted inline. */
1594 : 375 : if (!outline_contracts_p (d))
1595 : : return;
1596 : :
1597 : : /* Build the pre/post functions (or not). */
1598 : 375 : tree pre = build_precondition_function (d);
1599 : 375 : tree post = build_postcondition_function (d);
1600 : 375 : set_contract_functions (d, pre, post);
1601 : : }
1602 : :
1603 : : static const char *
1604 : 699 : get_contract_level_name (tree contract)
1605 : : {
1606 : 699 : if (CONTRACT_LITERAL_MODE_P (contract))
1607 : : return "";
1608 : 684 : if (tree mode = CONTRACT_MODE (contract))
1609 : 43 : if (tree level = TREE_VALUE (mode))
1610 : 43 : return IDENTIFIER_POINTER (level);
1611 : : return "default";
1612 : : }
1613 : :
1614 : : static const char *
1615 : 699 : get_contract_role_name (tree contract)
1616 : : {
1617 : 699 : if (CONTRACT_LITERAL_MODE_P (contract))
1618 : : return "";
1619 : 684 : if (tree mode = CONTRACT_MODE (contract))
1620 : 43 : if (tree role = TREE_PURPOSE (mode))
1621 : 24 : return IDENTIFIER_POINTER (role);
1622 : : return "default";
1623 : : }
1624 : :
1625 : : /* Build a layout-compatible internal version of std::contract_violation. */
1626 : :
1627 : : static tree
1628 : 699 : get_pseudo_contract_violation_type ()
1629 : : {
1630 : 699 : if (!pseudo_contract_violation_type)
1631 : : {
1632 : : /* Must match <contract>:
1633 : : class contract_violation {
1634 : : const char* _M_file;
1635 : : const char* _M_function;
1636 : : const char* _M_comment;
1637 : : const char* _M_level;
1638 : : const char* _M_role;
1639 : : uint_least32_t _M_line;
1640 : : signed char _M_continue;
1641 : : If this changes, also update the initializer in
1642 : : build_contract_violation. */
1643 : 119 : struct field_info { tree type; const char* name; };
1644 : 119 : const field_info info[] = {
1645 : 119 : { const_string_type_node, "_M_file" },
1646 : : { const_string_type_node, "_M_function" },
1647 : : { const_string_type_node, "_M_comment" },
1648 : : { const_string_type_node, "_M_level" },
1649 : : { const_string_type_node, "_M_role" },
1650 : 119 : { uint_least32_type_node, "_M_line" },
1651 : 119 : { signed_char_type_node, "_M_continue" }
1652 : 119 : };
1653 : 119 : tree fields = NULL_TREE;
1654 : 952 : for (const field_info& i : info)
1655 : : {
1656 : : /* finish_builtin_struct wants fieldss chained in reverse. */
1657 : 833 : tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1658 : 833 : get_identifier (i.name), i.type);
1659 : 833 : DECL_CHAIN (next) = fields;
1660 : 833 : fields = next;
1661 : : }
1662 : 119 : iloc_sentinel ils (input_location);
1663 : 119 : input_location = BUILTINS_LOCATION;
1664 : 119 : pseudo_contract_violation_type = make_class_type (RECORD_TYPE);
1665 : 119 : finish_builtin_struct (pseudo_contract_violation_type,
1666 : : "__pseudo_contract_violation",
1667 : : fields, NULL_TREE);
1668 : 238 : CLASSTYPE_AS_BASE (pseudo_contract_violation_type)
1669 : 119 : = pseudo_contract_violation_type;
1670 : 119 : DECL_CONTEXT (TYPE_NAME (pseudo_contract_violation_type))
1671 : 119 : = FROB_CONTEXT (global_namespace);
1672 : 119 : TREE_PUBLIC (TYPE_NAME (pseudo_contract_violation_type)) = true;
1673 : 119 : CLASSTYPE_LITERAL_P (pseudo_contract_violation_type) = true;
1674 : 119 : CLASSTYPE_LAZY_COPY_CTOR (pseudo_contract_violation_type) = true;
1675 : 119 : xref_basetypes (pseudo_contract_violation_type, /*bases=*/NULL_TREE);
1676 : 119 : pseudo_contract_violation_type
1677 : 119 : = cp_build_qualified_type (pseudo_contract_violation_type,
1678 : : TYPE_QUAL_CONST);
1679 : 119 : }
1680 : 699 : return pseudo_contract_violation_type;
1681 : : }
1682 : :
1683 : : /* Return a VAR_DECL to pass to handle_contract_violation. */
1684 : :
1685 : : static tree
1686 : 699 : build_contract_violation (tree contract, contract_continuation cmode)
1687 : : {
1688 : 699 : expanded_location loc = expand_location (EXPR_LOCATION (contract));
1689 : 887 : const char *function = fndecl_name (DECL_ORIGIN (current_function_decl));
1690 : 699 : const char *level = get_contract_level_name (contract);
1691 : 699 : const char *role = get_contract_role_name (contract);
1692 : :
1693 : : /* Must match the type layout in get_pseudo_contract_violation_type. */
1694 : 699 : tree ctor = build_constructor_va
1695 : 1398 : (init_list_type_node, 7,
1696 : : NULL_TREE, build_string_literal (loc.file),
1697 : : NULL_TREE, build_string_literal (function),
1698 : 699 : NULL_TREE, CONTRACT_COMMENT (contract),
1699 : : NULL_TREE, build_string_literal (level),
1700 : : NULL_TREE, build_string_literal (role),
1701 : 699 : NULL_TREE, build_int_cst (uint_least32_type_node, loc.line),
1702 : 699 : NULL_TREE, build_int_cst (signed_char_type_node, cmode));
1703 : :
1704 : 699 : ctor = finish_compound_literal (get_pseudo_contract_violation_type (),
1705 : : ctor, tf_none);
1706 : 699 : protected_set_expr_location (ctor, EXPR_LOCATION (contract));
1707 : 699 : return ctor;
1708 : : }
1709 : :
1710 : : /* Return handle_contract_violation(), declaring it if needed. */
1711 : :
1712 : : static tree
1713 : 699 : declare_handle_contract_violation ()
1714 : : {
1715 : 699 : tree fnname = get_identifier ("handle_contract_violation");
1716 : 699 : tree viol_name = get_identifier ("contract_violation");
1717 : 699 : tree l = lookup_qualified_name (global_namespace, fnname,
1718 : : LOOK_want::HIDDEN_FRIEND);
1719 : 1488 : for (tree f: lkp_range (l))
1720 : 699 : if (TREE_CODE (f) == FUNCTION_DECL)
1721 : : {
1722 : 609 : tree parms = TYPE_ARG_TYPES (TREE_TYPE (f));
1723 : 609 : if (remaining_arguments (parms) != 1)
1724 : 0 : continue;
1725 : 609 : tree parmtype = non_reference (TREE_VALUE (parms));
1726 : 609 : if (CLASS_TYPE_P (parmtype)
1727 : 1218 : && TYPE_IDENTIFIER (parmtype) == viol_name)
1728 : 609 : return f;
1729 : : }
1730 : :
1731 : 90 : tree id_exp = get_identifier ("experimental");
1732 : 90 : tree ns_exp = lookup_qualified_name (std_node, id_exp);
1733 : :
1734 : 90 : tree violation = error_mark_node;
1735 : 90 : if (TREE_CODE (ns_exp) == NAMESPACE_DECL)
1736 : 0 : violation = lookup_qualified_name (ns_exp, viol_name,
1737 : : LOOK_want::TYPE
1738 : : |LOOK_want::HIDDEN_FRIEND);
1739 : :
1740 : 90 : if (TREE_CODE (violation) == TYPE_DECL)
1741 : 0 : violation = TREE_TYPE (violation);
1742 : : else
1743 : : {
1744 : 90 : push_nested_namespace (std_node);
1745 : 90 : push_namespace (id_exp, /*inline*/false);
1746 : 90 : violation = make_class_type (RECORD_TYPE);
1747 : 90 : create_implicit_typedef (viol_name, violation);
1748 : 90 : DECL_SOURCE_LOCATION (TYPE_NAME (violation)) = BUILTINS_LOCATION;
1749 : 90 : DECL_CONTEXT (TYPE_NAME (violation)) = current_namespace;
1750 : 90 : TREE_PUBLIC (TYPE_NAME (violation)) = true;
1751 : 90 : pushdecl_namespace_level (TYPE_NAME (violation), /*hidden*/true);
1752 : 90 : pop_namespace ();
1753 : 90 : pop_nested_namespace (std_node);
1754 : : }
1755 : :
1756 : 90 : tree argtype = cp_build_qualified_type (violation, TYPE_QUAL_CONST);
1757 : 90 : argtype = cp_build_reference_type (argtype, /*rval*/false);
1758 : 90 : tree fntype = build_function_type_list (void_type_node, argtype, NULL_TREE);
1759 : :
1760 : 90 : push_nested_namespace (global_namespace);
1761 : 90 : tree fn = build_cp_library_fn_ptr ("handle_contract_violation", fntype,
1762 : : ECF_COLD);
1763 : 90 : pushdecl_namespace_level (fn, /*hiding*/true);
1764 : 90 : pop_nested_namespace (global_namespace);
1765 : :
1766 : 90 : return fn;
1767 : : }
1768 : :
1769 : : /* Build the call to handle_contract_violation for CONTRACT. */
1770 : :
1771 : : static void
1772 : 699 : build_contract_handler_call (tree contract,
1773 : : contract_continuation cmode)
1774 : : {
1775 : : /* We may need to declare new types, ensure they are not considered
1776 : : attached to a named module. */
1777 : 699 : auto module_kind_override = make_temp_override
1778 : 699 : (module_kind, module_kind & ~(MK_PURVIEW | MK_ATTACH | MK_EXPORTING));
1779 : :
1780 : 699 : tree violation = build_contract_violation (contract, cmode);
1781 : 699 : tree violation_fn = declare_handle_contract_violation ();
1782 : 699 : tree call = build_call_n (violation_fn, 1, build_address (violation));
1783 : 699 : finish_expr_stmt (call);
1784 : 699 : }
1785 : :
1786 : : /* Generate the code that checks or assumes a contract, but do not attach
1787 : : it to the current context. This is called during genericization. */
1788 : :
1789 : : tree
1790 : 759 : build_contract_check (tree contract)
1791 : : {
1792 : 759 : contract_semantic semantic = get_contract_semantic (contract);
1793 : 759 : if (semantic == CCS_INVALID)
1794 : : return NULL_TREE;
1795 : :
1796 : : /* Ignored contracts are never checked or assumed. */
1797 : 759 : if (semantic == CCS_IGNORE)
1798 : 30 : return void_node;
1799 : :
1800 : 729 : remap_dummy_this (current_function_decl, &CONTRACT_CONDITION (contract));
1801 : 729 : tree condition = CONTRACT_CONDITION (contract);
1802 : 729 : if (condition == error_mark_node)
1803 : : return NULL_TREE;
1804 : :
1805 : 729 : location_t loc = EXPR_LOCATION (contract);
1806 : :
1807 : 729 : if (semantic == CCS_ASSUME)
1808 : 30 : return build_assume_call (loc, condition);
1809 : :
1810 : 699 : tree if_stmt = begin_if_stmt ();
1811 : 699 : tree cond = build_x_unary_op (loc,
1812 : : TRUTH_NOT_EXPR,
1813 : 699 : condition, NULL_TREE,
1814 : : tf_warning_or_error);
1815 : 699 : finish_if_stmt_cond (cond, if_stmt);
1816 : :
1817 : : /* Get the continuation mode. */
1818 : 699 : contract_continuation cmode;
1819 : 699 : switch (semantic)
1820 : : {
1821 : : case CCS_NEVER: cmode = NEVER_CONTINUE; break;
1822 : 475 : case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
1823 : 0 : default: gcc_unreachable ();
1824 : : }
1825 : :
1826 : 699 : build_contract_handler_call (contract, cmode);
1827 : 699 : if (cmode == NEVER_CONTINUE)
1828 : 224 : finish_expr_stmt (build_call_a (terminate_fn, 0, nullptr));
1829 : :
1830 : 699 : finish_then_clause (if_stmt);
1831 : 699 : tree scope = IF_SCOPE (if_stmt);
1832 : 699 : IF_SCOPE (if_stmt) = NULL;
1833 : 699 : return do_poplevel (scope);
1834 : : }
1835 : :
1836 : : /* Add the contract statement CONTRACT to the current block if valid. */
1837 : :
1838 : : static void
1839 : 756 : emit_contract_statement (tree contract)
1840 : : {
1841 : : /* Only add valid contracts. */
1842 : 756 : if (get_contract_semantic (contract) != CCS_INVALID
1843 : 756 : && CONTRACT_CONDITION (contract) != error_mark_node)
1844 : 754 : add_stmt (contract);
1845 : 756 : }
1846 : :
1847 : : /* Generate the statement for the given contract attribute by adding the
1848 : : statement to the current block. Returns the next contract in the chain. */
1849 : :
1850 : : static tree
1851 : 233 : emit_contract_attr (tree attr)
1852 : : {
1853 : 233 : gcc_assert (TREE_CODE (attr) == TREE_LIST);
1854 : :
1855 : 233 : emit_contract_statement (CONTRACT_STATEMENT (attr));
1856 : :
1857 : 233 : return CONTRACT_CHAIN (attr);
1858 : : }
1859 : :
1860 : : /* Add the statements of contract attributes ATTRS to the current block. */
1861 : :
1862 : : static void
1863 : 72 : emit_contract_conditions (tree attrs, tree_code code)
1864 : : {
1865 : 72 : if (!attrs) return;
1866 : 72 : gcc_assert (TREE_CODE (attrs) == TREE_LIST);
1867 : 72 : gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1868 : 207 : while (attrs)
1869 : : {
1870 : 135 : tree contract = CONTRACT_STATEMENT (attrs);
1871 : 135 : if (TREE_CODE (contract) == code)
1872 : 82 : attrs = emit_contract_attr (attrs);
1873 : : else
1874 : 53 : attrs = CONTRACT_CHAIN (attrs);
1875 : : }
1876 : : }
1877 : :
1878 : : /* Emit the statement for an assertion attribute. */
1879 : :
1880 : : void
1881 : 151 : emit_assertion (tree attr)
1882 : : {
1883 : 151 : emit_contract_attr (attr);
1884 : 151 : }
1885 : :
1886 : : /* Emit statements for precondition attributes. */
1887 : :
1888 : : static void
1889 : 39 : emit_preconditions (tree attr)
1890 : : {
1891 : 0 : return emit_contract_conditions (attr, PRECONDITION_STMT);
1892 : : }
1893 : :
1894 : : /* Emit statements for postcondition attributes. */
1895 : :
1896 : : static void
1897 : 33 : emit_postconditions (tree attr)
1898 : : {
1899 : 0 : return emit_contract_conditions (attr, POSTCONDITION_STMT);
1900 : : }
1901 : :
1902 : : /* We're compiling the pre/postcondition function CONDFN; remap any FN
1903 : : attributes that match CODE and emit them. */
1904 : :
1905 : : static void
1906 : 406 : remap_and_emit_conditions (tree fn, tree condfn, tree_code code)
1907 : : {
1908 : 406 : gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1909 : 1018 : for (tree attr = DECL_CONTRACTS (fn); attr;
1910 : 612 : attr = CONTRACT_CHAIN (attr))
1911 : : {
1912 : 612 : tree contract = CONTRACT_STATEMENT (attr);
1913 : 612 : if (TREE_CODE (contract) == code)
1914 : : {
1915 : 523 : contract = copy_node (contract);
1916 : 523 : remap_contract (fn, condfn, contract, /*duplicate_p=*/false);
1917 : 523 : emit_contract_statement (contract);
1918 : : }
1919 : : }
1920 : 406 : }
1921 : :
1922 : : /* Converts a contract condition to bool and ensures it has a locaiton. */
1923 : :
1924 : : tree
1925 : 889 : finish_contract_condition (cp_expr condition)
1926 : : {
1927 : : /* Ensure we have the condition location saved in case we later need to
1928 : : emit a conversion error during template instantiation and wouldn't
1929 : : otherwise have it. */
1930 : 889 : if (!CAN_HAVE_LOCATION_P (condition) || EXCEPTIONAL_CLASS_P (condition))
1931 : : {
1932 : 47 : condition = build1_loc (condition.get_location (), VIEW_CONVERT_EXPR,
1933 : 47 : TREE_TYPE (condition), condition);
1934 : 47 : EXPR_LOCATION_WRAPPER_P (condition) = 1;
1935 : : }
1936 : :
1937 : 889 : if (condition == error_mark_node || type_dependent_expression_p (condition))
1938 : : return condition;
1939 : :
1940 : 710 : return condition_conversion (condition);
1941 : : }
1942 : :
1943 : : void
1944 : 804892 : maybe_update_postconditions (tree fco)
1945 : : {
1946 : : /* Update any postconditions and the postcondition checking function
1947 : : as needed. If there are postconditions, we'll use those to rewrite
1948 : : return statements to check postconditions. */
1949 : 804892 : if (has_active_postconditions (fco))
1950 : : {
1951 : 7 : rebuild_postconditions (fco);
1952 : 7 : tree post = build_postcondition_function (fco);
1953 : 7 : set_postcondition_function (fco, post);
1954 : : }
1955 : 804892 : }
1956 : :
1957 : : /* Called on attribute lists that must not contain contracts. If any
1958 : : contracts are present, issue an error diagnostic and return true. */
1959 : :
1960 : : bool
1961 : 947729104 : diagnose_misapplied_contracts (tree attributes)
1962 : : {
1963 : 947729104 : if (attributes == NULL_TREE)
1964 : : return false;
1965 : :
1966 : 27644852 : tree contract_attr = find_contract (attributes);
1967 : 27644852 : if (!contract_attr)
1968 : : return false;
1969 : :
1970 : 17 : error_at (EXPR_LOCATION (CONTRACT_STATEMENT (contract_attr)),
1971 : : "contracts must appertain to a function type");
1972 : :
1973 : : /* Invalidate the contract so we don't treat it as valid later on. */
1974 : 17 : invalidate_contract (TREE_VALUE (TREE_VALUE (contract_attr)));
1975 : :
1976 : 17 : return true;
1977 : : }
1978 : :
1979 : : /* Build and return an argument list containing all the parameters of the
1980 : : (presumably guarded) FUNCTION_DECL FN. This can be used to forward all of
1981 : : FN's arguments to a function taking the same list of arguments -- namely
1982 : : the unchecked form of FN.
1983 : :
1984 : : We use CALL_FROM_THUNK_P instead of forward_parm for forwarding
1985 : : semantics. */
1986 : :
1987 : : static vec<tree, va_gc> *
1988 : 416 : build_arg_list (tree fn)
1989 : : {
1990 : 416 : vec<tree, va_gc> *args = make_tree_vector ();
1991 : 1028 : for (tree t = DECL_ARGUMENTS (fn); t; t = DECL_CHAIN (t))
1992 : 612 : vec_safe_push (args, t);
1993 : 416 : return args;
1994 : : }
1995 : :
1996 : : void
1997 : 143956593 : start_function_contracts (tree decl1)
1998 : : {
1999 : 143956593 : if (!handle_contracts_p (decl1))
2000 : : return;
2001 : :
2002 : : /* For cdtors, we evaluate the contracts check inline. */
2003 : 422 : if (!outline_contracts_p (decl1))
2004 : : return;
2005 : :
2006 : : /* Contracts may have just been added without a chance to parse them, though
2007 : : we still need the PRE_FN available to generate a call to it. */
2008 : 375 : if (!DECL_PRE_FN (decl1))
2009 : 375 : build_contract_function_decls (decl1);
2010 : :
2011 : : }
2012 : :
2013 : : /* If we have a precondition function and it's valid, call it. */
2014 : :
2015 : : static void
2016 : 342 : add_pre_condition_fn_call (tree fndecl)
2017 : : {
2018 : : /* If we're starting a guarded function with valid contracts, we need to
2019 : : insert a call to the pre function. */
2020 : 342 : gcc_checking_assert (DECL_PRE_FN (fndecl)
2021 : : && DECL_PRE_FN (fndecl) != error_mark_node);
2022 : :
2023 : 342 : releasing_vec args = build_arg_list (fndecl);
2024 : 342 : tree call = build_call_a (DECL_PRE_FN (fndecl), args->length (),
2025 : : args->address ());
2026 : 342 : CALL_FROM_THUNK_P (call) = true;
2027 : 342 : finish_expr_stmt (call);
2028 : 342 : }
2029 : :
2030 : : /* Build and add a call to the post-condition checking function, when that
2031 : : is in use. */
2032 : :
2033 : : static void
2034 : 74 : add_post_condition_fn_call (tree fndecl)
2035 : : {
2036 : 74 : gcc_checking_assert (DECL_POST_FN (fndecl)
2037 : : && DECL_POST_FN (fndecl) != error_mark_node);
2038 : :
2039 : 74 : releasing_vec args = build_arg_list (fndecl);
2040 : 74 : if (get_postcondition_result_parameter (fndecl))
2041 : 66 : vec_safe_push (args, DECL_RESULT (fndecl));
2042 : 74 : tree call = build_call_a (DECL_POST_FN (fndecl), args->length (),
2043 : : args->address ());
2044 : 74 : CALL_FROM_THUNK_P (call) = true;
2045 : 74 : finish_expr_stmt (call);
2046 : 74 : }
2047 : :
2048 : : /* Add a call or a direct evaluation of the pre checks. */
2049 : :
2050 : : static void
2051 : 381 : apply_preconditions (tree fndecl)
2052 : : {
2053 : 381 : if (outline_contracts_p (fndecl))
2054 : 342 : add_pre_condition_fn_call (fndecl);
2055 : : else
2056 : 39 : emit_preconditions (DECL_CONTRACTS (fndecl));
2057 : 381 : }
2058 : :
2059 : : /* Add a call or a direct evaluation of the post checks. */
2060 : :
2061 : : static void
2062 : 107 : apply_postconditions (tree fndecl)
2063 : : {
2064 : 107 : if (outline_contracts_p (fndecl))
2065 : 74 : add_post_condition_fn_call (fndecl);
2066 : : else
2067 : 33 : emit_postconditions (DECL_CONTRACTS (fndecl));
2068 : 107 : }
2069 : :
2070 : : /* Add contract handling to the function in FNDECL.
2071 : :
2072 : : When we have only pre-conditions, this simply prepends a call (or a direct
2073 : : evaluation, for cdtors) to the existing function body.
2074 : :
2075 : : When we have post conditions we build a try-finally block.
2076 : : If the function might throw then the handler in the try-finally is an
2077 : : EH_ELSE expression, where the post condition check is applied to the
2078 : : non-exceptional path, and an empty statement is added to the EH path. If
2079 : : the function has a non-throwing eh spec, then the handler is simply the
2080 : : post-condition checker. */
2081 : :
2082 : : void
2083 : 426 : maybe_apply_function_contracts (tree fndecl)
2084 : : {
2085 : 426 : if (!handle_contracts_p (fndecl))
2086 : : /* We did nothing and the original function body statement list will be
2087 : : popped by our caller. */
2088 : : return;
2089 : :
2090 : 422 : bool do_pre = has_active_preconditions (fndecl);
2091 : 422 : bool do_post = has_active_postconditions (fndecl);
2092 : : /* We should not have reached here with nothing to do... */
2093 : 422 : gcc_checking_assert (do_pre || do_post);
2094 : :
2095 : : /* This copies the approach used for function try blocks. */
2096 : 422 : tree fnbody = pop_stmt_list (DECL_SAVED_TREE (fndecl));
2097 : 422 : DECL_SAVED_TREE (fndecl) = push_stmt_list ();
2098 : 422 : tree compound_stmt = begin_compound_stmt (0);
2099 : 422 : current_binding_level->artificial = 1;
2100 : :
2101 : : /* Do not add locations for the synthesised code. */
2102 : 422 : location_t loc = UNKNOWN_LOCATION;
2103 : :
2104 : : /* For other cases, we call a function to process the check. */
2105 : :
2106 : : /* If we have a pre, but not a post, then just emit that and we are done. */
2107 : 422 : if (!do_post)
2108 : : {
2109 : 315 : apply_preconditions (fndecl);
2110 : 315 : add_stmt (fnbody);
2111 : 315 : finish_compound_stmt (compound_stmt);
2112 : 315 : return;
2113 : : }
2114 : :
2115 : 107 : if (do_pre)
2116 : : /* Add a precondition call, if we have one. */
2117 : 66 : apply_preconditions (fndecl);
2118 : 107 : tree try_fin = build_stmt (loc, TRY_FINALLY_EXPR, fnbody, NULL_TREE);
2119 : 107 : add_stmt (try_fin);
2120 : 107 : TREE_OPERAND (try_fin, 1) = push_stmt_list ();
2121 : : /* If we have exceptions, and a function that might throw, then add
2122 : : an EH_ELSE clause that allows the exception to propagate upwards
2123 : : without encountering the post-condition checks. */
2124 : 107 : if (flag_exceptions && !type_noexcept_p (TREE_TYPE (fndecl)))
2125 : : {
2126 : 98 : tree eh_else = build_stmt (loc, EH_ELSE_EXPR, NULL_TREE, NULL_TREE);
2127 : 98 : add_stmt (eh_else);
2128 : 98 : TREE_OPERAND (eh_else, 0) = push_stmt_list ();
2129 : 98 : apply_postconditions (fndecl);
2130 : 98 : TREE_OPERAND (eh_else, 0) = pop_stmt_list (TREE_OPERAND (eh_else, 0));
2131 : 98 : TREE_OPERAND (eh_else, 1) = build_empty_stmt (loc);
2132 : : }
2133 : : else
2134 : 9 : apply_postconditions (fndecl);
2135 : 107 : TREE_OPERAND (try_fin, 1) = pop_stmt_list (TREE_OPERAND (try_fin, 1));
2136 : 107 : finish_compound_stmt (compound_stmt);
2137 : : /* The DECL_SAVED_TREE stmt list will be popped by our caller. */
2138 : : }
2139 : :
2140 : : /* Finish up the pre & post function definitions for a guarded FNDECL,
2141 : : and compile those functions all the way to assembler language output. */
2142 : :
2143 : : void
2144 : 143956557 : finish_function_contracts (tree fndecl)
2145 : : {
2146 : 143956557 : if (!handle_contracts_p (fndecl)
2147 : 143956557 : || !outline_contracts_p (fndecl))
2148 : : return;
2149 : :
2150 : 898 : for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
2151 : : {
2152 : 533 : tree contract = CONTRACT_STATEMENT (ca);
2153 : 533 : if (!CONTRACT_CONDITION (contract)
2154 : 533 : || CONTRACT_CONDITION_DEFERRED_P (contract)
2155 : 1066 : || CONTRACT_CONDITION (contract) == error_mark_node)
2156 : : return;
2157 : : }
2158 : :
2159 : 365 : int flags = SF_DEFAULT | SF_PRE_PARSED;
2160 : :
2161 : : /* If either the pre or post functions are bad, don't bother emitting
2162 : : any contracts. The program is already ill-formed. */
2163 : 365 : tree pre = DECL_PRE_FN (fndecl);
2164 : 365 : tree post = DECL_POST_FN (fndecl);
2165 : 365 : if (pre == error_mark_node || post == error_mark_node)
2166 : : return;
2167 : :
2168 : 365 : if (pre && DECL_INITIAL (fndecl) != error_mark_node)
2169 : : {
2170 : 336 : DECL_PENDING_INLINE_P (pre) = false;
2171 : 336 : start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
2172 : 336 : remap_and_emit_conditions (fndecl, pre, PRECONDITION_STMT);
2173 : 336 : tree finished_pre = finish_function (false);
2174 : 336 : expand_or_defer_fn (finished_pre);
2175 : : }
2176 : :
2177 : 365 : if (post && DECL_INITIAL (fndecl) != error_mark_node)
2178 : : {
2179 : 70 : DECL_PENDING_INLINE_P (post) = false;
2180 : 70 : start_preparsed_function (post,
2181 : 70 : DECL_ATTRIBUTES (post),
2182 : : flags);
2183 : 70 : remap_and_emit_conditions (fndecl, post, POSTCONDITION_STMT);
2184 : 70 : if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post))))
2185 : 0 : finish_return_stmt (get_postcondition_result_parameter (fndecl));
2186 : :
2187 : 70 : tree finished_post = finish_function (false);
2188 : 70 : expand_or_defer_fn (finished_post);
2189 : : }
2190 : : }
2191 : :
2192 : :
2193 : : /* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
2194 : : guarded functions. */
2195 : :
2196 : : void
2197 : 18098444 : duplicate_contracts (tree newdecl, tree olddecl)
2198 : : {
2199 : 18098444 : if (TREE_CODE (newdecl) == TEMPLATE_DECL)
2200 : 3615915 : newdecl = DECL_TEMPLATE_RESULT (newdecl);
2201 : 18098444 : if (TREE_CODE (olddecl) == TEMPLATE_DECL)
2202 : 3615915 : olddecl = DECL_TEMPLATE_RESULT (olddecl);
2203 : :
2204 : : /* Compare contracts to see if they match. */
2205 : 18098444 : tree old_contracts = DECL_CONTRACTS (olddecl);
2206 : 18098444 : tree new_contracts = DECL_CONTRACTS (newdecl);
2207 : :
2208 : 18098444 : if (!old_contracts && !new_contracts)
2209 : : return;
2210 : :
2211 : 197 : location_t old_loc = DECL_SOURCE_LOCATION (olddecl);
2212 : 197 : location_t new_loc = DECL_SOURCE_LOCATION (newdecl);
2213 : :
2214 : : /* If both declarations specify contracts, ensure they match.
2215 : :
2216 : : TODO: This handles a potential error a little oddly. Consider:
2217 : :
2218 : : struct B {
2219 : : virtual void f(int n) [[pre: n == 0]];
2220 : : };
2221 : : struct D : B {
2222 : : void f(int n) override; // inherits contracts
2223 : : };
2224 : : void D::f(int n) [[pre: n == 0]] // OK
2225 : : { }
2226 : :
2227 : : It's okay because we're explicitly restating the inherited contract.
2228 : : Changing the precondition on the definition D::f causes match_contracts
2229 : : to complain about the mismatch.
2230 : :
2231 : : This would previously have been diagnosed as adding contracts to an
2232 : : override, but this seems like it should be well-formed. */
2233 : 197 : if (old_contracts && new_contracts)
2234 : : {
2235 : 65 : if (!match_contract_conditions (old_loc, old_contracts,
2236 : : new_loc, new_contracts,
2237 : : cmc_declaration))
2238 : : return;
2239 : 55 : if (DECL_UNIQUE_FRIEND_P (newdecl))
2240 : : /* Newdecl's contracts are still DEFERRED_PARSE, and we're about to
2241 : : collapse it into olddecl, so stash away olddecl's contracts for
2242 : : later comparison. */
2243 : 4 : defer_guarded_contract_match (olddecl, olddecl, old_contracts);
2244 : : }
2245 : :
2246 : : /* Handle cases where contracts are omitted in one or the other
2247 : : declaration. */
2248 : 187 : if (old_contracts)
2249 : : {
2250 : : /* Contracts have been previously specified by are no omitted. The
2251 : : new declaration inherits the existing contracts. */
2252 : 127 : if (!new_contracts)
2253 : 72 : copy_contract_attributes (newdecl, olddecl);
2254 : :
2255 : : /* In all cases, remove existing contracts from OLDDECL to prevent the
2256 : : attribute merging function from adding excess contracts. */
2257 : 127 : remove_contract_attributes (olddecl);
2258 : : }
2259 : 60 : else if (!old_contracts)
2260 : : {
2261 : : /* We are adding contracts to a declaration. */
2262 : 60 : if (new_contracts)
2263 : : {
2264 : : /* We can't add to a previously defined function. */
2265 : 60 : if (DECL_INITIAL (olddecl))
2266 : : {
2267 : 4 : auto_diagnostic_group d;
2268 : 4 : error_at (new_loc, "cannot add contracts after definition");
2269 : 4 : inform (DECL_SOURCE_LOCATION (olddecl), "original definition here");
2270 : 4 : return;
2271 : 4 : }
2272 : :
2273 : : /* We can't add to an unguarded virtual function declaration. */
2274 : 56 : if (DECL_VIRTUAL_P (olddecl) && new_contracts)
2275 : : {
2276 : 3 : auto_diagnostic_group d;
2277 : 3 : error_at (new_loc, "cannot add contracts to a virtual function");
2278 : 3 : inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here");
2279 : 3 : return;
2280 : 3 : }
2281 : :
2282 : : /* Depending on the "first declaration" rule, we may not be able
2283 : : to add contracts to a function after the fact. */
2284 : 53 : if (flag_contract_strict_declarations)
2285 : : {
2286 : 3 : warning_at (new_loc,
2287 : 3 : OPT_fcontract_strict_declarations_,
2288 : : "declaration adds contracts to %q#D",
2289 : : olddecl);
2290 : 3 : return;
2291 : : }
2292 : :
2293 : : /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to
2294 : : remap them because NEWDECL's parameters will replace those of
2295 : : OLDDECL. Remove the contracts from NEWDECL so they aren't
2296 : : cloned when merging. */
2297 : 50 : copy_contract_attributes (olddecl, newdecl);
2298 : 50 : remove_contract_attributes (newdecl);
2299 : : }
2300 : : }
2301 : : }
2302 : :
2303 : : /* Replace the any contract attributes on OVERRIDER with a copy where any
2304 : : references to BASEFN's PARM_DECLs have been rewritten to the corresponding
2305 : : PARM_DECL in OVERRIDER. */
2306 : :
2307 : : void
2308 : 12 : inherit_base_contracts (tree overrider, tree basefn)
2309 : : {
2310 : 12 : tree last = NULL_TREE, contract_attrs = NULL_TREE;
2311 : 12 : for (tree a = DECL_CONTRACTS (basefn);
2312 : 24 : a != NULL_TREE;
2313 : 12 : a = CONTRACT_CHAIN (a))
2314 : : {
2315 : 12 : tree c = copy_node (a);
2316 : 24 : TREE_VALUE (c) = build_tree_list (TREE_PURPOSE (TREE_VALUE (c)),
2317 : 12 : copy_node (CONTRACT_STATEMENT (c)));
2318 : :
2319 : 12 : tree src = basefn;
2320 : 12 : tree dst = overrider;
2321 : 12 : remap_contract (src, dst, CONTRACT_STATEMENT (c), /*duplicate_p=*/true);
2322 : :
2323 : 24 : CONTRACT_COMMENT (CONTRACT_STATEMENT (c)) =
2324 : 12 : copy_node (CONTRACT_COMMENT (CONTRACT_STATEMENT (c)));
2325 : :
2326 : 12 : chainon (last, c);
2327 : 12 : last = c;
2328 : 12 : if (!contract_attrs)
2329 : 12 : contract_attrs = c;
2330 : : }
2331 : :
2332 : 12 : set_decl_contracts (overrider, contract_attrs);
2333 : 12 : }
2334 : :
2335 : : #include "gt-cp-contracts.h"
|