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

source code of gcc/cp/contracts.cc