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