Require target lra in gcc.c-torture/compile/asmgoto-6.c
[official-gcc.git] / gcc / cp / contracts.cc
blob9d1cb558f4f72ebe78c3420667e7d33e664be595
1 /* Definitions for C++ contract levels
2 Copyright (C) 2020-2023 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"
164 #include "intl.h"
166 const int max_custom_roles = 32;
167 static contract_role contract_build_roles[max_custom_roles] = {
170 bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = {
171 { 0, 0, 0, 0, 0, },
172 { 0, 1, 0, 0, 0, },
173 { 0, 1, 1, 1, 1, },
174 { 0, 1, 1, 1, 1, },
175 { 0, 1, 0, 0, 1, },
178 void
179 validate_contract_role (contract_role *role)
181 gcc_assert (role);
182 if (!unchecked_contract_p (role->axiom_semantic))
183 error ("axiom contract semantic must be %<assume%> or %<ignore%>");
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");
190 contract_semantic
191 lookup_concrete_semantic (const char *name)
193 if (strcmp (name, "ignore") == 0)
194 return CCS_IGNORE;
195 if (strcmp (name, "assume") == 0)
196 return CCS_ASSUME;
197 if (strcmp (name, "check_never_continue") == 0
198 || strcmp (name, "never") == 0
199 || strcmp (name, "abort") == 0)
200 return CCS_NEVER;
201 if (strcmp (name, "check_maybe_continue") == 0
202 || strcmp (name, "maybe") == 0)
203 return CCS_MAYBE;
204 error ("'%s' is not a valid explicit concrete semantic", name);
205 return CCS_INVALID;
208 /* Compare role and name up to either the NUL terminator or the first
209 occurrence of colon. */
211 static bool
212 role_name_equal (const char *role, const char *name)
214 size_t role_len = strcspn (role, ":");
215 size_t name_len = strcspn (name, ":");
216 if (role_len != name_len)
217 return false;
218 return strncmp (role, name, role_len) == 0;
221 static bool
222 role_name_equal (contract_role *role, const char *name)
224 if (role->name == NULL)
225 return false;
226 return role_name_equal (role->name, name);
229 contract_role *
230 get_contract_role (const char *name)
232 for (int i = 0; i < max_custom_roles; ++i)
234 contract_role *potential = contract_build_roles + i;
235 if (role_name_equal (potential, name))
236 return potential;
238 if (role_name_equal (name, "default") || role_name_equal (name, "review"))
240 setup_default_contract_role (false);
241 return get_contract_role (name);
243 return NULL;
246 contract_role *
247 add_contract_role (const char *name,
248 contract_semantic des,
249 contract_semantic aus,
250 contract_semantic axs,
251 bool update)
253 for (int i = 0; i < max_custom_roles; ++i)
255 contract_role *potential = contract_build_roles + i;
256 if (potential->name != NULL
257 && !role_name_equal (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;
267 return NULL;
270 enum contract_build_level { OFF, DEFAULT, AUDIT };
271 static bool flag_contract_continuation_mode = false;
272 static bool flag_contract_assumption_mode = true;
273 static int flag_contract_build_level = DEFAULT;
275 static bool contracts_p1332_default = false, contracts_p1332_review = false,
276 contracts_std = false, contracts_p1429 = false;
278 static contract_semantic
279 get_concrete_check ()
281 return flag_contract_continuation_mode ? CCS_MAYBE : CCS_NEVER;
284 static contract_semantic
285 get_concrete_axiom_semantic ()
287 return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE;
290 void
291 setup_default_contract_role (bool update)
293 contract_semantic check = get_concrete_check ();
294 contract_semantic axiom = get_concrete_axiom_semantic ();
295 switch (flag_contract_build_level)
297 case OFF:
298 add_contract_role ("default", CCS_IGNORE, CCS_IGNORE, axiom, update);
299 add_contract_role ("review", CCS_IGNORE, CCS_IGNORE, CCS_IGNORE, update);
300 break;
301 case DEFAULT:
302 add_contract_role ("default", check, CCS_IGNORE, axiom, update);
303 add_contract_role ("review", check, CCS_IGNORE, CCS_IGNORE, update);
304 break;
305 case AUDIT:
306 add_contract_role ("default", check, check, axiom, update);
307 add_contract_role ("review", check, check, CCS_IGNORE, update);
308 break;
312 contract_semantic
313 map_contract_semantic (const char *ident)
315 if (strcmp (ident, "ignore") == 0)
316 return CCS_IGNORE;
317 else if (strcmp (ident, "assume") == 0)
318 return CCS_ASSUME;
319 else if (strcmp (ident, "check_never_continue") == 0)
320 return CCS_NEVER;
321 else if (strcmp (ident, "check_maybe_continue") == 0)
322 return CCS_MAYBE;
323 return CCS_INVALID;
326 contract_level
327 map_contract_level (const char *ident)
329 if (strcmp (ident, "default") == 0)
330 return CONTRACT_DEFAULT;
331 else if (strcmp (ident, "audit") == 0)
332 return CONTRACT_AUDIT;
333 else if (strcmp (ident, "axiom") == 0)
334 return CONTRACT_AXIOM;
335 return CONTRACT_INVALID;
339 void
340 handle_OPT_fcontract_build_level_ (const char *arg)
342 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
344 error ("%<-fcontract-build-level=%> cannot be mixed with p1332/p1429");
345 return;
347 else
348 contracts_std = true;
350 if (strcmp (arg, "off") == 0)
351 flag_contract_build_level = OFF;
352 else if (strcmp (arg, "default") == 0)
353 flag_contract_build_level = DEFAULT;
354 else if (strcmp (arg, "audit") == 0)
355 flag_contract_build_level = AUDIT;
356 else
357 error ("%<-fcontract-build-level=%> must be off|default|audit");
359 setup_default_contract_role ();
362 void
363 handle_OPT_fcontract_assumption_mode_ (const char *arg)
365 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
367 error ("%<-fcontract-assumption-mode=%> cannot be mixed with p1332/p1429");
368 return;
370 else
371 contracts_std = true;
373 if (strcmp (arg, "on") == 0)
374 flag_contract_assumption_mode = true;
375 else if (strcmp (arg, "off") == 0)
376 flag_contract_assumption_mode = false;
377 else
378 error ("%<-fcontract-assumption-mode=%> must be %<on%> or %<off%>");
380 setup_default_contract_role ();
383 void
384 handle_OPT_fcontract_continuation_mode_ (const char *arg)
386 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
388 error ("%<-fcontract-continuation-mode=%> cannot be mixed with p1332/p1429");
389 return;
391 else
392 contracts_std = true;
394 if (strcmp (arg, "on") == 0)
395 flag_contract_continuation_mode = true;
396 else if (strcmp (arg, "off") == 0)
397 flag_contract_continuation_mode = false;
398 else
399 error ("%<-fcontract-continuation-mode=%> must be %<on%> or %<off%>");
401 setup_default_contract_role ();
404 void
405 handle_OPT_fcontract_role_ (const char *arg)
407 const char *name = arg;
408 const char *vals = strchr (name, ':');
409 if (vals == NULL)
411 error ("%<-fcontract-role=%> must be in the form role:semantics");
412 return;
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);
419 aus = strchr (des, ',');
420 if (aus == NULL)
422 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
423 goto validate;
425 *aus = '\0'; // null terminate des
426 aus = aus + 1; // move past null
428 axs = strchr (aus, ',');
429 if (axs == NULL)
431 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
432 goto validate;
434 *axs = '\0'; // null terminate aus
435 axs = axs + 1; // move past null
437 dess = lookup_concrete_semantic (des);
438 auss = lookup_concrete_semantic (aus);
439 axss = lookup_concrete_semantic (axs);
440 validate:
441 free (des);
442 if (dess == CCS_INVALID || auss == CCS_INVALID || axss == CCS_INVALID)
443 return;
445 bool is_defalult_role = role_name_equal (name, "default");
446 bool is_review_role = role_name_equal (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))
450 error ("%<-fcontract-role=%> cannot be mixed with std/p1429 contract flags");
451 return;
453 else if (is_std_role)
455 contracts_p1332_default |= is_defalult_role;
456 contracts_p1332_review |= is_review_role;
459 contract_role *role = add_contract_role (name, dess, auss, axss);
461 if (role == NULL)
463 // TODO: not enough space?
464 error ("%<-fcontract-level=%> too many custom roles");
465 return;
467 else
468 validate_contract_role (role);
471 void
472 handle_OPT_fcontract_semantic_ (const char *arg)
474 if (!strchr (arg, ':'))
476 error ("%<-fcontract-semantic=%> must be in the form level:semantic");
477 return;
480 if (contracts_std || contracts_p1332_default)
482 error ("%<-fcontract-semantic=%> cannot be mixed with std/p1332 contract flags");
483 return;
485 contracts_p1429 = true;
487 contract_role *role = get_contract_role ("default");
488 if (!role)
490 error ("%<-fcontract-semantic=%> cannot find default role");
491 return;
494 const char *semantic = strchr (arg, ':') + 1;
495 contract_semantic sem = lookup_concrete_semantic (semantic);
496 if (sem == CCS_INVALID)
497 return;
499 if (strncmp ("default:", arg, 8) == 0)
500 role->default_semantic = sem;
501 else if (strncmp ("audit:", arg, 6) == 0)
502 role->audit_semantic = sem;
503 else if (strncmp ("axiom:", arg, 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);
510 /* Convert a contract CONFIG into a contract_mode. */
512 static contract_mode
513 contract_config_to_mode (tree config)
515 if (config == NULL_TREE)
516 return contract_mode (CONTRACT_DEFAULT, get_default_contract_role ());
518 /* TREE_LIST has TREE_VALUE is a level and TREE_PURPOSE is role. */
519 if (TREE_CODE (config) == TREE_LIST)
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 ();
527 contract_level level =
528 map_contract_level (IDENTIFIER_POINTER (TREE_VALUE (config)));
529 return contract_mode (level, role);
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);
539 /* Convert a contract's config into a concrete semantic using the current
540 contract semantic mapping. */
542 static contract_semantic
543 compute_concrete_semantic (tree contract)
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
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;
567 gcc_assert (false);
570 /* Return true if any contract in CONTRACT_ATTRs is not yet parsed. */
572 bool
573 contract_any_deferred_p (tree contract_attr)
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;
581 /* Returns true if all attributes are contracts. */
583 bool
584 all_attributes_are_contracts_p (tree attributes)
586 for (; attributes; attributes = TREE_CHAIN (attributes))
587 if (!cxx_contract_attribute_p (attributes))
588 return false;
589 return true;
592 /* Mark most of a contract as being invalid. */
594 tree
595 invalidate_contract (tree t)
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;
604 /* Returns an invented parameter declration of the form 'TYPE ID' for the
605 purpose of parsing the postcondition.
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. */
610 tree
611 make_postcondition_variable (cp_expr id, tree type)
613 if (id == error_mark_node)
614 return id;
616 tree decl = build_lang_decl (PARM_DECL, id, type);
617 DECL_ARTIFICIAL (decl) = true;
618 DECL_SOURCE_LOCATION (decl) = id.get_location ();
620 pushdecl (decl);
621 return decl;
624 /* As above, except that the type is unknown. */
626 tree
627 make_postcondition_variable (cp_expr id)
629 return make_postcondition_variable (id, make_auto ());
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. */
636 bool
637 check_postcondition_result (tree decl, tree type, location_t loc)
639 if (VOID_TYPE_P (type))
641 error_at (loc,
642 DECL_CONSTRUCTOR_P (decl)
643 ? G_("constructor does not return a value to test")
644 : DECL_DESTRUCTOR_P (decl)
645 ? G_("destructor does not return a value to test")
646 : G_("function does not return a value to test"));
647 return false;
650 return true;
653 /* Instantiate each postcondition with the return type to finalize the
654 attribute. */
656 void
657 rebuild_postconditions (tree decl)
659 tree type = TREE_TYPE (TREE_TYPE (decl));
660 tree attributes = DECL_CONTRACTS (decl);
662 for (; attributes ; attributes = TREE_CHAIN (attributes))
664 if (!cxx_contract_attribute_p (attributes))
665 continue;
666 tree contract = TREE_VALUE (TREE_VALUE (attributes));
667 if (TREE_CODE (contract) != POSTCONDITION_STMT)
668 continue;
669 tree condition = CONTRACT_CONDITION (contract);
671 /* If any conditions are deferred, they're all deferred. Note that
672 we don't have to instantiate postconditions in that case because
673 the type is available through the declaration. */
674 if (TREE_CODE (condition) == DEFERRED_PARSE)
675 return;
677 tree oldvar = POSTCONDITION_IDENTIFIER (contract);
678 if (!oldvar)
679 continue;
681 /* Always update the context of the result variable so that it can
682 be remapped by remap_contracts. */
683 DECL_CONTEXT (oldvar) = decl;
685 /* If the return type is undeduced, defer until later. */
686 if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
687 return;
689 /* Check the postcondition variable. */
690 location_t loc = DECL_SOURCE_LOCATION (oldvar);
691 if (!check_postcondition_result (decl, type, loc))
693 invalidate_contract (contract);
694 continue;
697 /* "Instantiate" the result variable using the known type. Also update
698 the context so the inliner will actually remap this the parameter when
699 generating contract checks. */
700 tree newvar = copy_node (oldvar);
701 TREE_TYPE (newvar) = type;
703 /* Make parameters and result available for substitution. */
704 local_specialization_stack stack (lss_copy);
705 for (tree t = DECL_ARGUMENTS (decl); t != NULL_TREE; t = TREE_CHAIN (t))
706 register_local_identity (t);
707 register_local_specialization (newvar, oldvar);
709 ++processing_contract_condition;
710 condition = tsubst_expr (condition, make_tree_vec (0),
711 tf_warning_or_error, decl);
712 --processing_contract_condition;
714 /* Update the contract condition and result. */
715 POSTCONDITION_IDENTIFIER (contract) = newvar;
716 CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
720 static tree
721 build_comment (cp_expr condition)
723 /* Try to get the actual source text for the condition; if that fails pretty
724 print the resulting tree. */
725 char *str = get_source_text_between (condition.get_start (),
726 condition.get_finish ());
727 if (!str)
729 /* FIXME cases where we end up here
730 #line macro usage (oof)
731 contracts10.C
732 contracts11.C */
733 const char *str = expr_to_string (condition);
734 return build_string_literal (strlen (str) + 1, str);
737 tree t = build_string_literal (strlen (str) + 1, str);
738 free (str);
739 return t;
742 /* Build a contract statement. */
744 tree
745 grok_contract (tree attribute, tree mode, tree result, cp_expr condition,
746 location_t loc)
748 tree_code code;
749 if (is_attribute_p ("assert", attribute))
750 code = ASSERTION_STMT;
751 else if (is_attribute_p ("pre", attribute))
752 code = PRECONDITION_STMT;
753 else if (is_attribute_p ("post", attribute))
754 code = POSTCONDITION_STMT;
755 else
756 gcc_unreachable ();
758 /* Build the contract. The condition is added later. In the case that
759 the contract is deferred, result an plain identifier, not a result
760 variable. */
761 tree contract;
762 tree type = void_type_node;
763 if (code != POSTCONDITION_STMT)
764 contract = build3_loc (loc, code, type, mode, NULL_TREE, NULL_TREE);
765 else
766 contract = build4_loc (loc, code, type, mode, NULL_TREE, NULL_TREE, result);
768 /* Determine the concrete semantic. */
769 set_contract_semantic (contract, compute_concrete_semantic (contract));
771 /* If the contract is deferred, don't do anything with the condition. */
772 if (TREE_CODE (condition) == DEFERRED_PARSE)
774 CONTRACT_CONDITION (contract) = condition;
775 return contract;
778 /* Generate the comment from the original condition. */
779 CONTRACT_COMMENT (contract) = build_comment (condition);
781 /* The condition is converted to bool. */
782 condition = finish_contract_condition (condition);
783 CONTRACT_CONDITION (contract) = condition;
785 return contract;
788 /* Build the contract attribute specifier where IDENTIFIER is one of 'pre',
789 'post' or 'assert' and CONTRACT is the underlying statement. */
790 tree
791 finish_contract_attribute (tree identifier, tree contract)
793 if (contract == error_mark_node)
794 return error_mark_node;
796 tree attribute = build_tree_list (build_tree_list (NULL_TREE, identifier),
797 build_tree_list (NULL_TREE, contract));
800 /* Mark the attribute as dependent if the condition is dependent.
802 TODO: I'm not sure this is strictly necessary. It's going to be marked as
803 such by a subroutine of cplus_decl_attributes. */
804 tree condition = CONTRACT_CONDITION (contract);
805 if (TREE_CODE (condition) == DEFERRED_PARSE
806 || value_dependent_expression_p (condition))
807 ATTR_IS_DEPENDENT (attribute) = true;
809 return attribute;
812 /* Update condition of a late-parsed contract and postcondition variable,
813 if any. */
815 void
816 update_late_contract (tree contract, tree result, tree condition)
818 if (TREE_CODE (contract) == POSTCONDITION_STMT)
819 POSTCONDITION_IDENTIFIER (contract) = result;
821 /* Generate the comment from the original condition. */
822 CONTRACT_COMMENT (contract) = build_comment (condition);
824 /* The condition is converted to bool. */
825 condition = finish_contract_condition (condition);
826 CONTRACT_CONDITION (contract) = condition;
829 /* Return TRUE iff ATTR has been parsed by the front-end as a c++2a contract
830 attribute. */
832 bool
833 cxx_contract_attribute_p (const_tree attr)
835 if (attr == NULL_TREE
836 || TREE_CODE (attr) != TREE_LIST)
837 return false;
839 if (!TREE_PURPOSE (attr) || TREE_CODE (TREE_PURPOSE (attr)) != TREE_LIST)
840 return false;
841 if (!TREE_VALUE (attr) || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST)
842 return false;
843 if (!TREE_VALUE (TREE_VALUE (attr)))
844 return false;
846 return (TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == PRECONDITION_STMT
847 || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == POSTCONDITION_STMT
848 || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == ASSERTION_STMT);
851 /* True if ATTR is an assertion. */
853 bool
854 cp_contract_assertion_p (const_tree attr)
856 /* This is only an assertion if it is a valid cxx contract attribute and the
857 statement is an ASSERTION_STMT. */
858 return cxx_contract_attribute_p (attr)
859 && TREE_CODE (CONTRACT_STATEMENT (attr)) == ASSERTION_STMT;
862 /* Remove all c++2a style contract attributes from the DECL_ATTRIBUTEs of the
863 FUNCTION_DECL FNDECL. */
865 void
866 remove_contract_attributes (tree fndecl)
868 tree list = NULL_TREE;
869 for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
870 if (!cxx_contract_attribute_p (p))
871 list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list);
872 DECL_ATTRIBUTES (fndecl) = nreverse (list);
875 static tree find_first_non_contract (tree attributes)
877 tree head = attributes;
878 tree p = find_contract (attributes);
880 /* There are no contracts. */
881 if (!p)
882 return head;
884 /* There are leading contracts. */
885 if (p == head)
887 while (cxx_contract_attribute_p (p))
888 p = TREE_CHAIN (p);
889 head = p;
892 return head;
895 /* Remove contracts from ATTRIBUTES. */
897 tree splice_out_contracts (tree attributes)
899 tree head = find_first_non_contract (attributes);
900 if (!head)
901 return NULL_TREE;
903 /* Splice out remaining contracts. */
904 tree p = TREE_CHAIN (head);
905 tree q = head;
906 while (p)
908 if (cxx_contract_attribute_p (p))
910 /* Skip a sequence of contracts and then link q to the next
911 non-contract attribute. */
913 p = TREE_CHAIN (p);
914 while (cxx_contract_attribute_p (p));
915 TREE_CHAIN (q) = p;
917 else
918 p = TREE_CHAIN (p);
921 return head;
924 /* Copy contract attributes from NEWDECL onto the attribute list of OLDDECL. */
926 void copy_contract_attributes (tree olddecl, tree newdecl)
928 tree attrs = NULL_TREE;
929 for (tree c = DECL_CONTRACTS (newdecl); c; c = TREE_CHAIN (c))
931 if (!cxx_contract_attribute_p (c))
932 continue;
933 attrs = tree_cons (TREE_PURPOSE (c), TREE_VALUE (c), attrs);
935 attrs = chainon (DECL_ATTRIBUTES (olddecl), nreverse (attrs));
936 DECL_ATTRIBUTES (olddecl) = attrs;
938 /* And update DECL_CONTEXT of the postcondition result identifier. */
939 rebuild_postconditions (olddecl);
942 /* Returns the parameter corresponding to the return value of a guarded
943 function D. Returns NULL_TREE if D has no postconditions or is void. */
945 static tree
946 get_postcondition_result_parameter (tree d)
948 if (!d || d == error_mark_node)
949 return NULL_TREE;
951 if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (d))))
952 return NULL_TREE;
954 tree post = DECL_POST_FN (d);
955 if (!post || post == error_mark_node)
956 return NULL_TREE;
958 for (tree arg = DECL_ARGUMENTS (post); arg; arg = TREE_CHAIN (arg))
959 if (!TREE_CHAIN (arg))
960 return arg;
962 return NULL_TREE;
966 /* For use with the tree inliner. This preserves non-mapped local variables,
967 such as postcondition result variables, during remapping. */
969 static tree
970 retain_decl (tree decl, copy_body_data *)
972 return decl;
975 /* Rewrite the condition of contract in place, so that references to SRC's
976 parameters are updated to refer to DST's parameters. The postcondition
977 result variable is left unchanged.
979 This, along with remap_contracts, are subroutines of duplicate_decls.
980 When declarations are merged, we sometimes need to update contracts to
981 refer to new parameters.
983 If DUPLICATE_P is true, this is called by duplicate_decls to rewrite contacts
984 in terms of a new set of parameters. In this case, we can retain local
985 variables appearing in the contract because the contract is not being
986 prepared for insertion into a new function. Importantly, this preserves the
987 references to postcondition results, which are not replaced during merging.
989 If false, we're preparing to emit the contract condition into the body
990 of a new function, so we need to make copies of all local variables
991 appearing in the contract (e.g., if it includes a lambda expression). Note
992 that in this case, postcondition results are mapped to the last parameter
993 of DST.
995 This is also used to reuse a parent type's contracts on virtual methods. */
997 static void
998 remap_contract (tree src, tree dst, tree contract, bool duplicate_p)
1000 copy_body_data id;
1001 hash_map<tree, tree> decl_map;
1003 memset (&id, 0, sizeof (id));
1004 id.src_fn = src;
1005 id.dst_fn = dst;
1006 id.src_cfun = DECL_STRUCT_FUNCTION (src);
1007 id.decl_map = &decl_map;
1009 /* If we're merging contracts, don't copy local variables. */
1010 id.copy_decl = duplicate_p ? retain_decl : copy_decl_no_change;
1012 id.transform_call_graph_edges = CB_CGE_DUPLICATE;
1013 id.transform_new_cfg = false;
1014 id.transform_return_to_modify = false;
1015 id.transform_parameter = true;
1017 /* Make sure not to unshare trees behind the front-end's back
1018 since front-end specific mechanisms may rely on sharing. */
1019 id.regimplify = false;
1020 id.do_not_unshare = true;
1021 id.do_not_fold = true;
1023 /* We're not inside any EH region. */
1024 id.eh_lp_nr = 0;
1026 bool do_remap = false;
1028 /* Insert parameter remappings. */
1029 if (TREE_CODE (src) == FUNCTION_DECL)
1030 src = DECL_ARGUMENTS (src);
1031 if (TREE_CODE (dst) == FUNCTION_DECL)
1032 dst = DECL_ARGUMENTS (dst);
1034 for (tree sp = src, dp = dst;
1035 sp || dp;
1036 sp = DECL_CHAIN (sp), dp = DECL_CHAIN (dp))
1038 if (!sp && dp
1039 && TREE_CODE (contract) == POSTCONDITION_STMT
1040 && DECL_CHAIN (dp) == NULL_TREE)
1042 gcc_assert (!duplicate_p);
1043 if (tree result = POSTCONDITION_IDENTIFIER (contract))
1045 gcc_assert (DECL_P (result));
1046 insert_decl_map (&id, result, dp);
1047 do_remap = true;
1049 break;
1051 gcc_assert (sp && dp);
1053 if (sp == dp)
1054 continue;
1056 insert_decl_map (&id, sp, dp);
1057 do_remap = true;
1059 if (!do_remap)
1060 return;
1062 walk_tree (&CONTRACT_CONDITION (contract), copy_tree_body_r, &id, NULL);
1065 /* Rewrite any references to SRC's PARM_DECLs to the corresponding PARM_DECL in
1066 DST in all of the contract attributes in CONTRACTS by calling remap_contract
1067 on each.
1069 This is used for two purposes: to rewrite contract attributes during
1070 duplicate_decls, and to prepare contracts for emission into a function's
1071 respective precondition and postcondition functions. DUPLICATE_P is used
1072 to determine the context in which this function is called. See above for
1073 the behavior described by this flag. */
1075 void
1076 remap_contracts (tree src, tree dst, tree contracts, bool duplicate_p)
1078 for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
1080 if (!cxx_contract_attribute_p (attr))
1081 continue;
1082 tree contract = CONTRACT_STATEMENT (attr);
1083 if (TREE_CODE (CONTRACT_CONDITION (contract)) != DEFERRED_PARSE)
1084 remap_contract (src, dst, contract, duplicate_p);
1088 /* Helper to replace references to dummy this parameters with references to
1089 the first argument of the FUNCTION_DECL DATA. */
1091 static tree
1092 remap_dummy_this_1 (tree *tp, int *, void *data)
1094 if (!is_this_parameter (*tp))
1095 return NULL_TREE;
1096 tree fn = (tree)data;
1097 *tp = DECL_ARGUMENTS (fn);
1098 return NULL_TREE;
1101 /* Replace all references to dummy this parameters in EXPR with references to
1102 the first argument of the FUNCTION_DECL FN. */
1104 static void
1105 remap_dummy_this (tree fn, tree *expr)
1107 walk_tree (expr, remap_dummy_this_1, fn, NULL);
1110 /* Contract matching. */
1112 /* True if the contract is valid. */
1114 static bool
1115 contract_valid_p (tree contract)
1117 return CONTRACT_CONDITION (contract) != error_mark_node;
1120 /* True if the contract attribute is valid. */
1122 static bool
1123 contract_attribute_valid_p (tree attribute)
1125 return contract_valid_p (TREE_VALUE (TREE_VALUE (attribute)));
1128 /* Compare the contract conditions of OLD_ATTR and NEW_ATTR. Returns false
1129 if the conditions are equivalent, and true otherwise. */
1131 static bool
1132 check_for_mismatched_contracts (tree old_attr, tree new_attr,
1133 contract_matching_context ctx)
1135 tree old_contract = CONTRACT_STATEMENT (old_attr);
1136 tree new_contract = CONTRACT_STATEMENT (new_attr);
1138 /* Different kinds of contracts do not match. */
1139 if (TREE_CODE (old_contract) != TREE_CODE (new_contract))
1141 auto_diagnostic_group d;
1142 error_at (EXPR_LOCATION (new_contract),
1143 ctx == cmc_declaration
1144 ? "mismatched contract attribute in declaration"
1145 : "mismatched contract attribute in override");
1146 inform (EXPR_LOCATION (old_contract), "previous contract here");
1147 return true;
1150 /* A deferred contract tentatively matches. */
1151 if (CONTRACT_CONDITION_DEFERRED_P (new_contract))
1152 return false;
1154 /* Compare the conditions of the contracts. We fold immediately to avoid
1155 issues comparing contracts on overrides that use parameters -- see
1156 contracts-pre3. */
1157 tree t1 = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
1158 tree t2 = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
1160 /* Compare the contracts. The fold doesn't eliminate conversions to members.
1161 Set the comparing_override_contracts flag to ensure that references
1162 through 'this' are equal if they designate the same member, regardless of
1163 the path those members. */
1164 bool saved_comparing_contracts = comparing_override_contracts;
1165 comparing_override_contracts = (ctx == cmc_override);
1166 bool matching_p = cp_tree_equal (t1, t2);
1167 comparing_override_contracts = saved_comparing_contracts;
1169 if (!matching_p)
1171 auto_diagnostic_group d;
1172 error_at (EXPR_LOCATION (CONTRACT_CONDITION (new_contract)),
1173 ctx == cmc_declaration
1174 ? "mismatched contract condition in declaration"
1175 : "mismatched contract condition in override");
1176 inform (EXPR_LOCATION (CONTRACT_CONDITION (old_contract)),
1177 "previous contract here");
1178 return true;
1181 return false;
1184 /* Compare the contract attributes of OLDDECL and NEWDECL. Returns true
1185 if the contracts match, and false if they differ. */
1187 bool
1188 match_contract_conditions (location_t oldloc, tree old_attrs,
1189 location_t newloc, tree new_attrs,
1190 contract_matching_context ctx)
1192 /* Contracts only match if they are both specified. */
1193 if (!old_attrs || !new_attrs)
1194 return true;
1196 /* Compare each contract in turn. */
1197 while (old_attrs && new_attrs)
1199 /* If either contract is ill-formed, skip the rest of the comparison,
1200 since we've already diagnosed an error. */
1201 if (!contract_attribute_valid_p (new_attrs)
1202 || !contract_attribute_valid_p (old_attrs))
1203 return false;
1205 if (check_for_mismatched_contracts (old_attrs, new_attrs, ctx))
1206 return false;
1207 old_attrs = CONTRACT_CHAIN (old_attrs);
1208 new_attrs = CONTRACT_CHAIN (new_attrs);
1211 /* If we didn't compare all attributes, the contracts don't match. */
1212 if (old_attrs || new_attrs)
1214 auto_diagnostic_group d;
1215 error_at (newloc,
1216 ctx == cmc_declaration
1217 ? "declaration has a different number of contracts than "
1218 "previously declared"
1219 : "override has a different number of contracts than "
1220 "previously declared");
1221 inform (oldloc,
1222 new_attrs
1223 ? "original declaration with fewer contracts here"
1224 : "original declaration with more contracts here");
1225 return false;
1228 return true;
1231 /* Deferred contract mapping.
1233 This is used to compare late-parsed contracts on overrides with their
1234 base class functions.
1236 TODO: It seems like this could be replaced by a simple list that maps from
1237 overrides to their base functions. It's not clear that we really need
1238 a map to a function + a list of contracts. */
1240 /* Map from FNDECL to a tree list of contracts that have not been matched or
1241 diagnosed yet. The TREE_PURPOSE is the basefn we're overriding, and the
1242 TREE_VALUE is the list of contract attrs for BASEFN. */
1244 static hash_map<tree_decl_hash, tree> pending_guarded_decls;
1246 void
1247 defer_guarded_contract_match (tree fndecl, tree fn, tree contracts)
1249 if (!pending_guarded_decls.get (fndecl))
1251 pending_guarded_decls.put (fndecl, build_tree_list (fn, contracts));
1252 return;
1254 for (tree pending = *pending_guarded_decls.get (fndecl);
1255 pending;
1256 pending = TREE_CHAIN (pending))
1258 if (TREE_VALUE (pending) == contracts)
1259 return;
1260 if (TREE_CHAIN (pending) == NULL_TREE)
1261 TREE_CHAIN (pending) = build_tree_list (fn, contracts);
1265 /* If the FUNCTION_DECL DECL has any contracts that had their matching
1266 deferred earlier, do that checking now. */
1268 void
1269 match_deferred_contracts (tree decl)
1271 tree *tp = pending_guarded_decls.get (decl);
1272 if (!tp)
1273 return;
1275 gcc_assert(!contract_any_deferred_p (DECL_CONTRACTS (decl)));
1277 processing_template_decl_sentinel ptds;
1278 processing_template_decl = uses_template_parms (decl);
1280 /* Do late contract matching. */
1281 for (tree pending = *tp; pending; pending = TREE_CHAIN (pending))
1283 tree new_contracts = TREE_VALUE (pending);
1284 location_t new_loc = CONTRACT_SOURCE_LOCATION (new_contracts);
1285 tree old_contracts = DECL_CONTRACTS (decl);
1286 location_t old_loc = CONTRACT_SOURCE_LOCATION (old_contracts);
1287 tree base = TREE_PURPOSE (pending);
1288 match_contract_conditions (new_loc, new_contracts,
1289 old_loc, old_contracts,
1290 base ? cmc_override : cmc_declaration);
1293 /* Clear out deferred match list so we don't check it twice. */
1294 pending_guarded_decls.remove (decl);
1297 /* Map from FUNCTION_DECL to a FUNCTION_DECL for either the PRE_FN or POST_FN.
1298 These are used to parse contract conditions and are called inside the body
1299 of the guarded function. */
1300 static GTY(()) hash_map<tree, tree> *decl_pre_fn;
1301 static GTY(()) hash_map<tree, tree> *decl_post_fn;
1303 /* Returns the precondition funtion for D, or null if not set. */
1305 tree
1306 get_precondition_function (tree d)
1308 hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1309 tree *result = decl_pre_fn->get (d);
1310 return result ? *result : NULL_TREE;
1313 /* Returns the postcondition funtion for D, or null if not set. */
1315 tree
1316 get_postcondition_function (tree d)
1318 hash_map_maybe_create<hm_ggc> (decl_post_fn);
1319 tree *result = decl_post_fn->get (d);
1320 return result ? *result : NULL_TREE;
1323 /* Makes PRE the precondition function for D. */
1325 void
1326 set_precondition_function (tree d, tree pre)
1328 gcc_assert (pre);
1329 hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1330 gcc_assert (!decl_pre_fn->get (d));
1331 decl_pre_fn->put (d, pre);
1334 /* Makes POST the postcondition function for D. */
1336 void
1337 set_postcondition_function (tree d, tree post)
1339 gcc_assert (post);
1340 hash_map_maybe_create<hm_ggc> (decl_post_fn);
1341 gcc_assert (!decl_post_fn->get (d));
1342 decl_post_fn->put (d, post);
1345 /* Set the PRE and POST functions for D. Note that PRE and POST can be
1346 null in this case. If so the functions are not recorded. */
1348 void
1349 set_contract_functions (tree d, tree pre, tree post)
1351 if (pre)
1352 set_precondition_function (d, pre);
1353 if (post)
1354 set_postcondition_function (d, post);
1357 /* Return a copy of the FUNCTION_DECL IDECL with its own unshared
1358 PARM_DECL and DECL_ATTRIBUTEs. */
1360 static tree
1361 copy_fn_decl (tree idecl)
1363 tree decl = copy_decl (idecl);
1364 DECL_ATTRIBUTES (decl) = copy_list (DECL_ATTRIBUTES (idecl));
1366 if (DECL_RESULT (idecl))
1368 DECL_RESULT (decl) = copy_decl (DECL_RESULT (idecl));
1369 DECL_CONTEXT (DECL_RESULT (decl)) = decl;
1371 if (!DECL_ARGUMENTS (idecl) || VOID_TYPE_P (DECL_ARGUMENTS (idecl)))
1372 return decl;
1374 tree last = DECL_ARGUMENTS (decl) = copy_decl (DECL_ARGUMENTS (decl));
1375 DECL_CONTEXT (last) = decl;
1376 for (tree p = TREE_CHAIN (DECL_ARGUMENTS (idecl)); p; p = TREE_CHAIN (p))
1378 if (VOID_TYPE_P (p))
1380 TREE_CHAIN (last) = void_list_node;
1381 break;
1383 last = TREE_CHAIN (last) = copy_decl (p);
1384 DECL_CONTEXT (last) = decl;
1386 return decl;
1389 /* Build a declaration for the pre- or postcondition of a guarded FNDECL. */
1391 static tree
1392 build_contract_condition_function (tree fndecl, bool pre)
1394 if (TREE_TYPE (fndecl) == error_mark_node)
1395 return error_mark_node;
1396 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
1397 && !TYPE_METHOD_BASETYPE (TREE_TYPE (fndecl)))
1398 return error_mark_node;
1400 /* Create and rename the unchecked function and give an internal name. */
1401 tree fn = copy_fn_decl (fndecl);
1402 DECL_RESULT (fn) = NULL_TREE;
1403 tree value_type = pre ? void_type_node : TREE_TYPE (TREE_TYPE (fn));
1405 /* Don't propagate declaration attributes to the checking function,
1406 including the original contracts. */
1407 DECL_ATTRIBUTES (fn) = NULL_TREE;
1409 tree arg_types = NULL_TREE;
1410 tree *last = &arg_types;
1412 /* FIXME will later optimizations delete unused args to prevent extra arg
1413 passing? do we care? */
1414 tree class_type = NULL_TREE;
1415 for (tree arg_type = TYPE_ARG_TYPES (TREE_TYPE (fn));
1416 arg_type && arg_type != void_list_node;
1417 arg_type = TREE_CHAIN (arg_type))
1419 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
1420 && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type)
1422 class_type = TREE_TYPE (TREE_VALUE (arg_type));
1423 continue;
1425 *last = build_tree_list (TREE_PURPOSE (arg_type), TREE_VALUE (arg_type));
1426 last = &TREE_CHAIN (*last);
1429 if (pre || VOID_TYPE_P (value_type))
1430 *last = void_list_node;
1431 else
1433 tree name = get_identifier ("__r");
1434 tree parm = build_lang_decl (PARM_DECL, name, value_type);
1435 DECL_CONTEXT (parm) = fn;
1436 DECL_ARTIFICIAL (parm) = true;
1437 DECL_ARGUMENTS (fn) = chainon (DECL_ARGUMENTS (fn), parm);
1439 *last = build_tree_list (NULL_TREE, value_type);
1440 TREE_CHAIN (*last) = void_list_node;
1442 if (aggregate_value_p (value_type, fndecl))
1443 /* If FNDECL returns in memory, don't return the value from the
1444 postcondition. */
1445 value_type = void_type_node;
1448 TREE_TYPE (fn) = build_function_type (value_type, arg_types);
1449 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
1450 TREE_TYPE (fn) = build_method_type (class_type, TREE_TYPE (fn));
1452 DECL_NAME (fn) = copy_node (DECL_NAME (fn));
1453 DECL_INITIAL (fn) = error_mark_node;
1454 DECL_ABSTRACT_ORIGIN (fn) = fndecl;
1456 IDENTIFIER_VIRTUAL_P (DECL_NAME (fn)) = false;
1457 DECL_VIRTUAL_P (fn) = false;
1459 /* Make these functions internal if we can, i.e. if the guarded function is
1460 not vague linkage, or if we can put them in a comdat group with the
1461 guarded function. */
1462 if (!DECL_WEAK (fndecl) || HAVE_COMDAT_GROUP)
1464 TREE_PUBLIC (fn) = false;
1465 DECL_EXTERNAL (fn) = false;
1466 DECL_WEAK (fn) = false;
1467 DECL_COMDAT (fn) = false;
1469 /* We haven't set the comdat group on the guarded function yet, we'll add
1470 this to the same group in comdat_linkage later. */
1471 gcc_assert (!DECL_ONE_ONLY (fndecl));
1473 DECL_INTERFACE_KNOWN (fn) = true;
1476 DECL_ARTIFICIAL (fn) = true;
1478 /* Update various inline related declaration properties. */
1479 //DECL_DECLARED_INLINE_P (fn) = true;
1480 DECL_DISREGARD_INLINE_LIMITS (fn) = true;
1481 TREE_NO_WARNING (fn) = 1;
1483 return fn;
1486 /* Return true if CONTRACT is checked or assumed under the current build
1487 configuration. */
1489 bool
1490 contract_active_p (tree contract)
1492 return get_contract_semantic (contract) != CCS_IGNORE;
1495 static bool
1496 has_active_contract_condition (tree d, tree_code c)
1498 for (tree as = DECL_CONTRACTS (d) ; as != NULL_TREE; as = TREE_CHAIN (as))
1500 tree contract = TREE_VALUE (TREE_VALUE (as));
1501 if (TREE_CODE (contract) == c && contract_active_p (contract))
1502 return true;
1504 return false;
1507 /* True if D has any checked or assumed preconditions. */
1509 static bool
1510 has_active_preconditions (tree d)
1512 return has_active_contract_condition (d, PRECONDITION_STMT);
1515 /* True if D has any checked or assumed postconditions. */
1517 static bool
1518 has_active_postconditions (tree d)
1520 return has_active_contract_condition (d, POSTCONDITION_STMT);
1523 /* Return true if any contract in the CONTRACT list is checked or assumed
1524 under the current build configuration. */
1526 bool
1527 contract_any_active_p (tree contract)
1529 for (; contract != NULL_TREE; contract = CONTRACT_CHAIN (contract))
1530 if (contract_active_p (TREE_VALUE (TREE_VALUE (contract))))
1531 return true;
1532 return false;
1535 /* Do we need to mess with contracts for DECL1? */
1537 static bool
1538 handle_contracts_p (tree decl1)
1540 return (flag_contracts
1541 && !processing_template_decl
1542 && DECL_ABSTRACT_ORIGIN (decl1) == NULL_TREE
1543 && contract_any_active_p (DECL_CONTRACTS (decl1)));
1546 /* Should we break out DECL1's pre/post contracts into separate functions?
1547 FIXME I'd like this to default to 0, but that will need an overhaul to the
1548 return identifier handling to just refer to the RESULT_DECL. */
1550 static bool
1551 outline_contracts_p (tree decl1)
1553 return (!DECL_CONSTRUCTOR_P (decl1)
1554 && !DECL_DESTRUCTOR_P (decl1));
1557 /* Build the precondition checking function for D. */
1559 static tree
1560 build_precondition_function (tree d)
1562 if (!has_active_preconditions (d))
1563 return NULL_TREE;
1565 return build_contract_condition_function (d, /*pre=*/true);
1568 /* Build the postcondition checking function for D. If the return
1569 type is undeduced, don't build the function yet. We do that in
1570 apply_deduced_return_type. */
1572 static tree
1573 build_postcondition_function (tree d)
1575 if (!has_active_postconditions (d))
1576 return NULL_TREE;
1578 tree type = TREE_TYPE (TREE_TYPE (d));
1579 if (is_auto (type))
1580 return NULL_TREE;
1582 return build_contract_condition_function (d, /*pre=*/false);
1585 static void
1586 build_contract_function_decls (tree d)
1588 /* Constructors and destructors have their contracts inserted inline. */
1589 if (!outline_contracts_p (d))
1590 return;
1592 /* Build the pre/post functions (or not). */
1593 tree pre = build_precondition_function (d);
1594 tree post = build_postcondition_function (d);
1595 set_contract_functions (d, pre, post);
1598 static const char *
1599 get_contract_level_name (tree contract)
1601 if (CONTRACT_LITERAL_MODE_P (contract))
1602 return "";
1603 if (tree mode = CONTRACT_MODE (contract))
1604 if (tree level = TREE_VALUE (mode))
1605 return IDENTIFIER_POINTER (level);
1606 return "default";
1609 static const char *
1610 get_contract_role_name (tree contract)
1612 if (CONTRACT_LITERAL_MODE_P (contract))
1613 return "";
1614 if (tree mode = CONTRACT_MODE (contract))
1615 if (tree role = TREE_PURPOSE (mode))
1616 return IDENTIFIER_POINTER (role);
1617 return "default";
1620 /* Build a layout-compatible internal version of std::contract_violation. */
1622 static tree
1623 get_pseudo_contract_violation_type ()
1625 if (!pseudo_contract_violation_type)
1627 /* Must match <contract>:
1628 class contract_violation {
1629 const char* _M_file;
1630 const char* _M_function;
1631 const char* _M_comment;
1632 const char* _M_level;
1633 const char* _M_role;
1634 uint_least32_t _M_line;
1635 signed char _M_continue;
1636 If this changes, also update the initializer in
1637 build_contract_violation. */
1638 const tree types[] = { const_string_type_node,
1639 const_string_type_node,
1640 const_string_type_node,
1641 const_string_type_node,
1642 const_string_type_node,
1643 uint_least32_type_node,
1644 signed_char_type_node };
1645 tree fields = NULL_TREE;
1646 for (tree type : types)
1648 /* finish_builtin_struct wants fieldss chained in reverse. */
1649 tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1650 NULL_TREE, type);
1651 DECL_CHAIN (next) = fields;
1652 fields = next;
1654 iloc_sentinel ils (input_location);
1655 input_location = BUILTINS_LOCATION;
1656 pseudo_contract_violation_type = make_class_type (RECORD_TYPE);
1657 finish_builtin_struct (pseudo_contract_violation_type,
1658 "__pseudo_contract_violation",
1659 fields, NULL_TREE);
1660 CLASSTYPE_AS_BASE (pseudo_contract_violation_type)
1661 = pseudo_contract_violation_type;
1662 DECL_CONTEXT (TYPE_NAME (pseudo_contract_violation_type))
1663 = FROB_CONTEXT (global_namespace);
1664 TREE_PUBLIC (TYPE_NAME (pseudo_contract_violation_type)) = true;
1665 CLASSTYPE_LITERAL_P (pseudo_contract_violation_type) = true;
1666 CLASSTYPE_LAZY_COPY_CTOR (pseudo_contract_violation_type) = true;
1667 xref_basetypes (pseudo_contract_violation_type, /*bases=*/NULL_TREE);
1668 pseudo_contract_violation_type
1669 = cp_build_qualified_type (pseudo_contract_violation_type,
1670 TYPE_QUAL_CONST);
1672 return pseudo_contract_violation_type;
1675 /* Return a VAR_DECL to pass to handle_contract_violation. */
1677 static tree
1678 build_contract_violation (tree contract, contract_continuation cmode)
1680 expanded_location loc = expand_location (EXPR_LOCATION (contract));
1681 const char *function = fndecl_name (DECL_ORIGIN (current_function_decl));
1682 const char *level = get_contract_level_name (contract);
1683 const char *role = get_contract_role_name (contract);
1685 /* Must match the type layout in get_pseudo_contract_violation_type. */
1686 tree ctor = build_constructor_va
1687 (init_list_type_node, 7,
1688 NULL_TREE, build_string_literal (loc.file),
1689 NULL_TREE, build_string_literal (function),
1690 NULL_TREE, CONTRACT_COMMENT (contract),
1691 NULL_TREE, build_string_literal (level),
1692 NULL_TREE, build_string_literal (role),
1693 NULL_TREE, build_int_cst (uint_least32_type_node, loc.line),
1694 NULL_TREE, build_int_cst (signed_char_type_node, cmode));
1696 ctor = finish_compound_literal (get_pseudo_contract_violation_type (),
1697 ctor, tf_none);
1698 protected_set_expr_location (ctor, EXPR_LOCATION (contract));
1699 return ctor;
1702 /* Return handle_contract_violation(), declaring it if needed. */
1704 static tree
1705 declare_handle_contract_violation ()
1707 tree fnname = get_identifier ("handle_contract_violation");
1708 tree viol_name = get_identifier ("contract_violation");
1709 tree l = lookup_qualified_name (global_namespace, fnname,
1710 LOOK_want::HIDDEN_FRIEND);
1711 for (tree f: lkp_range (l))
1712 if (TREE_CODE (f) == FUNCTION_DECL)
1714 tree parms = TYPE_ARG_TYPES (TREE_TYPE (f));
1715 if (remaining_arguments (parms) != 1)
1716 continue;
1717 tree parmtype = non_reference (TREE_VALUE (parms));
1718 if (CLASS_TYPE_P (parmtype)
1719 && TYPE_IDENTIFIER (parmtype) == viol_name)
1720 return f;
1723 tree id_exp = get_identifier ("experimental");
1724 tree ns_exp = lookup_qualified_name (std_node, id_exp);
1726 tree violation = error_mark_node;
1727 if (TREE_CODE (ns_exp) == NAMESPACE_DECL)
1728 violation = lookup_qualified_name (ns_exp, viol_name,
1729 LOOK_want::TYPE
1730 |LOOK_want::HIDDEN_FRIEND);
1732 if (TREE_CODE (violation) == TYPE_DECL)
1733 violation = TREE_TYPE (violation);
1734 else
1736 push_nested_namespace (std_node);
1737 push_namespace (id_exp, /*inline*/false);
1738 violation = make_class_type (RECORD_TYPE);
1739 create_implicit_typedef (viol_name, violation);
1740 DECL_SOURCE_LOCATION (TYPE_NAME (violation)) = BUILTINS_LOCATION;
1741 DECL_CONTEXT (TYPE_NAME (violation)) = current_namespace;
1742 pushdecl_namespace_level (TYPE_NAME (violation), /*hidden*/true);
1743 pop_namespace ();
1744 pop_nested_namespace (std_node);
1747 tree argtype = cp_build_qualified_type (violation, TYPE_QUAL_CONST);
1748 argtype = cp_build_reference_type (argtype, /*rval*/false);
1749 tree fntype = build_function_type_list (void_type_node, argtype, NULL_TREE);
1751 push_nested_namespace (global_namespace);
1752 tree fn = build_cp_library_fn_ptr ("handle_contract_violation", fntype,
1753 ECF_COLD);
1754 pushdecl_namespace_level (fn, /*hiding*/true);
1755 pop_nested_namespace (global_namespace);
1757 return fn;
1760 /* Build the call to handle_contract_violation for CONTRACT. */
1762 static void
1763 build_contract_handler_call (tree contract,
1764 contract_continuation cmode)
1766 tree violation = build_contract_violation (contract, cmode);
1767 tree violation_fn = declare_handle_contract_violation ();
1768 tree call = build_call_n (violation_fn, 1, build_address (violation));
1769 finish_expr_stmt (call);
1772 /* Generate the code that checks or assumes a contract, but do not attach
1773 it to the current context. This is called during genericization. */
1775 tree
1776 build_contract_check (tree contract)
1778 contract_semantic semantic = get_contract_semantic (contract);
1779 if (semantic == CCS_INVALID)
1780 return NULL_TREE;
1782 /* Ignored contracts are never checked or assumed. */
1783 if (semantic == CCS_IGNORE)
1784 return void_node;
1786 remap_dummy_this (current_function_decl, &CONTRACT_CONDITION (contract));
1787 tree condition = CONTRACT_CONDITION (contract);
1788 if (condition == error_mark_node)
1789 return NULL_TREE;
1791 location_t loc = EXPR_LOCATION (contract);
1793 if (semantic == CCS_ASSUME)
1794 return build_assume_call (loc, condition);
1796 tree if_stmt = begin_if_stmt ();
1797 tree cond = build_x_unary_op (loc,
1798 TRUTH_NOT_EXPR,
1799 condition, NULL_TREE,
1800 tf_warning_or_error);
1801 finish_if_stmt_cond (cond, if_stmt);
1803 /* Get the continuation mode. */
1804 contract_continuation cmode;
1805 switch (semantic)
1807 case CCS_NEVER: cmode = NEVER_CONTINUE; break;
1808 case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
1809 default: gcc_unreachable ();
1812 build_contract_handler_call (contract, cmode);
1813 if (cmode == NEVER_CONTINUE)
1814 finish_expr_stmt (build_call_a (terminate_fn, 0, nullptr));
1816 finish_then_clause (if_stmt);
1817 tree scope = IF_SCOPE (if_stmt);
1818 IF_SCOPE (if_stmt) = NULL;
1819 return do_poplevel (scope);
1822 /* Add the contract statement CONTRACT to the current block if valid. */
1824 static void
1825 emit_contract_statement (tree contract)
1827 /* Only add valid contracts. */
1828 if (get_contract_semantic (contract) != CCS_INVALID
1829 && CONTRACT_CONDITION (contract) != error_mark_node)
1830 add_stmt (contract);
1833 /* Generate the statement for the given contract attribute by adding the
1834 statement to the current block. Returns the next contract in the chain. */
1836 static tree
1837 emit_contract_attr (tree attr)
1839 gcc_assert (TREE_CODE (attr) == TREE_LIST);
1841 emit_contract_statement (CONTRACT_STATEMENT (attr));
1843 return CONTRACT_CHAIN (attr);
1846 /* Add the statements of contract attributes ATTRS to the current block. */
1848 static void
1849 emit_contract_conditions (tree attrs, tree_code code)
1851 if (!attrs) return;
1852 gcc_assert (TREE_CODE (attrs) == TREE_LIST);
1853 gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1854 while (attrs)
1856 tree contract = CONTRACT_STATEMENT (attrs);
1857 if (TREE_CODE (contract) == code)
1858 attrs = emit_contract_attr (attrs);
1859 else
1860 attrs = CONTRACT_CHAIN (attrs);
1864 /* Emit the statement for an assertion attribute. */
1866 void
1867 emit_assertion (tree attr)
1869 emit_contract_attr (attr);
1872 /* Emit statements for precondition attributes. */
1874 static void
1875 emit_preconditions (tree attr)
1877 return emit_contract_conditions (attr, PRECONDITION_STMT);
1880 /* Emit statements for postcondition attributes. */
1882 static void
1883 emit_postconditions_cleanup (tree contracts)
1885 tree stmts = push_stmt_list ();
1886 emit_contract_conditions (contracts, POSTCONDITION_STMT);
1887 stmts = pop_stmt_list (stmts);
1888 push_cleanup (NULL_TREE, stmts, /*eh_only*/false);
1891 /* We're compiling the pre/postcondition function CONDFN; remap any FN
1892 attributes that match CODE and emit them. */
1894 static void
1895 remap_and_emit_conditions (tree fn, tree condfn, tree_code code)
1897 gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1898 for (tree attr = DECL_CONTRACTS (fn); attr;
1899 attr = CONTRACT_CHAIN (attr))
1901 tree contract = CONTRACT_STATEMENT (attr);
1902 if (TREE_CODE (contract) == code)
1904 contract = copy_node (contract);
1905 remap_contract (fn, condfn, contract, /*duplicate_p=*/false);
1906 emit_contract_statement (contract);
1911 /* Converts a contract condition to bool and ensures it has a locaiton. */
1913 tree
1914 finish_contract_condition (cp_expr condition)
1916 /* Ensure we have the condition location saved in case we later need to
1917 emit a conversion error during template instantiation and wouldn't
1918 otherwise have it. */
1919 if (!CAN_HAVE_LOCATION_P (condition) || EXCEPTIONAL_CLASS_P (condition))
1921 condition = build1_loc (condition.get_location (), VIEW_CONVERT_EXPR,
1922 TREE_TYPE (condition), condition);
1923 EXPR_LOCATION_WRAPPER_P (condition) = 1;
1926 if (condition == error_mark_node || type_dependent_expression_p (condition))
1927 return condition;
1929 return condition_conversion (condition);
1932 void
1933 maybe_update_postconditions (tree fco)
1935 /* Update any postconditions and the postcondition checking function
1936 as needed. If there are postconditions, we'll use those to rewrite
1937 return statements to check postconditions. */
1938 if (has_active_postconditions (fco))
1940 rebuild_postconditions (fco);
1941 tree post = build_postcondition_function (fco);
1942 set_postcondition_function (fco, post);
1946 /* Called on attribute lists that must not contain contracts. If any
1947 contracts are present, issue an error diagnostic and return true. */
1949 bool
1950 diagnose_misapplied_contracts (tree attributes)
1952 if (attributes == NULL_TREE)
1953 return false;
1955 tree contract_attr = find_contract (attributes);
1956 if (!contract_attr)
1957 return false;
1959 error_at (EXPR_LOCATION (CONTRACT_STATEMENT (contract_attr)),
1960 "contracts must appertain to a function type");
1962 /* Invalidate the contract so we don't treat it as valid later on. */
1963 invalidate_contract (TREE_VALUE (TREE_VALUE (contract_attr)));
1965 return true;
1968 /* Build and return an argument list containing all the parameters of the
1969 (presumably guarded) FUNCTION_DECL FN. This can be used to forward all of
1970 FN's arguments to a function taking the same list of arguments -- namely
1971 the unchecked form of FN.
1973 We use CALL_FROM_THUNK_P instead of forward_parm for forwarding
1974 semantics. */
1976 static vec<tree, va_gc> *
1977 build_arg_list (tree fn)
1979 vec<tree, va_gc> *args = make_tree_vector ();
1980 for (tree t = DECL_ARGUMENTS (fn); t; t = DECL_CHAIN (t))
1981 vec_safe_push (args, t);
1982 return args;
1985 void
1986 start_function_contracts (tree decl1)
1988 if (!handle_contracts_p (decl1))
1989 return;
1991 if (!outline_contracts_p (decl1))
1993 emit_preconditions (DECL_CONTRACTS (current_function_decl));
1994 emit_postconditions_cleanup (DECL_CONTRACTS (current_function_decl));
1995 return;
1998 /* Contracts may have just been added without a chance to parse them, though
1999 we still need the PRE_FN available to generate a call to it. */
2000 if (!DECL_PRE_FN (decl1))
2001 build_contract_function_decls (decl1);
2003 /* If we're starting a guarded function with valid contracts, we need to
2004 insert a call to the pre function. */
2005 if (DECL_PRE_FN (decl1)
2006 && DECL_PRE_FN (decl1) != error_mark_node)
2008 releasing_vec args = build_arg_list (decl1);
2009 tree call = build_call_a (DECL_PRE_FN (decl1),
2010 args->length (),
2011 args->address ());
2012 CALL_FROM_THUNK_P (call) = true;
2013 finish_expr_stmt (call);
2017 /* Finish up the pre & post function definitions for a guarded FNDECL,
2018 and compile those functions all the way to assembler language output. */
2020 void
2021 finish_function_contracts (tree fndecl)
2023 if (!handle_contracts_p (fndecl)
2024 || !outline_contracts_p (fndecl))
2025 return;
2027 for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
2029 tree contract = CONTRACT_STATEMENT (ca);
2030 if (!CONTRACT_CONDITION (contract)
2031 || CONTRACT_CONDITION_DEFERRED_P (contract)
2032 || CONTRACT_CONDITION (contract) == error_mark_node)
2033 return;
2036 int flags = SF_DEFAULT | SF_PRE_PARSED;
2038 /* If either the pre or post functions are bad, don't bother emitting
2039 any contracts. The program is already ill-formed. */
2040 tree pre = DECL_PRE_FN (fndecl);
2041 tree post = DECL_POST_FN (fndecl);
2042 if (pre == error_mark_node || post == error_mark_node)
2043 return;
2045 if (pre && DECL_INITIAL (fndecl) != error_mark_node)
2047 DECL_PENDING_INLINE_P (pre) = false;
2048 start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
2049 remap_and_emit_conditions (fndecl, pre, PRECONDITION_STMT);
2050 tree finished_pre = finish_function (false);
2051 expand_or_defer_fn (finished_pre);
2054 if (post && DECL_INITIAL (fndecl) != error_mark_node)
2056 DECL_PENDING_INLINE_P (post) = false;
2057 start_preparsed_function (post,
2058 DECL_ATTRIBUTES (post),
2059 flags);
2060 remap_and_emit_conditions (fndecl, post, POSTCONDITION_STMT);
2061 if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post))))
2062 finish_return_stmt (get_postcondition_result_parameter (fndecl));
2064 tree finished_post = finish_function (false);
2065 expand_or_defer_fn (finished_post);
2069 /* Rewrite the expression of a returned expression so that it invokes the
2070 postcondition function as needed. */
2072 tree
2073 apply_postcondition_to_return (tree expr)
2075 tree fn = current_function_decl;
2076 tree post = DECL_POST_FN (fn);
2077 if (!post)
2078 return NULL_TREE;
2080 /* If FN returns in memory, POST has a void return type and we call it when
2081 EXPR is DECL_RESULT (fn). If FN returns a scalar, POST has the same
2082 return type and we call it when EXPR is the value being returned. */
2083 if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post)))
2084 != (expr == DECL_RESULT (fn)))
2085 return NULL_TREE;
2087 releasing_vec args = build_arg_list (fn);
2088 if (get_postcondition_result_parameter (fn))
2089 vec_safe_push (args, expr);
2090 tree call = build_call_a (post,
2091 args->length (),
2092 args->address ());
2093 CALL_FROM_THUNK_P (call) = true;
2095 return call;
2098 /* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
2099 guarded functions. */
2101 void
2102 duplicate_contracts (tree newdecl, tree olddecl)
2104 if (TREE_CODE (newdecl) == TEMPLATE_DECL)
2105 newdecl = DECL_TEMPLATE_RESULT (newdecl);
2106 if (TREE_CODE (olddecl) == TEMPLATE_DECL)
2107 olddecl = DECL_TEMPLATE_RESULT (olddecl);
2109 /* Compare contracts to see if they match. */
2110 tree old_contracts = DECL_CONTRACTS (olddecl);
2111 tree new_contracts = DECL_CONTRACTS (newdecl);
2113 if (!old_contracts && !new_contracts)
2114 return;
2116 location_t old_loc = DECL_SOURCE_LOCATION (olddecl);
2117 location_t new_loc = DECL_SOURCE_LOCATION (newdecl);
2119 /* If both declarations specify contracts, ensure they match.
2121 TODO: This handles a potential error a little oddly. Consider:
2123 struct B {
2124 virtual void f(int n) [[pre: n == 0]];
2126 struct D : B {
2127 void f(int n) override; // inherits contracts
2129 void D::f(int n) [[pre: n == 0]] // OK
2132 It's okay because we're explicitly restating the inherited contract.
2133 Changing the precondition on the definition D::f causes match_contracts
2134 to complain about the mismatch.
2136 This would previously have been diagnosed as adding contracts to an
2137 override, but this seems like it should be well-formed. */
2138 if (old_contracts && new_contracts)
2140 if (!match_contract_conditions (old_loc, old_contracts,
2141 new_loc, new_contracts,
2142 cmc_declaration))
2143 return;
2144 if (DECL_UNIQUE_FRIEND_P (newdecl))
2145 /* Newdecl's contracts are still DEFERRED_PARSE, and we're about to
2146 collapse it into olddecl, so stash away olddecl's contracts for
2147 later comparison. */
2148 defer_guarded_contract_match (olddecl, olddecl, old_contracts);
2151 /* Handle cases where contracts are omitted in one or the other
2152 declaration. */
2153 if (old_contracts)
2155 /* Contracts have been previously specified by are no omitted. The
2156 new declaration inherits the existing contracts. */
2157 if (!new_contracts)
2158 copy_contract_attributes (newdecl, olddecl);
2160 /* In all cases, remove existing contracts from OLDDECL to prevent the
2161 attribute merging function from adding excess contracts. */
2162 remove_contract_attributes (olddecl);
2164 else if (!old_contracts)
2166 /* We are adding contracts to a declaration. */
2167 if (new_contracts)
2169 /* We can't add to a previously defined function. */
2170 if (DECL_INITIAL (olddecl))
2172 auto_diagnostic_group d;
2173 error_at (new_loc, "cannot add contracts after definition");
2174 inform (DECL_SOURCE_LOCATION (olddecl), "original definition here");
2175 return;
2178 /* We can't add to an unguarded virtual function declaration. */
2179 if (DECL_VIRTUAL_P (olddecl) && new_contracts)
2181 auto_diagnostic_group d;
2182 error_at (new_loc, "cannot add contracts to a virtual function");
2183 inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here");
2184 return;
2187 /* Depending on the "first declaration" rule, we may not be able
2188 to add contracts to a function after the fact. */
2189 if (flag_contract_strict_declarations)
2191 warning_at (new_loc,
2192 OPT_fcontract_strict_declarations_,
2193 "declaration adds contracts to %q#D",
2194 olddecl);
2195 return;
2198 /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to
2199 remap them because NEWDECL's parameters will replace those of
2200 OLDDECL. Remove the contracts from NEWDECL so they aren't
2201 cloned when merging. */
2202 copy_contract_attributes (olddecl, newdecl);
2203 remove_contract_attributes (newdecl);
2208 /* Replace the any contract attributes on OVERRIDER with a copy where any
2209 references to BASEFN's PARM_DECLs have been rewritten to the corresponding
2210 PARM_DECL in OVERRIDER. */
2212 void
2213 inherit_base_contracts (tree overrider, tree basefn)
2215 tree last = NULL_TREE, contract_attrs = NULL_TREE;
2216 for (tree a = DECL_CONTRACTS (basefn);
2217 a != NULL_TREE;
2218 a = CONTRACT_CHAIN (a))
2220 tree c = copy_node (a);
2221 TREE_VALUE (c) = build_tree_list (TREE_PURPOSE (TREE_VALUE (c)),
2222 copy_node (CONTRACT_STATEMENT (c)));
2224 tree src = basefn;
2225 tree dst = overrider;
2226 remap_contract (src, dst, CONTRACT_STATEMENT (c), /*duplicate_p=*/true);
2228 CONTRACT_COMMENT (CONTRACT_STATEMENT (c)) =
2229 copy_node (CONTRACT_COMMENT (CONTRACT_STATEMENT (c)));
2231 chainon (last, c);
2232 last = c;
2233 if (!contract_attrs)
2234 contract_attrs = c;
2237 set_decl_contracts (overrider, contract_attrs);
2240 #include "gt-cp-contracts.h"