d: Merge upstream dmd, druntime c8ae4adb2e, phobos 792c8b7c1.
[official-gcc.git] / gcc / cp / contracts.cc
blob45f52b20392a87f0ad6bfe49fe15e59ac6b0918d
1 /* Definitions for C++ contract levels
2 Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 Contributed by Jeff Chapman II (jchapman@lock3software.com)
5 This file is part of GCC.
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.
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.
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/>. */
21 /* Design Notes
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.
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:
32 [[ pre: v > 0 ]]
34 is transformed into:
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
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>.
53 ??? is it worth factoring out the calls to handle_contract_violation and
54 terminate into a local function?
56 Assumed contracts use the same implementation as C++23 [[assume]].
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).
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).
70 Contracts on overrides must match those present on (all of) the overridee(s).
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.
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.
84 int fun(int v)
85 [[ pre: v > 0 ]]
86 [[ post r: r < 0 ]]
88 return -v;
91 The original decl is left alone and instead calls are generated to pre/post
92 functions within the body:
94 void fun.pre(int v)
96 [[ assert: v > 0 ]];
98 int fun.post(int v, int __r)
100 [[ assert: __r < 0 ]];
101 return __r;
103 int fun(int v)
105 fun.pre(v);
106 return fun.post(v, -v);
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.
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
118 int fun(int v)
120 [[ assert: v > 0 ]];
121 auto &&__r = -v;
122 goto out;
123 out:
124 [[ assert: __r < 0 ]];
125 return __r;
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.
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.
139 For cdtors a post contract is implemented using a CLEANUP_STMT.
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.
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. */
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"
165 const int max_custom_roles = 32;
166 static contract_role contract_build_roles[max_custom_roles] = {
169 bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = {
170 { 0, 0, 0, 0, 0, },
171 { 0, 1, 0, 0, 0, },
172 { 0, 1, 1, 1, 1, },
173 { 0, 1, 1, 1, 1, },
174 { 0, 1, 0, 0, 1, },
177 void
178 validate_contract_role (contract_role *role)
180 gcc_assert (role);
181 if (!unchecked_contract_p (role->axiom_semantic))
182 error ("axiom contract semantic must be %<assume%> or %<ignore%>");
184 if (!valid_configs[role->default_semantic][role->audit_semantic] )
185 warning (0, "the %<audit%> semantic should be at least as strong as "
186 "the %<default%> semantic");
189 contract_semantic
190 lookup_concrete_semantic (const char *name)
192 if (strcmp (name, "ignore") == 0)
193 return CCS_IGNORE;
194 if (strcmp (name, "assume") == 0)
195 return CCS_ASSUME;
196 if (strcmp (name, "check_never_continue") == 0
197 || strcmp (name, "never") == 0
198 || strcmp (name, "abort") == 0)
199 return CCS_NEVER;
200 if (strcmp (name, "check_maybe_continue") == 0
201 || strcmp (name, "maybe") == 0)
202 return CCS_MAYBE;
203 error ("'%s' is not a valid explicit concrete semantic", name);
204 return CCS_INVALID;
207 /* Compare role and name up to either the NUL terminator or the first
208 occurrence of colon. */
210 static bool
211 role_name_equal (const char *role, const char *name)
213 size_t role_len = strcspn (role, ":");
214 size_t name_len = strcspn (name, ":");
215 if (role_len != name_len)
216 return false;
217 return strncmp (role, name, role_len) == 0;
220 static bool
221 role_name_equal (contract_role *role, const char *name)
223 if (role->name == NULL)
224 return false;
225 return role_name_equal (role->name, name);
228 contract_role *
229 get_contract_role (const char *name)
231 for (int i = 0; i < max_custom_roles; ++i)
233 contract_role *potential = contract_build_roles + i;
234 if (role_name_equal (potential, name))
235 return potential;
237 if (role_name_equal (name, "default") || role_name_equal (name, "review"))
239 setup_default_contract_role (false);
240 return get_contract_role (name);
242 return NULL;
245 contract_role *
246 add_contract_role (const char *name,
247 contract_semantic des,
248 contract_semantic aus,
249 contract_semantic axs,
250 bool update)
252 for (int i = 0; i < max_custom_roles; ++i)
254 contract_role *potential = contract_build_roles + i;
255 if (potential->name != NULL
256 && !role_name_equal (potential, name))
257 continue;
258 if (potential->name != NULL && !update)
259 return potential;
260 potential->name = name;
261 potential->default_semantic = des;
262 potential->audit_semantic = aus;
263 potential->axiom_semantic = axs;
264 return potential;
266 return NULL;
269 enum contract_build_level { OFF, DEFAULT, AUDIT };
270 static bool flag_contract_continuation_mode = false;
271 static bool flag_contract_assumption_mode = true;
272 static int flag_contract_build_level = DEFAULT;
274 static bool contracts_p1332_default = false, contracts_p1332_review = false,
275 contracts_std = false, contracts_p1429 = false;
277 static contract_semantic
278 get_concrete_check ()
280 return flag_contract_continuation_mode ? CCS_MAYBE : CCS_NEVER;
283 static contract_semantic
284 get_concrete_axiom_semantic ()
286 return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE;
289 void
290 setup_default_contract_role (bool update)
292 contract_semantic check = get_concrete_check ();
293 contract_semantic axiom = get_concrete_axiom_semantic ();
294 switch (flag_contract_build_level)
296 case OFF:
297 add_contract_role ("default", CCS_IGNORE, CCS_IGNORE, axiom, update);
298 add_contract_role ("review", CCS_IGNORE, CCS_IGNORE, CCS_IGNORE, update);
299 break;
300 case DEFAULT:
301 add_contract_role ("default", check, CCS_IGNORE, axiom, update);
302 add_contract_role ("review", check, CCS_IGNORE, CCS_IGNORE, update);
303 break;
304 case AUDIT:
305 add_contract_role ("default", check, check, axiom, update);
306 add_contract_role ("review", check, check, CCS_IGNORE, update);
307 break;
311 contract_semantic
312 map_contract_semantic (const char *ident)
314 if (strcmp (ident, "ignore") == 0)
315 return CCS_IGNORE;
316 else if (strcmp (ident, "assume") == 0)
317 return CCS_ASSUME;
318 else if (strcmp (ident, "check_never_continue") == 0)
319 return CCS_NEVER;
320 else if (strcmp (ident, "check_maybe_continue") == 0)
321 return CCS_MAYBE;
322 return CCS_INVALID;
325 contract_level
326 map_contract_level (const char *ident)
328 if (strcmp (ident, "default") == 0)
329 return CONTRACT_DEFAULT;
330 else if (strcmp (ident, "audit") == 0)
331 return CONTRACT_AUDIT;
332 else if (strcmp (ident, "axiom") == 0)
333 return CONTRACT_AXIOM;
334 return CONTRACT_INVALID;
338 void
339 handle_OPT_fcontract_build_level_ (const char *arg)
341 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
343 error ("%<-fcontract-build-level=%> cannot be mixed with p1332/p1429");
344 return;
346 else
347 contracts_std = true;
349 if (strcmp (arg, "off") == 0)
350 flag_contract_build_level = OFF;
351 else if (strcmp (arg, "default") == 0)
352 flag_contract_build_level = DEFAULT;
353 else if (strcmp (arg, "audit") == 0)
354 flag_contract_build_level = AUDIT;
355 else
356 error ("%<-fcontract-build-level=%> must be off|default|audit");
358 setup_default_contract_role ();
361 void
362 handle_OPT_fcontract_assumption_mode_ (const char *arg)
364 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
366 error ("%<-fcontract-assumption-mode=%> cannot be mixed with p1332/p1429");
367 return;
369 else
370 contracts_std = true;
372 if (strcmp (arg, "on") == 0)
373 flag_contract_assumption_mode = true;
374 else if (strcmp (arg, "off") == 0)
375 flag_contract_assumption_mode = false;
376 else
377 error ("%<-fcontract-assumption-mode=%> must be %<on%> or %<off%>");
379 setup_default_contract_role ();
382 void
383 handle_OPT_fcontract_continuation_mode_ (const char *arg)
385 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
387 error ("%<-fcontract-continuation-mode=%> cannot be mixed with p1332/p1429");
388 return;
390 else
391 contracts_std = true;
393 if (strcmp (arg, "on") == 0)
394 flag_contract_continuation_mode = true;
395 else if (strcmp (arg, "off") == 0)
396 flag_contract_continuation_mode = false;
397 else
398 error ("%<-fcontract-continuation-mode=%> must be %<on%> or %<off%>");
400 setup_default_contract_role ();
403 void
404 handle_OPT_fcontract_role_ (const char *arg)
406 const char *name = arg;
407 const char *vals = strchr (name, ':');
408 if (vals == NULL)
410 error ("%<-fcontract-role=%> must be in the form role:semantics");
411 return;
414 contract_semantic dess = CCS_INVALID, auss = CCS_INVALID, axss = CCS_INVALID;
415 char *des = NULL, *aus = NULL, *axs = NULL;
416 des = xstrdup (vals + 1);
418 aus = strchr (des, ',');
419 if (aus == NULL)
421 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
422 goto validate;
424 *aus = '\0'; // null terminate des
425 aus = aus + 1; // move past null
427 axs = strchr (aus, ',');
428 if (axs == NULL)
430 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
431 goto validate;
433 *axs = '\0'; // null terminate aus
434 axs = axs + 1; // move past null
436 dess = lookup_concrete_semantic (des);
437 auss = lookup_concrete_semantic (aus);
438 axss = lookup_concrete_semantic (axs);
439 validate:
440 free (des);
441 if (dess == CCS_INVALID || auss == CCS_INVALID || axss == CCS_INVALID)
442 return;
444 bool is_defalult_role = role_name_equal (name, "default");
445 bool is_review_role = role_name_equal (name, "review");
446 bool is_std_role = is_defalult_role || is_review_role;
447 if ((contracts_std && is_std_role) || (contracts_p1429 && is_defalult_role))
449 error ("%<-fcontract-role=%> cannot be mixed with std/p1429 contract flags");
450 return;
452 else if (is_std_role)
454 contracts_p1332_default |= is_defalult_role;
455 contracts_p1332_review |= is_review_role;
458 contract_role *role = add_contract_role (name, dess, auss, axss);
460 if (role == NULL)
462 // TODO: not enough space?
463 error ("%<-fcontract-level=%> too many custom roles");
464 return;
466 else
467 validate_contract_role (role);
470 void
471 handle_OPT_fcontract_semantic_ (const char *arg)
473 if (!strchr (arg, ':'))
475 error ("%<-fcontract-semantic=%> must be in the form level:semantic");
476 return;
479 if (contracts_std || contracts_p1332_default)
481 error ("%<-fcontract-semantic=%> cannot be mixed with std/p1332 contract flags");
482 return;
484 contracts_p1429 = true;
486 contract_role *role = get_contract_role ("default");
487 if (!role)
489 error ("%<-fcontract-semantic=%> cannot find default role");
490 return;
493 const char *semantic = strchr (arg, ':') + 1;
494 contract_semantic sem = lookup_concrete_semantic (semantic);
495 if (sem == CCS_INVALID)
496 return;
498 if (strncmp ("default:", arg, 8) == 0)
499 role->default_semantic = sem;
500 else if (strncmp ("audit:", arg, 6) == 0)
501 role->audit_semantic = sem;
502 else if (strncmp ("axiom:", arg, 6) == 0)
503 role->axiom_semantic = sem;
504 else
505 error ("%<-fcontract-semantic=%> level must be default, audit, or axiom");
506 validate_contract_role (role);
509 /* Convert a contract CONFIG into a contract_mode. */
511 static contract_mode
512 contract_config_to_mode (tree config)
514 if (config == NULL_TREE)
515 return contract_mode (CONTRACT_DEFAULT, get_default_contract_role ());
517 /* TREE_LIST has TREE_VALUE is a level and TREE_PURPOSE is role. */
518 if (TREE_CODE (config) == TREE_LIST)
520 contract_role *role = NULL;
521 if (TREE_PURPOSE (config))
522 role = get_contract_role (IDENTIFIER_POINTER (TREE_PURPOSE (config)));
523 if (!role)
524 role = get_default_contract_role ();
526 contract_level level =
527 map_contract_level (IDENTIFIER_POINTER (TREE_VALUE (config)));
528 return contract_mode (level, role);
531 /* Literal semantic. */
532 gcc_assert (TREE_CODE (config) == IDENTIFIER_NODE);
533 contract_semantic semantic =
534 map_contract_semantic (IDENTIFIER_POINTER (config));
535 return contract_mode (semantic);
538 /* Convert a contract's config into a concrete semantic using the current
539 contract semantic mapping. */
541 static contract_semantic
542 compute_concrete_semantic (tree contract)
544 contract_mode mode = contract_config_to_mode (CONTRACT_MODE (contract));
545 /* Compute the concrete semantic for the contract. */
546 if (!flag_contract_mode)
547 /* If contracts are off, treat all contracts as ignore. */
548 return CCS_IGNORE;
549 else if (mode.kind == contract_mode::cm_invalid)
550 return CCS_INVALID;
551 else if (mode.kind == contract_mode::cm_explicit)
552 return mode.get_semantic ();
553 else
555 gcc_assert (mode.get_role ());
556 gcc_assert (mode.get_level () != CONTRACT_INVALID);
557 contract_level level = mode.get_level ();
558 contract_role *role = mode.get_role ();
559 if (level == CONTRACT_DEFAULT)
560 return role->default_semantic;
561 else if (level == CONTRACT_AUDIT)
562 return role->audit_semantic;
563 else if (level == CONTRACT_AXIOM)
564 return role->axiom_semantic;
566 gcc_assert (false);
569 /* Return true if any contract in CONTRACT_ATTRs is not yet parsed. */
571 bool
572 contract_any_deferred_p (tree contract_attr)
574 for (; contract_attr; contract_attr = CONTRACT_CHAIN (contract_attr))
575 if (CONTRACT_CONDITION_DEFERRED_P (CONTRACT_STATEMENT (contract_attr)))
576 return true;
577 return false;
580 /* Returns true if all attributes are contracts. */
582 bool
583 all_attributes_are_contracts_p (tree attributes)
585 for (; attributes; attributes = TREE_CHAIN (attributes))
586 if (!cxx_contract_attribute_p (attributes))
587 return false;
588 return true;
591 /* Mark most of a contract as being invalid. */
593 tree
594 invalidate_contract (tree t)
596 if (TREE_CODE (t) == POSTCONDITION_STMT && POSTCONDITION_IDENTIFIER (t))
597 POSTCONDITION_IDENTIFIER (t) = error_mark_node;
598 CONTRACT_CONDITION (t) = error_mark_node;
599 CONTRACT_COMMENT (t) = error_mark_node;
600 return t;
603 /* Returns an invented parameter declration of the form 'TYPE ID' for the
604 purpose of parsing the postcondition.
606 We use a PARM_DECL instead of a VAR_DECL so that tsubst forces a lookup
607 in local specializations when we instantiate these things later. */
609 tree
610 make_postcondition_variable (cp_expr id, tree type)
612 if (id == error_mark_node)
613 return id;
615 tree decl = build_lang_decl (PARM_DECL, id, type);
616 DECL_ARTIFICIAL (decl) = true;
617 DECL_SOURCE_LOCATION (decl) = id.get_location ();
619 pushdecl (decl);
620 return decl;
623 /* As above, except that the type is unknown. */
625 tree
626 make_postcondition_variable (cp_expr id)
628 return make_postcondition_variable (id, make_auto ());
631 /* Check that the TYPE is valid for a named postcondition variable. Emit a
632 diagnostic if it is not. Returns TRUE if the result is OK and false
633 otherwise. */
635 bool
636 check_postcondition_result (tree decl, tree type, location_t loc)
638 if (VOID_TYPE_P (type))
640 const char* what;
641 if (DECL_CONSTRUCTOR_P (decl))
642 what = "constructor";
643 else if (DECL_DESTRUCTOR_P (decl))
644 what = "destructor";
645 else
646 what = "function";
647 error_at (loc, "%s does not return a value to test", what);
648 return false;
651 return true;
654 /* Instantiate each postcondition with the return type to finalize the
655 attribute. */
657 void
658 rebuild_postconditions (tree decl)
660 tree type = TREE_TYPE (TREE_TYPE (decl));
661 tree attributes = DECL_CONTRACTS (decl);
663 for (; attributes ; attributes = TREE_CHAIN (attributes))
665 if (!cxx_contract_attribute_p (attributes))
666 continue;
667 tree contract = TREE_VALUE (TREE_VALUE (attributes));
668 if (TREE_CODE (contract) != POSTCONDITION_STMT)
669 continue;
670 tree condition = CONTRACT_CONDITION (contract);
672 /* If any conditions are deferred, they're all deferred. Note that
673 we don't have to instantiate postconditions in that case because
674 the type is available through the declaration. */
675 if (TREE_CODE (condition) == DEFERRED_PARSE)
676 return;
678 tree oldvar = POSTCONDITION_IDENTIFIER (contract);
679 if (!oldvar)
680 continue;
682 /* Always update the context of the result variable so that it can
683 be remapped by remap_contracts. */
684 DECL_CONTEXT (oldvar) = decl;
686 /* If the return type is undeduced, defer until later. */
687 if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
688 return;
690 /* Check the postcondition variable. */
691 location_t loc = DECL_SOURCE_LOCATION (oldvar);
692 if (!check_postcondition_result (decl, type, loc))
694 invalidate_contract (contract);
695 continue;
698 /* "Instantiate" the result variable using the known type. Also update
699 the context so the inliner will actually remap this the parameter when
700 generating contract checks. */
701 tree newvar = copy_node (oldvar);
702 TREE_TYPE (newvar) = type;
704 /* Make parameters and result available for substitution. */
705 local_specialization_stack stack (lss_copy);
706 for (tree t = DECL_ARGUMENTS (decl); t != NULL_TREE; t = TREE_CHAIN (t))
707 register_local_identity (t);
708 register_local_specialization (newvar, oldvar);
710 ++processing_contract_condition;
711 condition = tsubst_expr (condition, make_tree_vec (0),
712 tf_warning_or_error, decl);
713 --processing_contract_condition;
715 /* Update the contract condition and result. */
716 POSTCONDITION_IDENTIFIER (contract) = newvar;
717 CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
721 static tree
722 build_comment (cp_expr condition)
724 /* Try to get the actual source text for the condition; if that fails pretty
725 print the resulting tree. */
726 char *str = get_source_text_between (condition.get_start (),
727 condition.get_finish ());
728 if (!str)
730 /* FIXME cases where we end up here
731 #line macro usage (oof)
732 contracts10.C
733 contracts11.C */
734 const char *str = expr_to_string (condition);
735 return build_string_literal (strlen (str) + 1, str);
738 tree t = build_string_literal (strlen (str) + 1, str);
739 free (str);
740 return t;
743 /* Build a contract statement. */
745 tree
746 grok_contract (tree attribute, tree mode, tree result, cp_expr condition,
747 location_t loc)
749 tree_code code;
750 if (is_attribute_p ("assert", attribute))
751 code = ASSERTION_STMT;
752 else if (is_attribute_p ("pre", attribute))
753 code = PRECONDITION_STMT;
754 else if (is_attribute_p ("post", attribute))
755 code = POSTCONDITION_STMT;
756 else
757 gcc_unreachable ();
759 /* Build the contract. The condition is added later. In the case that
760 the contract is deferred, result an plain identifier, not a result
761 variable. */
762 tree contract;
763 tree type = void_type_node;
764 if (code != POSTCONDITION_STMT)
765 contract = build3_loc (loc, code, type, mode, NULL_TREE, NULL_TREE);
766 else
767 contract = build4_loc (loc, code, type, mode, NULL_TREE, NULL_TREE, result);
769 /* Determine the concrete semantic. */
770 set_contract_semantic (contract, compute_concrete_semantic (contract));
772 /* If the contract is deferred, don't do anything with the condition. */
773 if (TREE_CODE (condition) == DEFERRED_PARSE)
775 CONTRACT_CONDITION (contract) = condition;
776 return contract;
779 /* Generate the comment from the original condition. */
780 CONTRACT_COMMENT (contract) = build_comment (condition);
782 /* The condition is converted to bool. */
783 condition = finish_contract_condition (condition);
784 CONTRACT_CONDITION (contract) = condition;
786 return contract;
789 /* Build the contract attribute specifier where IDENTIFIER is one of 'pre',
790 'post' or 'assert' and CONTRACT is the underlying statement. */
791 tree
792 finish_contract_attribute (tree identifier, tree contract)
794 if (contract == error_mark_node)
795 return error_mark_node;
797 tree attribute = build_tree_list (build_tree_list (NULL_TREE, identifier),
798 build_tree_list (NULL_TREE, contract));
801 /* Mark the attribute as dependent if the condition is dependent.
803 TODO: I'm not sure this is strictly necessary. It's going to be marked as
804 such by a subroutine of cplus_decl_attributes. */
805 tree condition = CONTRACT_CONDITION (contract);
806 if (TREE_CODE (condition) == DEFERRED_PARSE
807 || value_dependent_expression_p (condition))
808 ATTR_IS_DEPENDENT (attribute) = true;
810 return attribute;
813 /* Update condition of a late-parsed contract and postcondition variable,
814 if any. */
816 void
817 update_late_contract (tree contract, tree result, tree condition)
819 if (TREE_CODE (contract) == POSTCONDITION_STMT)
820 POSTCONDITION_IDENTIFIER (contract) = result;
822 /* Generate the comment from the original condition. */
823 CONTRACT_COMMENT (contract) = build_comment (condition);
825 /* The condition is converted to bool. */
826 condition = finish_contract_condition (condition);
827 CONTRACT_CONDITION (contract) = condition;
830 /* Return TRUE iff ATTR has been parsed by the front-end as a c++2a contract
831 attribute. */
833 bool
834 cxx_contract_attribute_p (const_tree attr)
836 if (attr == NULL_TREE
837 || TREE_CODE (attr) != TREE_LIST)
838 return false;
840 if (!TREE_PURPOSE (attr) || TREE_CODE (TREE_PURPOSE (attr)) != TREE_LIST)
841 return false;
842 if (!TREE_VALUE (attr) || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST)
843 return false;
844 if (!TREE_VALUE (TREE_VALUE (attr)))
845 return false;
847 return (TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == PRECONDITION_STMT
848 || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == POSTCONDITION_STMT
849 || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == ASSERTION_STMT);
852 /* True if ATTR is an assertion. */
854 bool
855 cp_contract_assertion_p (const_tree attr)
857 /* This is only an assertion if it is a valid cxx contract attribute and the
858 statement is an ASSERTION_STMT. */
859 return cxx_contract_attribute_p (attr)
860 && TREE_CODE (CONTRACT_STATEMENT (attr)) == ASSERTION_STMT;
863 /* Remove all c++2a style contract attributes from the DECL_ATTRIBUTEs of the
864 FUNCTION_DECL FNDECL. */
866 void
867 remove_contract_attributes (tree fndecl)
869 tree list = NULL_TREE;
870 for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
871 if (!cxx_contract_attribute_p (p))
872 list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list);
873 DECL_ATTRIBUTES (fndecl) = nreverse (list);
876 static tree find_first_non_contract (tree attributes)
878 tree head = attributes;
879 tree p = find_contract (attributes);
881 /* There are no contracts. */
882 if (!p)
883 return head;
885 /* There are leading contracts. */
886 if (p == head)
888 while (cxx_contract_attribute_p (p))
889 p = TREE_CHAIN (p);
890 head = p;
893 return head;
896 /* Remove contracts from ATTRIBUTES. */
898 tree splice_out_contracts (tree attributes)
900 tree head = find_first_non_contract (attributes);
901 if (!head)
902 return NULL_TREE;
904 /* Splice out remaining contracts. */
905 tree p = TREE_CHAIN (head);
906 tree q = head;
907 while (p)
909 if (cxx_contract_attribute_p (p))
911 /* Skip a sequence of contracts and then link q to the next
912 non-contract attribute. */
914 p = TREE_CHAIN (p);
915 while (cxx_contract_attribute_p (p));
916 TREE_CHAIN (q) = p;
918 else
919 p = TREE_CHAIN (p);
922 return head;
925 /* Copy contract attributes from NEWDECL onto the attribute list of OLDDECL. */
927 void copy_contract_attributes (tree olddecl, tree newdecl)
929 tree attrs = NULL_TREE;
930 for (tree c = DECL_CONTRACTS (newdecl); c; c = TREE_CHAIN (c))
932 if (!cxx_contract_attribute_p (c))
933 continue;
934 attrs = tree_cons (TREE_PURPOSE (c), TREE_VALUE (c), attrs);
936 attrs = chainon (DECL_ATTRIBUTES (olddecl), nreverse (attrs));
937 DECL_ATTRIBUTES (olddecl) = attrs;
939 /* And update DECL_CONTEXT of the postcondition result identifier. */
940 rebuild_postconditions (olddecl);
943 /* Returns the parameter corresponding to the return value of a guarded
944 function D. Returns NULL_TREE if D has no postconditions or is void. */
946 static tree
947 get_postcondition_result_parameter (tree d)
949 if (!d || d == error_mark_node)
950 return NULL_TREE;
952 if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (d))))
953 return NULL_TREE;
955 tree post = DECL_POST_FN (d);
956 if (!post || post == error_mark_node)
957 return NULL_TREE;
959 for (tree arg = DECL_ARGUMENTS (post); arg; arg = TREE_CHAIN (arg))
960 if (!TREE_CHAIN (arg))
961 return arg;
963 return NULL_TREE;
967 /* For use with the tree inliner. This preserves non-mapped local variables,
968 such as postcondition result variables, during remapping. */
970 static tree
971 retain_decl (tree decl, copy_body_data *)
973 return decl;
976 /* Rewrite the condition of contract in place, so that references to SRC's
977 parameters are updated to refer to DST's parameters. The postcondition
978 result variable is left unchanged.
980 This, along with remap_contracts, are subroutines of duplicate_decls.
981 When declarations are merged, we sometimes need to update contracts to
982 refer to new parameters.
984 If DUPLICATE_P is true, this is called by duplicate_decls to rewrite contacts
985 in terms of a new set of parameters. In this case, we can retain local
986 variables appearing in the contract because the contract is not being
987 prepared for insertion into a new function. Importantly, this preserves the
988 references to postcondition results, which are not replaced during merging.
990 If false, we're preparing to emit the contract condition into the body
991 of a new function, so we need to make copies of all local variables
992 appearing in the contract (e.g., if it includes a lambda expression). Note
993 that in this case, postcondition results are mapped to the last parameter
994 of DST.
996 This is also used to reuse a parent type's contracts on virtual methods. */
998 static void
999 remap_contract (tree src, tree dst, tree contract, bool duplicate_p)
1001 copy_body_data id;
1002 hash_map<tree, tree> decl_map;
1004 memset (&id, 0, sizeof (id));
1005 id.src_fn = src;
1006 id.dst_fn = dst;
1007 id.src_cfun = DECL_STRUCT_FUNCTION (src);
1008 id.decl_map = &decl_map;
1010 /* If we're merging contracts, don't copy local variables. */
1011 id.copy_decl = duplicate_p ? retain_decl : copy_decl_no_change;
1013 id.transform_call_graph_edges = CB_CGE_DUPLICATE;
1014 id.transform_new_cfg = false;
1015 id.transform_return_to_modify = false;
1016 id.transform_parameter = true;
1018 /* Make sure not to unshare trees behind the front-end's back
1019 since front-end specific mechanisms may rely on sharing. */
1020 id.regimplify = false;
1021 id.do_not_unshare = true;
1022 id.do_not_fold = true;
1024 /* We're not inside any EH region. */
1025 id.eh_lp_nr = 0;
1027 bool do_remap = false;
1029 /* Insert parameter remappings. */
1030 if (TREE_CODE (src) == FUNCTION_DECL)
1031 src = DECL_ARGUMENTS (src);
1032 if (TREE_CODE (dst) == FUNCTION_DECL)
1033 dst = DECL_ARGUMENTS (dst);
1035 for (tree sp = src, dp = dst;
1036 sp || dp;
1037 sp = DECL_CHAIN (sp), dp = DECL_CHAIN (dp))
1039 if (!sp && dp
1040 && TREE_CODE (contract) == POSTCONDITION_STMT
1041 && DECL_CHAIN (dp) == NULL_TREE)
1043 gcc_assert (!duplicate_p);
1044 if (tree result = POSTCONDITION_IDENTIFIER (contract))
1046 gcc_assert (DECL_P (result));
1047 insert_decl_map (&id, result, dp);
1048 do_remap = true;
1050 break;
1052 gcc_assert (sp && dp);
1054 if (sp == dp)
1055 continue;
1057 insert_decl_map (&id, sp, dp);
1058 do_remap = true;
1060 if (!do_remap)
1061 return;
1063 walk_tree (&CONTRACT_CONDITION (contract), copy_tree_body_r, &id, NULL);
1066 /* Rewrite any references to SRC's PARM_DECLs to the corresponding PARM_DECL in
1067 DST in all of the contract attributes in CONTRACTS by calling remap_contract
1068 on each.
1070 This is used for two purposes: to rewrite contract attributes during
1071 duplicate_decls, and to prepare contracts for emission into a function's
1072 respective precondition and postcondition functions. DUPLICATE_P is used
1073 to determine the context in which this function is called. See above for
1074 the behavior described by this flag. */
1076 void
1077 remap_contracts (tree src, tree dst, tree contracts, bool duplicate_p)
1079 for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
1081 if (!cxx_contract_attribute_p (attr))
1082 continue;
1083 tree contract = CONTRACT_STATEMENT (attr);
1084 if (TREE_CODE (CONTRACT_CONDITION (contract)) != DEFERRED_PARSE)
1085 remap_contract (src, dst, contract, duplicate_p);
1089 /* Helper to replace references to dummy this parameters with references to
1090 the first argument of the FUNCTION_DECL DATA. */
1092 static tree
1093 remap_dummy_this_1 (tree *tp, int *, void *data)
1095 if (!is_this_parameter (*tp))
1096 return NULL_TREE;
1097 tree fn = (tree)data;
1098 *tp = DECL_ARGUMENTS (fn);
1099 return NULL_TREE;
1102 /* Replace all references to dummy this parameters in EXPR with references to
1103 the first argument of the FUNCTION_DECL FN. */
1105 static void
1106 remap_dummy_this (tree fn, tree *expr)
1108 walk_tree (expr, remap_dummy_this_1, fn, NULL);
1111 /* Contract matching. */
1113 /* True if the contract is valid. */
1115 static bool
1116 contract_valid_p (tree contract)
1118 return CONTRACT_CONDITION (contract) != error_mark_node;
1121 /* True if the contract attribute is valid. */
1123 static bool
1124 contract_attribute_valid_p (tree attribute)
1126 return contract_valid_p (TREE_VALUE (TREE_VALUE (attribute)));
1129 /* Compare the contract conditions of OLD_ATTR and NEW_ATTR. Returns false
1130 if the conditions are equivalent, and true otherwise. */
1132 static bool
1133 check_for_mismatched_contracts (tree old_attr, tree new_attr,
1134 contract_matching_context ctx)
1136 tree old_contract = CONTRACT_STATEMENT (old_attr);
1137 tree new_contract = CONTRACT_STATEMENT (new_attr);
1139 /* Different kinds of contracts do not match. */
1140 if (TREE_CODE (old_contract) != TREE_CODE (new_contract))
1142 auto_diagnostic_group d;
1143 error_at (EXPR_LOCATION (new_contract),
1144 ctx == cmc_declaration
1145 ? "mismatched contract attribute in declaration"
1146 : "mismatched contract attribute in override");
1147 inform (EXPR_LOCATION (old_contract), "previous contract here");
1148 return true;
1151 /* A deferred contract tentatively matches. */
1152 if (CONTRACT_CONDITION_DEFERRED_P (new_contract))
1153 return false;
1155 /* Compare the conditions of the contracts. We fold immediately to avoid
1156 issues comparing contracts on overrides that use parameters -- see
1157 contracts-pre3. */
1158 tree t1 = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
1159 tree t2 = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
1161 /* Compare the contracts. The fold doesn't eliminate conversions to members.
1162 Set the comparing_override_contracts flag to ensure that references
1163 through 'this' are equal if they designate the same member, regardless of
1164 the path those members. */
1165 bool saved_comparing_contracts = comparing_override_contracts;
1166 comparing_override_contracts = (ctx == cmc_override);
1167 bool matching_p = cp_tree_equal (t1, t2);
1168 comparing_override_contracts = saved_comparing_contracts;
1170 if (!matching_p)
1172 auto_diagnostic_group d;
1173 error_at (EXPR_LOCATION (CONTRACT_CONDITION (new_contract)),
1174 ctx == cmc_declaration
1175 ? "mismatched contract condition in declaration"
1176 : "mismatched contract condition in override");
1177 inform (EXPR_LOCATION (CONTRACT_CONDITION (old_contract)),
1178 "previous contract here");
1179 return true;
1182 return false;
1185 /* Compare the contract attributes of OLDDECL and NEWDECL. Returns true
1186 if the contracts match, and false if they differ. */
1188 bool
1189 match_contract_conditions (location_t oldloc, tree old_attrs,
1190 location_t newloc, tree new_attrs,
1191 contract_matching_context ctx)
1193 /* Contracts only match if they are both specified. */
1194 if (!old_attrs || !new_attrs)
1195 return true;
1197 /* Compare each contract in turn. */
1198 while (old_attrs && new_attrs)
1200 /* If either contract is ill-formed, skip the rest of the comparison,
1201 since we've already diagnosed an error. */
1202 if (!contract_attribute_valid_p (new_attrs)
1203 || !contract_attribute_valid_p (old_attrs))
1204 return false;
1206 if (check_for_mismatched_contracts (old_attrs, new_attrs, ctx))
1207 return false;
1208 old_attrs = CONTRACT_CHAIN (old_attrs);
1209 new_attrs = CONTRACT_CHAIN (new_attrs);
1212 /* If we didn't compare all attributes, the contracts don't match. */
1213 if (old_attrs || new_attrs)
1215 auto_diagnostic_group d;
1216 error_at (newloc,
1217 ctx == cmc_declaration
1218 ? "declaration has a different number of contracts than "
1219 "previously declared"
1220 : "override has a different number of contracts than "
1221 "previously declared");
1222 inform (oldloc,
1223 new_attrs
1224 ? "original declaration with fewer contracts here"
1225 : "original declaration with more contracts here");
1226 return false;
1229 return true;
1232 /* Deferred contract mapping.
1234 This is used to compare late-parsed contracts on overrides with their
1235 base class functions.
1237 TODO: It seems like this could be replaced by a simple list that maps from
1238 overrides to their base functions. It's not clear that we really need
1239 a map to a function + a list of contracts. */
1241 /* Map from FNDECL to a tree list of contracts that have not been matched or
1242 diagnosed yet. The TREE_PURPOSE is the basefn we're overriding, and the
1243 TREE_VALUE is the list of contract attrs for BASEFN. */
1245 static hash_map<tree_decl_hash, tree> pending_guarded_decls;
1247 void
1248 defer_guarded_contract_match (tree fndecl, tree fn, tree contracts)
1250 if (!pending_guarded_decls.get (fndecl))
1252 pending_guarded_decls.put (fndecl, build_tree_list (fn, contracts));
1253 return;
1255 for (tree pending = *pending_guarded_decls.get (fndecl);
1256 pending;
1257 pending = TREE_CHAIN (pending))
1259 if (TREE_VALUE (pending) == contracts)
1260 return;
1261 if (TREE_CHAIN (pending) == NULL_TREE)
1262 TREE_CHAIN (pending) = build_tree_list (fn, contracts);
1266 /* If the FUNCTION_DECL DECL has any contracts that had their matching
1267 deferred earlier, do that checking now. */
1269 void
1270 match_deferred_contracts (tree decl)
1272 tree *tp = pending_guarded_decls.get (decl);
1273 if (!tp)
1274 return;
1276 gcc_assert(!contract_any_deferred_p (DECL_CONTRACTS (decl)));
1278 processing_template_decl_sentinel ptds;
1279 processing_template_decl = uses_template_parms (decl);
1281 /* Do late contract matching. */
1282 for (tree pending = *tp; pending; pending = TREE_CHAIN (pending))
1284 tree new_contracts = TREE_VALUE (pending);
1285 location_t new_loc = CONTRACT_SOURCE_LOCATION (new_contracts);
1286 tree old_contracts = DECL_CONTRACTS (decl);
1287 location_t old_loc = CONTRACT_SOURCE_LOCATION (old_contracts);
1288 tree base = TREE_PURPOSE (pending);
1289 match_contract_conditions (new_loc, new_contracts,
1290 old_loc, old_contracts,
1291 base ? cmc_override : cmc_declaration);
1294 /* Clear out deferred match list so we don't check it twice. */
1295 pending_guarded_decls.remove (decl);
1298 /* Map from FUNCTION_DECL to a FUNCTION_DECL for either the PRE_FN or POST_FN.
1299 These are used to parse contract conditions and are called inside the body
1300 of the guarded function. */
1301 static GTY(()) hash_map<tree, tree> *decl_pre_fn;
1302 static GTY(()) hash_map<tree, tree> *decl_post_fn;
1304 /* Returns the precondition funtion for D, or null if not set. */
1306 tree
1307 get_precondition_function (tree d)
1309 hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1310 tree *result = decl_pre_fn->get (d);
1311 return result ? *result : NULL_TREE;
1314 /* Returns the postcondition funtion for D, or null if not set. */
1316 tree
1317 get_postcondition_function (tree d)
1319 hash_map_maybe_create<hm_ggc> (decl_post_fn);
1320 tree *result = decl_post_fn->get (d);
1321 return result ? *result : NULL_TREE;
1324 /* Makes PRE the precondition function for D. */
1326 void
1327 set_precondition_function (tree d, tree pre)
1329 gcc_assert (pre);
1330 hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1331 gcc_assert (!decl_pre_fn->get (d));
1332 decl_pre_fn->put (d, pre);
1335 /* Makes POST the postcondition function for D. */
1337 void
1338 set_postcondition_function (tree d, tree post)
1340 gcc_assert (post);
1341 hash_map_maybe_create<hm_ggc> (decl_post_fn);
1342 gcc_assert (!decl_post_fn->get (d));
1343 decl_post_fn->put (d, post);
1346 /* Set the PRE and POST functions for D. Note that PRE and POST can be
1347 null in this case. If so the functions are not recorded. */
1349 void
1350 set_contract_functions (tree d, tree pre, tree post)
1352 if (pre)
1353 set_precondition_function (d, pre);
1354 if (post)
1355 set_postcondition_function (d, post);
1358 /* Return a copy of the FUNCTION_DECL IDECL with its own unshared
1359 PARM_DECL and DECL_ATTRIBUTEs. */
1361 static tree
1362 copy_fn_decl (tree idecl)
1364 tree decl = copy_decl (idecl);
1365 DECL_ATTRIBUTES (decl) = copy_list (DECL_ATTRIBUTES (idecl));
1367 if (DECL_RESULT (idecl))
1369 DECL_RESULT (decl) = copy_decl (DECL_RESULT (idecl));
1370 DECL_CONTEXT (DECL_RESULT (decl)) = decl;
1372 if (!DECL_ARGUMENTS (idecl) || VOID_TYPE_P (DECL_ARGUMENTS (idecl)))
1373 return decl;
1375 tree last = DECL_ARGUMENTS (decl) = copy_decl (DECL_ARGUMENTS (decl));
1376 DECL_CONTEXT (last) = decl;
1377 for (tree p = TREE_CHAIN (DECL_ARGUMENTS (idecl)); p; p = TREE_CHAIN (p))
1379 if (VOID_TYPE_P (p))
1381 TREE_CHAIN (last) = void_list_node;
1382 break;
1384 last = TREE_CHAIN (last) = copy_decl (p);
1385 DECL_CONTEXT (last) = decl;
1387 return decl;
1390 /* Build a declaration for the pre- or postcondition of a guarded FNDECL. */
1392 static tree
1393 build_contract_condition_function (tree fndecl, bool pre)
1395 if (TREE_TYPE (fndecl) == error_mark_node)
1396 return error_mark_node;
1397 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
1398 && !TYPE_METHOD_BASETYPE (TREE_TYPE (fndecl)))
1399 return error_mark_node;
1401 /* Create and rename the unchecked function and give an internal name. */
1402 tree fn = copy_fn_decl (fndecl);
1403 DECL_RESULT (fn) = NULL_TREE;
1404 tree value_type = pre ? void_type_node : TREE_TYPE (TREE_TYPE (fn));
1406 /* Don't propagate declaration attributes to the checking function,
1407 including the original contracts. */
1408 DECL_ATTRIBUTES (fn) = NULL_TREE;
1410 tree arg_types = NULL_TREE;
1411 tree *last = &arg_types;
1413 /* FIXME will later optimizations delete unused args to prevent extra arg
1414 passing? do we care? */
1415 tree class_type = NULL_TREE;
1416 for (tree arg_type = TYPE_ARG_TYPES (TREE_TYPE (fn));
1417 arg_type && arg_type != void_list_node;
1418 arg_type = TREE_CHAIN (arg_type))
1420 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
1421 && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type)
1423 class_type = TREE_TYPE (TREE_VALUE (arg_type));
1424 continue;
1426 *last = build_tree_list (TREE_PURPOSE (arg_type), TREE_VALUE (arg_type));
1427 last = &TREE_CHAIN (*last);
1430 if (pre || VOID_TYPE_P (value_type))
1431 *last = void_list_node;
1432 else
1434 tree name = get_identifier ("__r");
1435 tree parm = build_lang_decl (PARM_DECL, name, value_type);
1436 DECL_CONTEXT (parm) = fn;
1437 DECL_ARTIFICIAL (parm) = true;
1438 DECL_ARGUMENTS (fn) = chainon (DECL_ARGUMENTS (fn), parm);
1440 *last = build_tree_list (NULL_TREE, value_type);
1441 TREE_CHAIN (*last) = void_list_node;
1443 if (aggregate_value_p (value_type, fndecl))
1444 /* If FNDECL returns in memory, don't return the value from the
1445 postcondition. */
1446 value_type = void_type_node;
1449 TREE_TYPE (fn) = build_function_type (value_type, arg_types);
1450 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
1451 TREE_TYPE (fn) = build_method_type (class_type, TREE_TYPE (fn));
1453 DECL_NAME (fn) = copy_node (DECL_NAME (fn));
1454 DECL_INITIAL (fn) = error_mark_node;
1455 DECL_ABSTRACT_ORIGIN (fn) = fndecl;
1457 IDENTIFIER_VIRTUAL_P (DECL_NAME (fn)) = false;
1458 DECL_VIRTUAL_P (fn) = false;
1460 /* Make these functions internal if we can, i.e. if the guarded function is
1461 not vague linkage, or if we can put them in a comdat group with the
1462 guarded function. */
1463 if (!DECL_WEAK (fndecl) || HAVE_COMDAT_GROUP)
1465 TREE_PUBLIC (fn) = false;
1466 DECL_EXTERNAL (fn) = false;
1467 DECL_WEAK (fn) = false;
1468 DECL_COMDAT (fn) = false;
1470 /* We haven't set the comdat group on the guarded function yet, we'll add
1471 this to the same group in comdat_linkage later. */
1472 gcc_assert (!DECL_ONE_ONLY (fndecl));
1474 DECL_INTERFACE_KNOWN (fn) = true;
1477 DECL_ARTIFICIAL (fn) = true;
1479 /* Update various inline related declaration properties. */
1480 //DECL_DECLARED_INLINE_P (fn) = true;
1481 DECL_DISREGARD_INLINE_LIMITS (fn) = true;
1482 TREE_NO_WARNING (fn) = 1;
1484 return fn;
1487 /* Return true if CONTRACT is checked or assumed under the current build
1488 configuration. */
1490 bool
1491 contract_active_p (tree contract)
1493 return get_contract_semantic (contract) != CCS_IGNORE;
1496 static bool
1497 has_active_contract_condition (tree d, tree_code c)
1499 for (tree as = DECL_CONTRACTS (d) ; as != NULL_TREE; as = TREE_CHAIN (as))
1501 tree contract = TREE_VALUE (TREE_VALUE (as));
1502 if (TREE_CODE (contract) == c && contract_active_p (contract))
1503 return true;
1505 return false;
1508 /* True if D has any checked or assumed preconditions. */
1510 static bool
1511 has_active_preconditions (tree d)
1513 return has_active_contract_condition (d, PRECONDITION_STMT);
1516 /* True if D has any checked or assumed postconditions. */
1518 static bool
1519 has_active_postconditions (tree d)
1521 return has_active_contract_condition (d, POSTCONDITION_STMT);
1524 /* Return true if any contract in the CONTRACT list is checked or assumed
1525 under the current build configuration. */
1527 bool
1528 contract_any_active_p (tree contract)
1530 for (; contract != NULL_TREE; contract = CONTRACT_CHAIN (contract))
1531 if (contract_active_p (TREE_VALUE (TREE_VALUE (contract))))
1532 return true;
1533 return false;
1536 /* Do we need to mess with contracts for DECL1? */
1538 static bool
1539 handle_contracts_p (tree decl1)
1541 return (flag_contracts
1542 && !processing_template_decl
1543 && DECL_ABSTRACT_ORIGIN (decl1) == NULL_TREE
1544 && contract_any_active_p (DECL_CONTRACTS (decl1)));
1547 /* Should we break out DECL1's pre/post contracts into separate functions?
1548 FIXME I'd like this to default to 0, but that will need an overhaul to the
1549 return identifier handling to just refer to the RESULT_DECL. */
1551 static bool
1552 outline_contracts_p (tree decl1)
1554 return (!DECL_CONSTRUCTOR_P (decl1)
1555 && !DECL_DESTRUCTOR_P (decl1));
1558 /* Build the precondition checking function for D. */
1560 static tree
1561 build_precondition_function (tree d)
1563 if (!has_active_preconditions (d))
1564 return NULL_TREE;
1566 return build_contract_condition_function (d, /*pre=*/true);
1569 /* Build the postcondition checking function for D. If the return
1570 type is undeduced, don't build the function yet. We do that in
1571 apply_deduced_return_type. */
1573 static tree
1574 build_postcondition_function (tree d)
1576 if (!has_active_postconditions (d))
1577 return NULL_TREE;
1579 tree type = TREE_TYPE (TREE_TYPE (d));
1580 if (is_auto (type))
1581 return NULL_TREE;
1583 return build_contract_condition_function (d, /*pre=*/false);
1586 static void
1587 build_contract_function_decls (tree d)
1589 /* Constructors and destructors have their contracts inserted inline. */
1590 if (!outline_contracts_p (d))
1591 return;
1593 /* Build the pre/post functions (or not). */
1594 tree pre = build_precondition_function (d);
1595 tree post = build_postcondition_function (d);
1596 set_contract_functions (d, pre, post);
1599 static const char *
1600 get_contract_level_name (tree contract)
1602 if (CONTRACT_LITERAL_MODE_P (contract))
1603 return "";
1604 if (tree mode = CONTRACT_MODE (contract))
1605 if (tree level = TREE_VALUE (mode))
1606 return IDENTIFIER_POINTER (level);
1607 return "default";
1610 static const char *
1611 get_contract_role_name (tree contract)
1613 if (CONTRACT_LITERAL_MODE_P (contract))
1614 return "";
1615 if (tree mode = CONTRACT_MODE (contract))
1616 if (tree role = TREE_PURPOSE (mode))
1617 return IDENTIFIER_POINTER (role);
1618 return "default";
1621 /* Build a layout-compatible internal version of std::contract_violation. */
1623 static tree
1624 get_pseudo_contract_violation_type ()
1626 if (!pseudo_contract_violation_type)
1628 /* Must match <contract>:
1629 class contract_violation {
1630 const char* _M_file;
1631 const char* _M_function;
1632 const char* _M_comment;
1633 const char* _M_level;
1634 const char* _M_role;
1635 uint_least32_t _M_line;
1636 signed char _M_continue;
1637 If this changes, also update the initializer in
1638 build_contract_violation. */
1639 const tree types[] = { const_string_type_node,
1640 const_string_type_node,
1641 const_string_type_node,
1642 const_string_type_node,
1643 const_string_type_node,
1644 uint_least32_type_node,
1645 signed_char_type_node };
1646 tree fields = NULL_TREE;
1647 for (tree type : types)
1649 /* finish_builtin_struct wants fieldss chained in reverse. */
1650 tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1651 NULL_TREE, type);
1652 DECL_CHAIN (next) = fields;
1653 fields = next;
1655 iloc_sentinel ils (input_location);
1656 input_location = BUILTINS_LOCATION;
1657 pseudo_contract_violation_type = make_class_type (RECORD_TYPE);
1658 finish_builtin_struct (pseudo_contract_violation_type,
1659 "__pseudo_contract_violation",
1660 fields, NULL_TREE);
1661 CLASSTYPE_AS_BASE (pseudo_contract_violation_type)
1662 = pseudo_contract_violation_type;
1663 DECL_CONTEXT (TYPE_NAME (pseudo_contract_violation_type))
1664 = FROB_CONTEXT (global_namespace);
1665 TREE_PUBLIC (TYPE_NAME (pseudo_contract_violation_type)) = true;
1666 CLASSTYPE_LITERAL_P (pseudo_contract_violation_type) = true;
1667 CLASSTYPE_LAZY_COPY_CTOR (pseudo_contract_violation_type) = true;
1668 xref_basetypes (pseudo_contract_violation_type, /*bases=*/NULL_TREE);
1669 pseudo_contract_violation_type
1670 = cp_build_qualified_type (pseudo_contract_violation_type,
1671 TYPE_QUAL_CONST);
1673 return pseudo_contract_violation_type;
1676 /* Return a VAR_DECL to pass to handle_contract_violation. */
1678 static tree
1679 build_contract_violation (tree contract, contract_continuation cmode)
1681 expanded_location loc = expand_location (EXPR_LOCATION (contract));
1682 const char *function = fndecl_name (DECL_ORIGIN (current_function_decl));
1683 const char *level = get_contract_level_name (contract);
1684 const char *role = get_contract_role_name (contract);
1686 /* Must match the type layout in get_pseudo_contract_violation_type. */
1687 tree ctor = build_constructor_va
1688 (init_list_type_node, 7,
1689 NULL_TREE, build_string_literal (loc.file),
1690 NULL_TREE, build_string_literal (function),
1691 NULL_TREE, CONTRACT_COMMENT (contract),
1692 NULL_TREE, build_string_literal (level),
1693 NULL_TREE, build_string_literal (role),
1694 NULL_TREE, build_int_cst (uint_least32_type_node, loc.line),
1695 NULL_TREE, build_int_cst (signed_char_type_node, cmode));
1697 ctor = finish_compound_literal (get_pseudo_contract_violation_type (),
1698 ctor, tf_none);
1699 protected_set_expr_location (ctor, EXPR_LOCATION (contract));
1700 return ctor;
1703 /* Return handle_contract_violation(), declaring it if needed. */
1705 static tree
1706 declare_handle_contract_violation ()
1708 tree fnname = get_identifier ("handle_contract_violation");
1709 tree viol_name = get_identifier ("contract_violation");
1710 tree l = lookup_qualified_name (global_namespace, fnname,
1711 LOOK_want::HIDDEN_FRIEND);
1712 for (tree f: lkp_range (l))
1713 if (TREE_CODE (f) == FUNCTION_DECL)
1715 tree parms = TYPE_ARG_TYPES (TREE_TYPE (f));
1716 if (remaining_arguments (parms) != 1)
1717 continue;
1718 tree parmtype = non_reference (TREE_VALUE (parms));
1719 if (CLASS_TYPE_P (parmtype)
1720 && TYPE_IDENTIFIER (parmtype) == viol_name)
1721 return f;
1724 tree id_exp = get_identifier ("experimental");
1725 tree ns_exp = lookup_qualified_name (std_node, id_exp);
1727 tree violation = error_mark_node;
1728 if (TREE_CODE (ns_exp) == NAMESPACE_DECL)
1729 violation = lookup_qualified_name (ns_exp, viol_name,
1730 LOOK_want::TYPE
1731 |LOOK_want::HIDDEN_FRIEND);
1733 if (TREE_CODE (violation) == TYPE_DECL)
1734 violation = TREE_TYPE (violation);
1735 else
1737 push_nested_namespace (std_node);
1738 push_namespace (id_exp, /*inline*/false);
1739 violation = make_class_type (RECORD_TYPE);
1740 create_implicit_typedef (viol_name, violation);
1741 DECL_SOURCE_LOCATION (TYPE_NAME (violation)) = BUILTINS_LOCATION;
1742 DECL_CONTEXT (TYPE_NAME (violation)) = current_namespace;
1743 pushdecl_namespace_level (TYPE_NAME (violation), /*hidden*/true);
1744 pop_namespace ();
1745 pop_nested_namespace (std_node);
1748 tree argtype = cp_build_qualified_type (violation, TYPE_QUAL_CONST);
1749 argtype = cp_build_reference_type (argtype, /*rval*/false);
1750 tree fntype = build_function_type_list (void_type_node, argtype, NULL_TREE);
1752 push_nested_namespace (global_namespace);
1753 tree fn = build_cp_library_fn_ptr ("handle_contract_violation", fntype,
1754 ECF_COLD);
1755 pushdecl_namespace_level (fn, /*hiding*/true);
1756 pop_nested_namespace (global_namespace);
1758 return fn;
1761 /* Build the call to handle_contract_violation for CONTRACT. */
1763 static void
1764 build_contract_handler_call (tree contract,
1765 contract_continuation cmode)
1767 tree violation = build_contract_violation (contract, cmode);
1768 tree violation_fn = declare_handle_contract_violation ();
1769 tree call = build_call_n (violation_fn, 1, build_address (violation));
1770 finish_expr_stmt (call);
1773 /* Generate the code that checks or assumes a contract, but do not attach
1774 it to the current context. This is called during genericization. */
1776 tree
1777 build_contract_check (tree contract)
1779 contract_semantic semantic = get_contract_semantic (contract);
1780 if (semantic == CCS_INVALID)
1781 return NULL_TREE;
1783 /* Ignored contracts are never checked or assumed. */
1784 if (semantic == CCS_IGNORE)
1785 return void_node;
1787 remap_dummy_this (current_function_decl, &CONTRACT_CONDITION (contract));
1788 tree condition = CONTRACT_CONDITION (contract);
1789 if (condition == error_mark_node)
1790 return NULL_TREE;
1792 location_t loc = EXPR_LOCATION (contract);
1794 if (semantic == CCS_ASSUME)
1795 return build_assume_call (loc, condition);
1797 tree if_stmt = begin_if_stmt ();
1798 tree cond = build_x_unary_op (loc,
1799 TRUTH_NOT_EXPR,
1800 condition, NULL_TREE,
1801 tf_warning_or_error);
1802 finish_if_stmt_cond (cond, if_stmt);
1804 /* Get the continuation mode. */
1805 contract_continuation cmode;
1806 switch (semantic)
1808 case CCS_NEVER: cmode = NEVER_CONTINUE; break;
1809 case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
1810 default: gcc_unreachable ();
1813 build_contract_handler_call (contract, cmode);
1814 if (cmode == NEVER_CONTINUE)
1815 finish_expr_stmt (build_call_a (terminate_fn, 0, nullptr));
1817 finish_then_clause (if_stmt);
1818 tree scope = IF_SCOPE (if_stmt);
1819 IF_SCOPE (if_stmt) = NULL;
1820 return do_poplevel (scope);
1823 /* Add the contract statement CONTRACT to the current block if valid. */
1825 static void
1826 emit_contract_statement (tree contract)
1828 /* Only add valid contracts. */
1829 if (get_contract_semantic (contract) != CCS_INVALID
1830 && CONTRACT_CONDITION (contract) != error_mark_node)
1831 add_stmt (contract);
1834 /* Generate the statement for the given contract attribute by adding the
1835 statement to the current block. Returns the next contract in the chain. */
1837 static tree
1838 emit_contract_attr (tree attr)
1840 gcc_assert (TREE_CODE (attr) == TREE_LIST);
1842 emit_contract_statement (CONTRACT_STATEMENT (attr));
1844 return CONTRACT_CHAIN (attr);
1847 /* Add the statements of contract attributes ATTRS to the current block. */
1849 static void
1850 emit_contract_conditions (tree attrs, tree_code code)
1852 if (!attrs) return;
1853 gcc_assert (TREE_CODE (attrs) == TREE_LIST);
1854 gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1855 while (attrs)
1857 tree contract = CONTRACT_STATEMENT (attrs);
1858 if (TREE_CODE (contract) == code)
1859 attrs = emit_contract_attr (attrs);
1860 else
1861 attrs = CONTRACT_CHAIN (attrs);
1865 /* Emit the statement for an assertion attribute. */
1867 void
1868 emit_assertion (tree attr)
1870 emit_contract_attr (attr);
1873 /* Emit statements for precondition attributes. */
1875 static void
1876 emit_preconditions (tree attr)
1878 return emit_contract_conditions (attr, PRECONDITION_STMT);
1881 /* Emit statements for postcondition attributes. */
1883 static void
1884 emit_postconditions_cleanup (tree contracts)
1886 tree stmts = push_stmt_list ();
1887 emit_contract_conditions (contracts, POSTCONDITION_STMT);
1888 stmts = pop_stmt_list (stmts);
1889 push_cleanup (NULL_TREE, stmts, /*eh_only*/false);
1892 /* We're compiling the pre/postcondition function CONDFN; remap any FN
1893 attributes that match CODE and emit them. */
1895 static void
1896 remap_and_emit_conditions (tree fn, tree condfn, tree_code code)
1898 gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1899 for (tree attr = DECL_CONTRACTS (fn); attr;
1900 attr = CONTRACT_CHAIN (attr))
1902 tree contract = CONTRACT_STATEMENT (attr);
1903 if (TREE_CODE (contract) == code)
1905 contract = copy_node (contract);
1906 remap_contract (fn, condfn, contract, /*duplicate_p=*/false);
1907 emit_contract_statement (contract);
1912 /* Converts a contract condition to bool and ensures it has a locaiton. */
1914 tree
1915 finish_contract_condition (cp_expr condition)
1917 /* Ensure we have the condition location saved in case we later need to
1918 emit a conversion error during template instantiation and wouldn't
1919 otherwise have it. */
1920 if (!CAN_HAVE_LOCATION_P (condition) || EXCEPTIONAL_CLASS_P (condition))
1922 condition = build1_loc (condition.get_location (), VIEW_CONVERT_EXPR,
1923 TREE_TYPE (condition), condition);
1924 EXPR_LOCATION_WRAPPER_P (condition) = 1;
1927 if (condition == error_mark_node || type_dependent_expression_p (condition))
1928 return condition;
1930 return condition_conversion (condition);
1933 void
1934 maybe_update_postconditions (tree fco)
1936 /* Update any postconditions and the postcondition checking function
1937 as needed. If there are postconditions, we'll use those to rewrite
1938 return statements to check postconditions. */
1939 if (has_active_postconditions (fco))
1941 rebuild_postconditions (fco);
1942 tree post = build_postcondition_function (fco);
1943 set_postcondition_function (fco, post);
1947 /* Called on attribute lists that must not contain contracts. If any
1948 contracts are present, issue an error diagnostic and return true. */
1950 bool
1951 diagnose_misapplied_contracts (tree attributes)
1953 if (attributes == NULL_TREE)
1954 return false;
1956 tree contract_attr = find_contract (attributes);
1957 if (!contract_attr)
1958 return false;
1960 error_at (EXPR_LOCATION (CONTRACT_STATEMENT (contract_attr)),
1961 "contracts must appertain to a function type");
1963 /* Invalidate the contract so we don't treat it as valid later on. */
1964 invalidate_contract (TREE_VALUE (TREE_VALUE (contract_attr)));
1966 return true;
1969 /* Build and return an argument list containing all the parameters of the
1970 (presumably guarded) FUNCTION_DECL FN. This can be used to forward all of
1971 FN's arguments to a function taking the same list of arguments -- namely
1972 the unchecked form of FN.
1974 We use CALL_FROM_THUNK_P instead of forward_parm for forwarding
1975 semantics. */
1977 static vec<tree, va_gc> *
1978 build_arg_list (tree fn)
1980 vec<tree, va_gc> *args = make_tree_vector ();
1981 for (tree t = DECL_ARGUMENTS (fn); t; t = DECL_CHAIN (t))
1982 vec_safe_push (args, t);
1983 return args;
1986 void
1987 start_function_contracts (tree decl1)
1989 if (!handle_contracts_p (decl1))
1990 return;
1992 if (!outline_contracts_p (decl1))
1994 emit_preconditions (DECL_CONTRACTS (current_function_decl));
1995 emit_postconditions_cleanup (DECL_CONTRACTS (current_function_decl));
1996 return;
1999 /* Contracts may have just been added without a chance to parse them, though
2000 we still need the PRE_FN available to generate a call to it. */
2001 if (!DECL_PRE_FN (decl1))
2002 build_contract_function_decls (decl1);
2004 /* If we're starting a guarded function with valid contracts, we need to
2005 insert a call to the pre function. */
2006 if (DECL_PRE_FN (decl1)
2007 && DECL_PRE_FN (decl1) != error_mark_node)
2009 releasing_vec args = build_arg_list (decl1);
2010 tree call = build_call_a (DECL_PRE_FN (decl1),
2011 args->length (),
2012 args->address ());
2013 CALL_FROM_THUNK_P (call) = true;
2014 finish_expr_stmt (call);
2018 /* Finish up the pre & post function definitions for a guarded FNDECL,
2019 and compile those functions all the way to assembler language output. */
2021 void
2022 finish_function_contracts (tree fndecl)
2024 if (!handle_contracts_p (fndecl)
2025 || !outline_contracts_p (fndecl))
2026 return;
2028 for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
2030 tree contract = CONTRACT_STATEMENT (ca);
2031 if (!CONTRACT_CONDITION (contract)
2032 || CONTRACT_CONDITION_DEFERRED_P (contract)
2033 || CONTRACT_CONDITION (contract) == error_mark_node)
2034 return;
2037 int flags = SF_DEFAULT | SF_PRE_PARSED;
2039 /* If either the pre or post functions are bad, don't bother emitting
2040 any contracts. The program is already ill-formed. */
2041 tree pre = DECL_PRE_FN (fndecl);
2042 tree post = DECL_POST_FN (fndecl);
2043 if (pre == error_mark_node || post == error_mark_node)
2044 return;
2046 if (pre && DECL_INITIAL (fndecl) != error_mark_node)
2048 DECL_PENDING_INLINE_P (pre) = false;
2049 start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
2050 remap_and_emit_conditions (fndecl, pre, PRECONDITION_STMT);
2051 tree finished_pre = finish_function (false);
2052 expand_or_defer_fn (finished_pre);
2055 if (post && DECL_INITIAL (fndecl) != error_mark_node)
2057 DECL_PENDING_INLINE_P (post) = false;
2058 start_preparsed_function (post,
2059 DECL_ATTRIBUTES (post),
2060 flags);
2061 remap_and_emit_conditions (fndecl, post, POSTCONDITION_STMT);
2062 if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post))))
2063 finish_return_stmt (get_postcondition_result_parameter (fndecl));
2065 tree finished_post = finish_function (false);
2066 expand_or_defer_fn (finished_post);
2070 /* Rewrite the expression of a returned expression so that it invokes the
2071 postcondition function as needed. */
2073 tree
2074 apply_postcondition_to_return (tree expr)
2076 tree fn = current_function_decl;
2077 tree post = DECL_POST_FN (fn);
2078 if (!post)
2079 return NULL_TREE;
2081 /* If FN returns in memory, POST has a void return type and we call it when
2082 EXPR is DECL_RESULT (fn). If FN returns a scalar, POST has the same
2083 return type and we call it when EXPR is the value being returned. */
2084 if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post)))
2085 != (expr == DECL_RESULT (fn)))
2086 return NULL_TREE;
2088 releasing_vec args = build_arg_list (fn);
2089 if (get_postcondition_result_parameter (fn))
2090 vec_safe_push (args, expr);
2091 tree call = build_call_a (post,
2092 args->length (),
2093 args->address ());
2094 CALL_FROM_THUNK_P (call) = true;
2096 return call;
2099 /* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
2100 guarded functions. */
2102 void
2103 duplicate_contracts (tree newdecl, tree olddecl)
2105 if (TREE_CODE (newdecl) == TEMPLATE_DECL)
2106 newdecl = DECL_TEMPLATE_RESULT (newdecl);
2107 if (TREE_CODE (olddecl) == TEMPLATE_DECL)
2108 olddecl = DECL_TEMPLATE_RESULT (olddecl);
2110 /* Compare contracts to see if they match. */
2111 tree old_contracts = DECL_CONTRACTS (olddecl);
2112 tree new_contracts = DECL_CONTRACTS (newdecl);
2114 if (!old_contracts && !new_contracts)
2115 return;
2117 location_t old_loc = DECL_SOURCE_LOCATION (olddecl);
2118 location_t new_loc = DECL_SOURCE_LOCATION (newdecl);
2120 /* If both declarations specify contracts, ensure they match.
2122 TODO: This handles a potential error a little oddly. Consider:
2124 struct B {
2125 virtual void f(int n) [[pre: n == 0]];
2127 struct D : B {
2128 void f(int n) override; // inherits contracts
2130 void D::f(int n) [[pre: n == 0]] // OK
2133 It's okay because we're explicitly restating the inherited contract.
2134 Changing the precondition on the definition D::f causes match_contracts
2135 to complain about the mismatch.
2137 This would previously have been diagnosed as adding contracts to an
2138 override, but this seems like it should be well-formed. */
2139 if (old_contracts && new_contracts)
2141 if (!match_contract_conditions (old_loc, old_contracts,
2142 new_loc, new_contracts,
2143 cmc_declaration))
2144 return;
2145 if (DECL_UNIQUE_FRIEND_P (newdecl))
2146 /* Newdecl's contracts are still DEFERRED_PARSE, and we're about to
2147 collapse it into olddecl, so stash away olddecl's contracts for
2148 later comparison. */
2149 defer_guarded_contract_match (olddecl, olddecl, old_contracts);
2152 /* Handle cases where contracts are omitted in one or the other
2153 declaration. */
2154 if (old_contracts)
2156 /* Contracts have been previously specified by are no omitted. The
2157 new declaration inherits the existing contracts. */
2158 if (!new_contracts)
2159 copy_contract_attributes (newdecl, olddecl);
2161 /* In all cases, remove existing contracts from OLDDECL to prevent the
2162 attribute merging function from adding excess contracts. */
2163 remove_contract_attributes (olddecl);
2165 else if (!old_contracts)
2167 /* We are adding contracts to a declaration. */
2168 if (new_contracts)
2170 /* We can't add to a previously defined function. */
2171 if (DECL_INITIAL (olddecl))
2173 auto_diagnostic_group d;
2174 error_at (new_loc, "cannot add contracts after definition");
2175 inform (DECL_SOURCE_LOCATION (olddecl), "original definition here");
2176 return;
2179 /* We can't add to an unguarded virtual function declaration. */
2180 if (DECL_VIRTUAL_P (olddecl) && new_contracts)
2182 auto_diagnostic_group d;
2183 error_at (new_loc, "cannot add contracts to a virtual function");
2184 inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here");
2185 return;
2188 /* Depending on the "first declaration" rule, we may not be able
2189 to add contracts to a function after the fact. */
2190 if (flag_contract_strict_declarations)
2192 warning_at (new_loc,
2193 OPT_fcontract_strict_declarations_,
2194 "declaration adds contracts to %q#D",
2195 olddecl);
2196 return;
2199 /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to
2200 remap them because NEWDECL's parameters will replace those of
2201 OLDDECL. Remove the contracts from NEWDECL so they aren't
2202 cloned when merging. */
2203 copy_contract_attributes (olddecl, newdecl);
2204 remove_contract_attributes (newdecl);
2209 /* Replace the any contract attributes on OVERRIDER with a copy where any
2210 references to BASEFN's PARM_DECLs have been rewritten to the corresponding
2211 PARM_DECL in OVERRIDER. */
2213 void
2214 inherit_base_contracts (tree overrider, tree basefn)
2216 tree last = NULL_TREE, contract_attrs = NULL_TREE;
2217 for (tree a = DECL_CONTRACTS (basefn);
2218 a != NULL_TREE;
2219 a = CONTRACT_CHAIN (a))
2221 tree c = copy_node (a);
2222 TREE_VALUE (c) = build_tree_list (TREE_PURPOSE (TREE_VALUE (c)),
2223 copy_node (CONTRACT_STATEMENT (c)));
2225 tree src = basefn;
2226 tree dst = overrider;
2227 remap_contract (src, dst, CONTRACT_STATEMENT (c), /*duplicate_p=*/true);
2229 CONTRACT_COMMENT (CONTRACT_STATEMENT (c)) =
2230 copy_node (CONTRACT_COMMENT (CONTRACT_STATEMENT (c)));
2232 chainon (last, c);
2233 last = c;
2234 if (!contract_attrs)
2235 contract_attrs = c;
2238 set_decl_contracts (overrider, contract_attrs);
2241 #include "gt-cp-contracts.h"