Daily bump.
[official-gcc.git] / gcc / cp / contracts.cc
blob39f0487ea367aa5b24501d7cb9ce5fd08b9b9289
1 /* Definitions for C++ contract levels
2 Copyright (C) 2020-2024 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 We implement the checking as follows:
93 For functions with no post-conditions we wrap the original function body as
94 follows:
97 handle_pre_condition_checking ();
98 original_function_body ();
101 This implements the intent that the preconditions are processed after the
102 function parameters are initialised but before any other actions.
104 For functions with post-conditions:
106 if (preconditions_exist)
107 handle_pre_condition_checking ();
110 original_function_body ();
112 finally
114 handle_post_condition_checking ();
116 else [only if the function is not marked noexcept(true) ]
121 In this, post-conditions [that might apply to the return value etc.] are
122 evaluated on every non-exceptional edge out of the function.
124 FIXME outlining contract checks into separate functions was motivated
125 partly by wanting to call the postcondition function at each return
126 statement, which we no longer do; at this point outlining doesn't seem to
127 have any advantage over emitting the contracts directly in the function
128 body.
130 More helpful for optimization might be to make the contracts a wrapper
131 function that could be inlined into the caller, the callee, or both. */
133 #include "config.h"
134 #include "system.h"
135 #include "coretypes.h"
136 #include "cp-tree.h"
137 #include "stringpool.h"
138 #include "diagnostic.h"
139 #include "options.h"
140 #include "contracts.h"
141 #include "tree.h"
142 #include "tree-inline.h"
143 #include "attribs.h"
144 #include "tree-iterator.h"
145 #include "print-tree.h"
146 #include "stor-layout.h"
147 #include "intl.h"
149 const int max_custom_roles = 32;
150 static contract_role contract_build_roles[max_custom_roles] = {
153 bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = {
154 { 0, 0, 0, 0, 0, },
155 { 0, 1, 0, 0, 0, },
156 { 0, 1, 1, 1, 1, },
157 { 0, 1, 1, 1, 1, },
158 { 0, 1, 0, 0, 1, },
161 void
162 validate_contract_role (contract_role *role)
164 gcc_assert (role);
165 if (!unchecked_contract_p (role->axiom_semantic))
166 error ("axiom contract semantic must be %<assume%> or %<ignore%>");
168 if (!valid_configs[role->default_semantic][role->audit_semantic] )
169 warning (0, "the %<audit%> semantic should be at least as strong as "
170 "the %<default%> semantic");
173 contract_semantic
174 lookup_concrete_semantic (const char *name)
176 if (strcmp (name, "ignore") == 0)
177 return CCS_IGNORE;
178 if (strcmp (name, "assume") == 0)
179 return CCS_ASSUME;
180 if (strcmp (name, "check_never_continue") == 0
181 || strcmp (name, "never") == 0
182 || strcmp (name, "abort") == 0)
183 return CCS_NEVER;
184 if (strcmp (name, "check_maybe_continue") == 0
185 || strcmp (name, "maybe") == 0)
186 return CCS_MAYBE;
187 error ("'%s' is not a valid explicit concrete semantic", name);
188 return CCS_INVALID;
191 /* Compare role and name up to either the NUL terminator or the first
192 occurrence of colon. */
194 static bool
195 role_name_equal (const char *role, const char *name)
197 size_t role_len = strcspn (role, ":");
198 size_t name_len = strcspn (name, ":");
199 if (role_len != name_len)
200 return false;
201 return strncmp (role, name, role_len) == 0;
204 static bool
205 role_name_equal (contract_role *role, const char *name)
207 if (role->name == NULL)
208 return false;
209 return role_name_equal (role->name, name);
212 contract_role *
213 get_contract_role (const char *name)
215 for (int i = 0; i < max_custom_roles; ++i)
217 contract_role *potential = contract_build_roles + i;
218 if (role_name_equal (potential, name))
219 return potential;
221 if (role_name_equal (name, "default") || role_name_equal (name, "review"))
223 setup_default_contract_role (false);
224 return get_contract_role (name);
226 return NULL;
229 contract_role *
230 add_contract_role (const char *name,
231 contract_semantic des,
232 contract_semantic aus,
233 contract_semantic axs,
234 bool update)
236 for (int i = 0; i < max_custom_roles; ++i)
238 contract_role *potential = contract_build_roles + i;
239 if (potential->name != NULL
240 && !role_name_equal (potential, name))
241 continue;
242 if (potential->name != NULL && !update)
243 return potential;
244 potential->name = name;
245 potential->default_semantic = des;
246 potential->audit_semantic = aus;
247 potential->axiom_semantic = axs;
248 return potential;
250 return NULL;
253 enum contract_build_level { OFF, DEFAULT, AUDIT };
254 static bool flag_contract_continuation_mode = false;
255 static bool flag_contract_assumption_mode = true;
256 static int flag_contract_build_level = DEFAULT;
258 static bool contracts_p1332_default = false, contracts_p1332_review = false,
259 contracts_std = false, contracts_p1429 = false;
261 static contract_semantic
262 get_concrete_check ()
264 return flag_contract_continuation_mode ? CCS_MAYBE : CCS_NEVER;
267 static contract_semantic
268 get_concrete_axiom_semantic ()
270 return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE;
273 void
274 setup_default_contract_role (bool update)
276 contract_semantic check = get_concrete_check ();
277 contract_semantic axiom = get_concrete_axiom_semantic ();
278 switch (flag_contract_build_level)
280 case OFF:
281 add_contract_role ("default", CCS_IGNORE, CCS_IGNORE, axiom, update);
282 add_contract_role ("review", CCS_IGNORE, CCS_IGNORE, CCS_IGNORE, update);
283 break;
284 case DEFAULT:
285 add_contract_role ("default", check, CCS_IGNORE, axiom, update);
286 add_contract_role ("review", check, CCS_IGNORE, CCS_IGNORE, update);
287 break;
288 case AUDIT:
289 add_contract_role ("default", check, check, axiom, update);
290 add_contract_role ("review", check, check, CCS_IGNORE, update);
291 break;
295 contract_semantic
296 map_contract_semantic (const char *ident)
298 if (strcmp (ident, "ignore") == 0)
299 return CCS_IGNORE;
300 else if (strcmp (ident, "assume") == 0)
301 return CCS_ASSUME;
302 else if (strcmp (ident, "check_never_continue") == 0)
303 return CCS_NEVER;
304 else if (strcmp (ident, "check_maybe_continue") == 0)
305 return CCS_MAYBE;
306 return CCS_INVALID;
309 contract_level
310 map_contract_level (const char *ident)
312 if (strcmp (ident, "default") == 0)
313 return CONTRACT_DEFAULT;
314 else if (strcmp (ident, "audit") == 0)
315 return CONTRACT_AUDIT;
316 else if (strcmp (ident, "axiom") == 0)
317 return CONTRACT_AXIOM;
318 return CONTRACT_INVALID;
322 void
323 handle_OPT_fcontract_build_level_ (const char *arg)
325 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
327 error ("%<-fcontract-build-level=%> cannot be mixed with p1332/p1429");
328 return;
330 else
331 contracts_std = true;
333 if (strcmp (arg, "off") == 0)
334 flag_contract_build_level = OFF;
335 else if (strcmp (arg, "default") == 0)
336 flag_contract_build_level = DEFAULT;
337 else if (strcmp (arg, "audit") == 0)
338 flag_contract_build_level = AUDIT;
339 else
340 error ("%<-fcontract-build-level=%> must be off|default|audit");
342 setup_default_contract_role ();
345 void
346 handle_OPT_fcontract_assumption_mode_ (const char *arg)
348 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
350 error ("%<-fcontract-assumption-mode=%> cannot be mixed with p1332/p1429");
351 return;
353 else
354 contracts_std = true;
356 if (strcmp (arg, "on") == 0)
357 flag_contract_assumption_mode = true;
358 else if (strcmp (arg, "off") == 0)
359 flag_contract_assumption_mode = false;
360 else
361 error ("%<-fcontract-assumption-mode=%> must be %<on%> or %<off%>");
363 setup_default_contract_role ();
366 void
367 handle_OPT_fcontract_continuation_mode_ (const char *arg)
369 if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
371 error ("%<-fcontract-continuation-mode=%> cannot be mixed with p1332/p1429");
372 return;
374 else
375 contracts_std = true;
377 if (strcmp (arg, "on") == 0)
378 flag_contract_continuation_mode = true;
379 else if (strcmp (arg, "off") == 0)
380 flag_contract_continuation_mode = false;
381 else
382 error ("%<-fcontract-continuation-mode=%> must be %<on%> or %<off%>");
384 setup_default_contract_role ();
387 void
388 handle_OPT_fcontract_role_ (const char *arg)
390 const char *name = arg;
391 const char *vals = strchr (name, ':');
392 if (vals == NULL)
394 error ("%<-fcontract-role=%> must be in the form role:semantics");
395 return;
398 contract_semantic dess = CCS_INVALID, auss = CCS_INVALID, axss = CCS_INVALID;
399 char *des = NULL, *aus = NULL, *axs = NULL;
400 des = xstrdup (vals + 1);
402 aus = strchr (des, ',');
403 if (aus == NULL)
405 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
406 goto validate;
408 *aus = '\0'; // null terminate des
409 aus = aus + 1; // move past null
411 axs = strchr (aus, ',');
412 if (axs == NULL)
414 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
415 goto validate;
417 *axs = '\0'; // null terminate aus
418 axs = axs + 1; // move past null
420 dess = lookup_concrete_semantic (des);
421 auss = lookup_concrete_semantic (aus);
422 axss = lookup_concrete_semantic (axs);
423 validate:
424 free (des);
425 if (dess == CCS_INVALID || auss == CCS_INVALID || axss == CCS_INVALID)
426 return;
428 bool is_defalult_role = role_name_equal (name, "default");
429 bool is_review_role = role_name_equal (name, "review");
430 bool is_std_role = is_defalult_role || is_review_role;
431 if ((contracts_std && is_std_role) || (contracts_p1429 && is_defalult_role))
433 error ("%<-fcontract-role=%> cannot be mixed with std/p1429 contract flags");
434 return;
436 else if (is_std_role)
438 contracts_p1332_default |= is_defalult_role;
439 contracts_p1332_review |= is_review_role;
442 contract_role *role = add_contract_role (name, dess, auss, axss);
444 if (role == NULL)
446 // TODO: not enough space?
447 error ("%<-fcontract-level=%> too many custom roles");
448 return;
450 else
451 validate_contract_role (role);
454 void
455 handle_OPT_fcontract_semantic_ (const char *arg)
457 if (!strchr (arg, ':'))
459 error ("%<-fcontract-semantic=%> must be in the form level:semantic");
460 return;
463 if (contracts_std || contracts_p1332_default)
465 error ("%<-fcontract-semantic=%> cannot be mixed with std/p1332 contract flags");
466 return;
468 contracts_p1429 = true;
470 contract_role *role = get_contract_role ("default");
471 if (!role)
473 error ("%<-fcontract-semantic=%> cannot find default role");
474 return;
477 const char *semantic = strchr (arg, ':') + 1;
478 contract_semantic sem = lookup_concrete_semantic (semantic);
479 if (sem == CCS_INVALID)
480 return;
482 if (strncmp ("default:", arg, 8) == 0)
483 role->default_semantic = sem;
484 else if (strncmp ("audit:", arg, 6) == 0)
485 role->audit_semantic = sem;
486 else if (strncmp ("axiom:", arg, 6) == 0)
487 role->axiom_semantic = sem;
488 else
489 error ("%<-fcontract-semantic=%> level must be default, audit, or axiom");
490 validate_contract_role (role);
493 /* Convert a contract CONFIG into a contract_mode. */
495 static contract_mode
496 contract_config_to_mode (tree config)
498 if (config == NULL_TREE)
499 return contract_mode (CONTRACT_DEFAULT, get_default_contract_role ());
501 /* TREE_LIST has TREE_VALUE is a level and TREE_PURPOSE is role. */
502 if (TREE_CODE (config) == TREE_LIST)
504 contract_role *role = NULL;
505 if (TREE_PURPOSE (config))
506 role = get_contract_role (IDENTIFIER_POINTER (TREE_PURPOSE (config)));
507 if (!role)
508 role = get_default_contract_role ();
510 contract_level level =
511 map_contract_level (IDENTIFIER_POINTER (TREE_VALUE (config)));
512 return contract_mode (level, role);
515 /* Literal semantic. */
516 gcc_assert (TREE_CODE (config) == IDENTIFIER_NODE);
517 contract_semantic semantic =
518 map_contract_semantic (IDENTIFIER_POINTER (config));
519 return contract_mode (semantic);
522 /* Convert a contract's config into a concrete semantic using the current
523 contract semantic mapping. */
525 static contract_semantic
526 compute_concrete_semantic (tree contract)
528 contract_mode mode = contract_config_to_mode (CONTRACT_MODE (contract));
529 /* Compute the concrete semantic for the contract. */
530 if (!flag_contract_mode)
531 /* If contracts are off, treat all contracts as ignore. */
532 return CCS_IGNORE;
533 else if (mode.kind == contract_mode::cm_invalid)
534 return CCS_INVALID;
535 else if (mode.kind == contract_mode::cm_explicit)
536 return mode.get_semantic ();
537 else
539 gcc_assert (mode.get_role ());
540 gcc_assert (mode.get_level () != CONTRACT_INVALID);
541 contract_level level = mode.get_level ();
542 contract_role *role = mode.get_role ();
543 if (level == CONTRACT_DEFAULT)
544 return role->default_semantic;
545 else if (level == CONTRACT_AUDIT)
546 return role->audit_semantic;
547 else if (level == CONTRACT_AXIOM)
548 return role->axiom_semantic;
550 gcc_assert (false);
553 /* Return true if any contract in CONTRACT_ATTRs is not yet parsed. */
555 bool
556 contract_any_deferred_p (tree contract_attr)
558 for (; contract_attr; contract_attr = CONTRACT_CHAIN (contract_attr))
559 if (CONTRACT_CONDITION_DEFERRED_P (CONTRACT_STATEMENT (contract_attr)))
560 return true;
561 return false;
564 /* Returns true if all attributes are contracts. */
566 bool
567 all_attributes_are_contracts_p (tree attributes)
569 for (; attributes; attributes = TREE_CHAIN (attributes))
570 if (!cxx_contract_attribute_p (attributes))
571 return false;
572 return true;
575 /* Mark most of a contract as being invalid. */
577 tree
578 invalidate_contract (tree t)
580 if (TREE_CODE (t) == POSTCONDITION_STMT && POSTCONDITION_IDENTIFIER (t))
581 POSTCONDITION_IDENTIFIER (t) = error_mark_node;
582 CONTRACT_CONDITION (t) = error_mark_node;
583 CONTRACT_COMMENT (t) = error_mark_node;
584 return t;
587 /* Returns an invented parameter declration of the form 'TYPE ID' for the
588 purpose of parsing the postcondition.
590 We use a PARM_DECL instead of a VAR_DECL so that tsubst forces a lookup
591 in local specializations when we instantiate these things later. */
593 tree
594 make_postcondition_variable (cp_expr id, tree type)
596 if (id == error_mark_node)
597 return id;
599 tree decl = build_lang_decl (PARM_DECL, id, type);
600 DECL_ARTIFICIAL (decl) = true;
601 DECL_SOURCE_LOCATION (decl) = id.get_location ();
603 pushdecl (decl);
604 return decl;
607 /* As above, except that the type is unknown. */
609 tree
610 make_postcondition_variable (cp_expr id)
612 return make_postcondition_variable (id, make_auto ());
615 /* Check that the TYPE is valid for a named postcondition variable. Emit a
616 diagnostic if it is not. Returns TRUE if the result is OK and false
617 otherwise. */
619 bool
620 check_postcondition_result (tree decl, tree type, location_t loc)
622 /* Do not be confused by targetm.cxx.cdtor_return_this ();
623 conceptually, cdtors have no return value. */
624 if (VOID_TYPE_P (type)
625 || DECL_CONSTRUCTOR_P (decl)
626 || DECL_DESTRUCTOR_P (decl))
628 error_at (loc,
629 DECL_CONSTRUCTOR_P (decl)
630 ? G_("constructor does not return a value to test")
631 : DECL_DESTRUCTOR_P (decl)
632 ? G_("destructor does not return a value to test")
633 : G_("function does not return a value to test"));
634 return false;
637 return true;
640 /* Instantiate each postcondition with the return type to finalize the
641 attribute. */
643 void
644 rebuild_postconditions (tree decl)
646 tree type = TREE_TYPE (TREE_TYPE (decl));
647 tree attributes = DECL_CONTRACTS (decl);
649 for (; attributes ; attributes = TREE_CHAIN (attributes))
651 if (!cxx_contract_attribute_p (attributes))
652 continue;
653 tree contract = TREE_VALUE (TREE_VALUE (attributes));
654 if (TREE_CODE (contract) != POSTCONDITION_STMT)
655 continue;
656 tree condition = CONTRACT_CONDITION (contract);
658 /* If any conditions are deferred, they're all deferred. Note that
659 we don't have to instantiate postconditions in that case because
660 the type is available through the declaration. */
661 if (TREE_CODE (condition) == DEFERRED_PARSE)
662 return;
664 tree oldvar = POSTCONDITION_IDENTIFIER (contract);
665 if (!oldvar)
666 continue;
668 /* Always update the context of the result variable so that it can
669 be remapped by remap_contracts. */
670 DECL_CONTEXT (oldvar) = decl;
672 /* If the return type is undeduced, defer until later. */
673 if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
674 return;
676 /* Check the postcondition variable. */
677 location_t loc = DECL_SOURCE_LOCATION (oldvar);
678 if (!check_postcondition_result (decl, type, loc))
680 invalidate_contract (contract);
681 continue;
684 /* "Instantiate" the result variable using the known type. Also update
685 the context so the inliner will actually remap this the parameter when
686 generating contract checks. */
687 tree newvar = copy_node (oldvar);
688 TREE_TYPE (newvar) = type;
690 /* Make parameters and result available for substitution. */
691 local_specialization_stack stack (lss_copy);
692 for (tree t = DECL_ARGUMENTS (decl); t != NULL_TREE; t = TREE_CHAIN (t))
693 register_local_identity (t);
694 register_local_specialization (newvar, oldvar);
696 ++processing_contract_condition;
697 condition = tsubst_expr (condition, make_tree_vec (0),
698 tf_warning_or_error, decl);
699 --processing_contract_condition;
701 /* Update the contract condition and result. */
702 POSTCONDITION_IDENTIFIER (contract) = newvar;
703 CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
707 static tree
708 build_comment (cp_expr condition)
710 /* Try to get the actual source text for the condition; if that fails pretty
711 print the resulting tree. */
712 char *str = get_source_text_between (global_dc->get_file_cache (),
713 condition.get_start (),
714 condition.get_finish ());
715 if (!str)
717 /* FIXME cases where we end up here
718 #line macro usage (oof)
719 contracts10.C
720 contracts11.C */
721 const char *str = expr_to_string (condition);
722 return build_string_literal (strlen (str) + 1, str);
725 tree t = build_string_literal (strlen (str) + 1, str);
726 free (str);
727 return t;
730 /* Build a contract statement. */
732 tree
733 grok_contract (tree attribute, tree mode, tree result, cp_expr condition,
734 location_t loc)
736 if (condition == error_mark_node)
737 return error_mark_node;
739 tree_code code;
740 if (is_attribute_p ("assert", attribute))
741 code = ASSERTION_STMT;
742 else if (is_attribute_p ("pre", attribute))
743 code = PRECONDITION_STMT;
744 else if (is_attribute_p ("post", attribute))
745 code = POSTCONDITION_STMT;
746 else
747 gcc_unreachable ();
749 /* Build the contract. The condition is added later. In the case that
750 the contract is deferred, result an plain identifier, not a result
751 variable. */
752 tree contract;
753 tree type = void_type_node;
754 if (code != POSTCONDITION_STMT)
755 contract = build3_loc (loc, code, type, mode, NULL_TREE, NULL_TREE);
756 else
757 contract = build4_loc (loc, code, type, mode, NULL_TREE, NULL_TREE, result);
759 /* Determine the concrete semantic. */
760 set_contract_semantic (contract, compute_concrete_semantic (contract));
762 /* If the contract is deferred, don't do anything with the condition. */
763 if (TREE_CODE (condition) == DEFERRED_PARSE)
765 CONTRACT_CONDITION (contract) = condition;
766 return contract;
769 /* Generate the comment from the original condition. */
770 CONTRACT_COMMENT (contract) = build_comment (condition);
772 /* The condition is converted to bool. */
773 condition = finish_contract_condition (condition);
775 if (condition == error_mark_node)
776 return error_mark_node;
778 CONTRACT_CONDITION (contract) = condition;
780 return contract;
783 /* Build the contract attribute specifier where IDENTIFIER is one of 'pre',
784 'post' or 'assert' and CONTRACT is the underlying statement. */
785 tree
786 finish_contract_attribute (tree identifier, tree contract)
788 if (contract == error_mark_node)
789 return error_mark_node;
791 tree attribute = build_tree_list (build_tree_list (NULL_TREE, identifier),
792 build_tree_list (NULL_TREE, contract));
794 /* Mark the attribute as dependent if the condition is dependent.
796 TODO: I'm not sure this is strictly necessary. It's going to be marked as
797 such by a subroutine of cplus_decl_attributes. */
798 tree condition = CONTRACT_CONDITION (contract);
799 if (TREE_CODE (condition) == DEFERRED_PARSE
800 || value_dependent_expression_p (condition))
801 ATTR_IS_DEPENDENT (attribute) = true;
803 return attribute;
806 /* Update condition of a late-parsed contract and postcondition variable,
807 if any. */
809 void
810 update_late_contract (tree contract, tree result, tree condition)
812 if (TREE_CODE (contract) == POSTCONDITION_STMT)
813 POSTCONDITION_IDENTIFIER (contract) = result;
815 /* Generate the comment from the original condition. */
816 CONTRACT_COMMENT (contract) = build_comment (condition);
818 /* The condition is converted to bool. */
819 condition = finish_contract_condition (condition);
820 CONTRACT_CONDITION (contract) = condition;
823 /* Return TRUE iff ATTR has been parsed by the front-end as a c++2a contract
824 attribute. */
826 bool
827 cxx_contract_attribute_p (const_tree attr)
829 if (attr == NULL_TREE
830 || TREE_CODE (attr) != TREE_LIST)
831 return false;
833 if (!TREE_PURPOSE (attr) || TREE_CODE (TREE_PURPOSE (attr)) != TREE_LIST)
834 return false;
835 if (!TREE_VALUE (attr) || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST)
836 return false;
837 if (!TREE_VALUE (TREE_VALUE (attr)))
838 return false;
840 return (TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == PRECONDITION_STMT
841 || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == POSTCONDITION_STMT
842 || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == ASSERTION_STMT);
845 /* True if ATTR is an assertion. */
847 bool
848 cp_contract_assertion_p (const_tree attr)
850 /* This is only an assertion if it is a valid cxx contract attribute and the
851 statement is an ASSERTION_STMT. */
852 return cxx_contract_attribute_p (attr)
853 && TREE_CODE (CONTRACT_STATEMENT (attr)) == ASSERTION_STMT;
856 /* Remove all c++2a style contract attributes from the DECL_ATTRIBUTEs of the
857 FUNCTION_DECL FNDECL. */
859 void
860 remove_contract_attributes (tree fndecl)
862 tree list = NULL_TREE;
863 for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
864 if (!cxx_contract_attribute_p (p))
865 list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list);
866 DECL_ATTRIBUTES (fndecl) = nreverse (list);
869 static tree find_first_non_contract (tree attributes)
871 tree head = attributes;
872 tree p = find_contract (attributes);
874 /* There are no contracts. */
875 if (!p)
876 return head;
878 /* There are leading contracts. */
879 if (p == head)
881 while (cxx_contract_attribute_p (p))
882 p = TREE_CHAIN (p);
883 head = p;
886 return head;
889 /* Remove contracts from ATTRIBUTES. */
891 tree splice_out_contracts (tree attributes)
893 tree head = find_first_non_contract (attributes);
894 if (!head)
895 return NULL_TREE;
897 /* Splice out remaining contracts. */
898 tree p = TREE_CHAIN (head);
899 tree q = head;
900 while (p)
902 if (cxx_contract_attribute_p (p))
904 /* Skip a sequence of contracts and then link q to the next
905 non-contract attribute. */
907 p = TREE_CHAIN (p);
908 while (cxx_contract_attribute_p (p));
909 TREE_CHAIN (q) = p;
911 else
912 p = TREE_CHAIN (p);
915 return head;
918 /* Copy contract attributes from NEWDECL onto the attribute list of OLDDECL. */
920 void copy_contract_attributes (tree olddecl, tree newdecl)
922 tree attrs = NULL_TREE;
923 for (tree c = DECL_CONTRACTS (newdecl); c; c = TREE_CHAIN (c))
925 if (!cxx_contract_attribute_p (c))
926 continue;
927 attrs = tree_cons (TREE_PURPOSE (c), TREE_VALUE (c), attrs);
929 attrs = chainon (DECL_ATTRIBUTES (olddecl), nreverse (attrs));
930 DECL_ATTRIBUTES (olddecl) = attrs;
932 /* And update DECL_CONTEXT of the postcondition result identifier. */
933 rebuild_postconditions (olddecl);
936 /* Returns the parameter corresponding to the return value of a guarded
937 function D. Returns NULL_TREE if D has no postconditions or is void. */
939 static tree
940 get_postcondition_result_parameter (tree d)
942 if (!d || d == error_mark_node)
943 return NULL_TREE;
945 if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (d))))
946 return NULL_TREE;
948 tree post = DECL_POST_FN (d);
949 if (!post || post == error_mark_node)
950 return NULL_TREE;
952 for (tree arg = DECL_ARGUMENTS (post); arg; arg = TREE_CHAIN (arg))
953 if (!TREE_CHAIN (arg))
954 return arg;
956 return NULL_TREE;
960 /* For use with the tree inliner. This preserves non-mapped local variables,
961 such as postcondition result variables, during remapping. */
963 static tree
964 retain_decl (tree decl, copy_body_data *)
966 return decl;
969 /* Rewrite the condition of contract in place, so that references to SRC's
970 parameters are updated to refer to DST's parameters. The postcondition
971 result variable is left unchanged.
973 This, along with remap_contracts, are subroutines of duplicate_decls.
974 When declarations are merged, we sometimes need to update contracts to
975 refer to new parameters.
977 If DUPLICATE_P is true, this is called by duplicate_decls to rewrite contacts
978 in terms of a new set of parameters. In this case, we can retain local
979 variables appearing in the contract because the contract is not being
980 prepared for insertion into a new function. Importantly, this preserves the
981 references to postcondition results, which are not replaced during merging.
983 If false, we're preparing to emit the contract condition into the body
984 of a new function, so we need to make copies of all local variables
985 appearing in the contract (e.g., if it includes a lambda expression). Note
986 that in this case, postcondition results are mapped to the last parameter
987 of DST.
989 This is also used to reuse a parent type's contracts on virtual methods. */
991 static void
992 remap_contract (tree src, tree dst, tree contract, bool duplicate_p)
994 copy_body_data id;
995 hash_map<tree, tree> decl_map;
997 memset (&id, 0, sizeof (id));
998 id.src_fn = src;
999 id.dst_fn = dst;
1000 id.src_cfun = DECL_STRUCT_FUNCTION (src);
1001 id.decl_map = &decl_map;
1003 /* If we're merging contracts, don't copy local variables. */
1004 id.copy_decl = duplicate_p ? retain_decl : copy_decl_no_change;
1006 id.transform_call_graph_edges = CB_CGE_DUPLICATE;
1007 id.transform_new_cfg = false;
1008 id.transform_return_to_modify = false;
1009 id.transform_parameter = true;
1011 /* Make sure not to unshare trees behind the front-end's back
1012 since front-end specific mechanisms may rely on sharing. */
1013 id.regimplify = false;
1014 id.do_not_unshare = true;
1015 id.do_not_fold = true;
1017 /* We're not inside any EH region. */
1018 id.eh_lp_nr = 0;
1020 bool do_remap = false;
1022 /* Insert parameter remappings. */
1023 if (TREE_CODE (src) == FUNCTION_DECL)
1024 src = DECL_ARGUMENTS (src);
1025 if (TREE_CODE (dst) == FUNCTION_DECL)
1026 dst = DECL_ARGUMENTS (dst);
1028 for (tree sp = src, dp = dst;
1029 sp || dp;
1030 sp = DECL_CHAIN (sp), dp = DECL_CHAIN (dp))
1032 if (!sp && dp
1033 && TREE_CODE (contract) == POSTCONDITION_STMT
1034 && DECL_CHAIN (dp) == NULL_TREE)
1036 gcc_assert (!duplicate_p);
1037 if (tree result = POSTCONDITION_IDENTIFIER (contract))
1039 gcc_assert (DECL_P (result));
1040 insert_decl_map (&id, result, dp);
1041 do_remap = true;
1043 break;
1045 gcc_assert (sp && dp);
1047 if (sp == dp)
1048 continue;
1050 insert_decl_map (&id, sp, dp);
1051 do_remap = true;
1053 if (!do_remap)
1054 return;
1056 walk_tree (&CONTRACT_CONDITION (contract), copy_tree_body_r, &id, NULL);
1059 /* Rewrite any references to SRC's PARM_DECLs to the corresponding PARM_DECL in
1060 DST in all of the contract attributes in CONTRACTS by calling remap_contract
1061 on each.
1063 This is used for two purposes: to rewrite contract attributes during
1064 duplicate_decls, and to prepare contracts for emission into a function's
1065 respective precondition and postcondition functions. DUPLICATE_P is used
1066 to determine the context in which this function is called. See above for
1067 the behavior described by this flag. */
1069 void
1070 remap_contracts (tree src, tree dst, tree contracts, bool duplicate_p)
1072 for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
1074 if (!cxx_contract_attribute_p (attr))
1075 continue;
1076 tree contract = CONTRACT_STATEMENT (attr);
1077 if (TREE_CODE (CONTRACT_CONDITION (contract)) != DEFERRED_PARSE)
1078 remap_contract (src, dst, contract, duplicate_p);
1082 /* Helper to replace references to dummy this parameters with references to
1083 the first argument of the FUNCTION_DECL DATA. */
1085 static tree
1086 remap_dummy_this_1 (tree *tp, int *, void *data)
1088 if (!is_this_parameter (*tp))
1089 return NULL_TREE;
1090 tree fn = (tree)data;
1091 *tp = DECL_ARGUMENTS (fn);
1092 return NULL_TREE;
1095 /* Replace all references to dummy this parameters in EXPR with references to
1096 the first argument of the FUNCTION_DECL FN. */
1098 static void
1099 remap_dummy_this (tree fn, tree *expr)
1101 walk_tree (expr, remap_dummy_this_1, fn, NULL);
1104 /* Contract matching. */
1106 /* True if the contract is valid. */
1108 static bool
1109 contract_valid_p (tree contract)
1111 return CONTRACT_CONDITION (contract) != error_mark_node;
1114 /* True if the contract attribute is valid. */
1116 static bool
1117 contract_attribute_valid_p (tree attribute)
1119 return contract_valid_p (TREE_VALUE (TREE_VALUE (attribute)));
1122 /* Compare the contract conditions of OLD_ATTR and NEW_ATTR. Returns false
1123 if the conditions are equivalent, and true otherwise. */
1125 static bool
1126 check_for_mismatched_contracts (tree old_attr, tree new_attr,
1127 contract_matching_context ctx)
1129 tree old_contract = CONTRACT_STATEMENT (old_attr);
1130 tree new_contract = CONTRACT_STATEMENT (new_attr);
1132 /* Different kinds of contracts do not match. */
1133 if (TREE_CODE (old_contract) != TREE_CODE (new_contract))
1135 auto_diagnostic_group d;
1136 error_at (EXPR_LOCATION (new_contract),
1137 ctx == cmc_declaration
1138 ? "mismatched contract attribute in declaration"
1139 : "mismatched contract attribute in override");
1140 inform (EXPR_LOCATION (old_contract), "previous contract here");
1141 return true;
1144 /* A deferred contract tentatively matches. */
1145 if (CONTRACT_CONDITION_DEFERRED_P (new_contract))
1146 return false;
1148 /* Compare the conditions of the contracts. We fold immediately to avoid
1149 issues comparing contracts on overrides that use parameters -- see
1150 contracts-pre3. */
1151 tree t1 = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
1152 tree t2 = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
1154 /* Compare the contracts. The fold doesn't eliminate conversions to members.
1155 Set the comparing_override_contracts flag to ensure that references
1156 through 'this' are equal if they designate the same member, regardless of
1157 the path those members. */
1158 bool saved_comparing_contracts = comparing_override_contracts;
1159 comparing_override_contracts = (ctx == cmc_override);
1160 bool matching_p = cp_tree_equal (t1, t2);
1161 comparing_override_contracts = saved_comparing_contracts;
1163 if (!matching_p)
1165 auto_diagnostic_group d;
1166 error_at (EXPR_LOCATION (CONTRACT_CONDITION (new_contract)),
1167 ctx == cmc_declaration
1168 ? "mismatched contract condition in declaration"
1169 : "mismatched contract condition in override");
1170 inform (EXPR_LOCATION (CONTRACT_CONDITION (old_contract)),
1171 "previous contract here");
1172 return true;
1175 return false;
1178 /* Compare the contract attributes of OLDDECL and NEWDECL. Returns true
1179 if the contracts match, and false if they differ. */
1181 bool
1182 match_contract_conditions (location_t oldloc, tree old_attrs,
1183 location_t newloc, tree new_attrs,
1184 contract_matching_context ctx)
1186 /* Contracts only match if they are both specified. */
1187 if (!old_attrs || !new_attrs)
1188 return true;
1190 /* Compare each contract in turn. */
1191 while (old_attrs && new_attrs)
1193 /* If either contract is ill-formed, skip the rest of the comparison,
1194 since we've already diagnosed an error. */
1195 if (!contract_attribute_valid_p (new_attrs)
1196 || !contract_attribute_valid_p (old_attrs))
1197 return false;
1199 if (check_for_mismatched_contracts (old_attrs, new_attrs, ctx))
1200 return false;
1201 old_attrs = CONTRACT_CHAIN (old_attrs);
1202 new_attrs = CONTRACT_CHAIN (new_attrs);
1205 /* If we didn't compare all attributes, the contracts don't match. */
1206 if (old_attrs || new_attrs)
1208 auto_diagnostic_group d;
1209 error_at (newloc,
1210 ctx == cmc_declaration
1211 ? "declaration has a different number of contracts than "
1212 "previously declared"
1213 : "override has a different number of contracts than "
1214 "previously declared");
1215 inform (oldloc,
1216 new_attrs
1217 ? "original declaration with fewer contracts here"
1218 : "original declaration with more contracts here");
1219 return false;
1222 return true;
1225 /* Deferred contract mapping.
1227 This is used to compare late-parsed contracts on overrides with their
1228 base class functions.
1230 TODO: It seems like this could be replaced by a simple list that maps from
1231 overrides to their base functions. It's not clear that we really need
1232 a map to a function + a list of contracts. */
1234 /* Map from FNDECL to a tree list of contracts that have not been matched or
1235 diagnosed yet. The TREE_PURPOSE is the basefn we're overriding, and the
1236 TREE_VALUE is the list of contract attrs for BASEFN. */
1238 static hash_map<tree_decl_hash, tree> pending_guarded_decls;
1240 void
1241 defer_guarded_contract_match (tree fndecl, tree fn, tree contracts)
1243 if (!pending_guarded_decls.get (fndecl))
1245 pending_guarded_decls.put (fndecl, build_tree_list (fn, contracts));
1246 return;
1248 for (tree pending = *pending_guarded_decls.get (fndecl);
1249 pending;
1250 pending = TREE_CHAIN (pending))
1252 if (TREE_VALUE (pending) == contracts)
1253 return;
1254 if (TREE_CHAIN (pending) == NULL_TREE)
1255 TREE_CHAIN (pending) = build_tree_list (fn, contracts);
1259 /* If the FUNCTION_DECL DECL has any contracts that had their matching
1260 deferred earlier, do that checking now. */
1262 void
1263 match_deferred_contracts (tree decl)
1265 tree *tp = pending_guarded_decls.get (decl);
1266 if (!tp)
1267 return;
1269 gcc_assert(!contract_any_deferred_p (DECL_CONTRACTS (decl)));
1271 processing_template_decl_sentinel ptds;
1272 processing_template_decl = uses_template_parms (decl);
1274 /* Do late contract matching. */
1275 for (tree pending = *tp; pending; pending = TREE_CHAIN (pending))
1277 tree new_contracts = TREE_VALUE (pending);
1278 location_t new_loc = CONTRACT_SOURCE_LOCATION (new_contracts);
1279 tree old_contracts = DECL_CONTRACTS (decl);
1280 location_t old_loc = CONTRACT_SOURCE_LOCATION (old_contracts);
1281 tree base = TREE_PURPOSE (pending);
1282 match_contract_conditions (new_loc, new_contracts,
1283 old_loc, old_contracts,
1284 base ? cmc_override : cmc_declaration);
1287 /* Clear out deferred match list so we don't check it twice. */
1288 pending_guarded_decls.remove (decl);
1291 /* Map from FUNCTION_DECL to a FUNCTION_DECL for either the PRE_FN or POST_FN.
1292 These are used to parse contract conditions and are called inside the body
1293 of the guarded function. */
1294 static GTY(()) hash_map<tree, tree> *decl_pre_fn;
1295 static GTY(()) hash_map<tree, tree> *decl_post_fn;
1297 /* Returns the precondition funtion for D, or null if not set. */
1299 tree
1300 get_precondition_function (tree d)
1302 hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1303 tree *result = decl_pre_fn->get (d);
1304 return result ? *result : NULL_TREE;
1307 /* Returns the postcondition funtion for D, or null if not set. */
1309 tree
1310 get_postcondition_function (tree d)
1312 hash_map_maybe_create<hm_ggc> (decl_post_fn);
1313 tree *result = decl_post_fn->get (d);
1314 return result ? *result : NULL_TREE;
1317 /* Makes PRE the precondition function for D. */
1319 void
1320 set_precondition_function (tree d, tree pre)
1322 gcc_assert (pre);
1323 hash_map_maybe_create<hm_ggc> (decl_pre_fn);
1324 gcc_assert (!decl_pre_fn->get (d));
1325 decl_pre_fn->put (d, pre);
1328 /* Makes POST the postcondition function for D. */
1330 void
1331 set_postcondition_function (tree d, tree post)
1333 gcc_assert (post);
1334 hash_map_maybe_create<hm_ggc> (decl_post_fn);
1335 gcc_assert (!decl_post_fn->get (d));
1336 decl_post_fn->put (d, post);
1339 /* Set the PRE and POST functions for D. Note that PRE and POST can be
1340 null in this case. If so the functions are not recorded. */
1342 void
1343 set_contract_functions (tree d, tree pre, tree post)
1345 if (pre)
1346 set_precondition_function (d, pre);
1347 if (post)
1348 set_postcondition_function (d, post);
1351 /* Return a copy of the FUNCTION_DECL IDECL with its own unshared
1352 PARM_DECL and DECL_ATTRIBUTEs. */
1354 static tree
1355 copy_fn_decl (tree idecl)
1357 tree decl = copy_decl (idecl);
1358 DECL_ATTRIBUTES (decl) = copy_list (DECL_ATTRIBUTES (idecl));
1360 if (DECL_RESULT (idecl))
1362 DECL_RESULT (decl) = copy_decl (DECL_RESULT (idecl));
1363 DECL_CONTEXT (DECL_RESULT (decl)) = decl;
1365 if (!DECL_ARGUMENTS (idecl) || VOID_TYPE_P (DECL_ARGUMENTS (idecl)))
1366 return decl;
1368 tree last = DECL_ARGUMENTS (decl) = copy_decl (DECL_ARGUMENTS (decl));
1369 DECL_CONTEXT (last) = decl;
1370 for (tree p = TREE_CHAIN (DECL_ARGUMENTS (idecl)); p; p = TREE_CHAIN (p))
1372 if (VOID_TYPE_P (p))
1374 TREE_CHAIN (last) = void_list_node;
1375 break;
1377 last = TREE_CHAIN (last) = copy_decl (p);
1378 DECL_CONTEXT (last) = decl;
1380 return decl;
1383 /* Build a declaration for the pre- or postcondition of a guarded FNDECL. */
1385 static tree
1386 build_contract_condition_function (tree fndecl, bool pre)
1388 if (TREE_TYPE (fndecl) == error_mark_node)
1389 return error_mark_node;
1390 if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
1391 && !TYPE_METHOD_BASETYPE (TREE_TYPE (fndecl)))
1392 return error_mark_node;
1394 /* Create and rename the unchecked function and give an internal name. */
1395 tree fn = copy_fn_decl (fndecl);
1396 DECL_RESULT (fn) = NULL_TREE;
1397 tree value_type = pre ? void_type_node : TREE_TYPE (TREE_TYPE (fn));
1399 /* Don't propagate declaration attributes to the checking function,
1400 including the original contracts. */
1401 DECL_ATTRIBUTES (fn) = NULL_TREE;
1403 tree arg_types = NULL_TREE;
1404 tree *last = &arg_types;
1406 /* FIXME will later optimizations delete unused args to prevent extra arg
1407 passing? do we care? */
1408 tree class_type = NULL_TREE;
1409 for (tree arg_type = TYPE_ARG_TYPES (TREE_TYPE (fn));
1410 arg_type && arg_type != void_list_node;
1411 arg_type = TREE_CHAIN (arg_type))
1413 if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
1414 && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type)
1416 class_type = TREE_TYPE (TREE_VALUE (arg_type));
1417 continue;
1419 *last = build_tree_list (TREE_PURPOSE (arg_type), TREE_VALUE (arg_type));
1420 last = &TREE_CHAIN (*last);
1423 if (pre || VOID_TYPE_P (value_type))
1424 *last = void_list_node;
1425 else
1427 tree name = get_identifier ("__r");
1428 tree parm = build_lang_decl (PARM_DECL, name, value_type);
1429 DECL_CONTEXT (parm) = fn;
1430 DECL_ARTIFICIAL (parm) = true;
1431 DECL_ARGUMENTS (fn) = chainon (DECL_ARGUMENTS (fn), parm);
1433 *last = build_tree_list (NULL_TREE, value_type);
1434 TREE_CHAIN (*last) = void_list_node;
1436 /* The handler is a void return. */
1437 value_type = void_type_node;
1440 TREE_TYPE (fn) = build_function_type (value_type, arg_types);
1441 if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl))
1442 TREE_TYPE (fn) = build_method_type (class_type, TREE_TYPE (fn));
1444 DECL_NAME (fn) = copy_node (DECL_NAME (fn));
1445 DECL_INITIAL (fn) = error_mark_node;
1446 DECL_ABSTRACT_ORIGIN (fn) = fndecl;
1448 IDENTIFIER_VIRTUAL_P (DECL_NAME (fn)) = false;
1449 DECL_VIRTUAL_P (fn) = false;
1451 /* Make these functions internal if we can, i.e. if the guarded function is
1452 not vague linkage, or if we can put them in a comdat group with the
1453 guarded function. */
1454 if (!DECL_WEAK (fndecl) || HAVE_COMDAT_GROUP)
1456 TREE_PUBLIC (fn) = false;
1457 DECL_EXTERNAL (fn) = false;
1458 DECL_WEAK (fn) = false;
1459 DECL_COMDAT (fn) = false;
1461 /* We haven't set the comdat group on the guarded function yet, we'll add
1462 this to the same group in comdat_linkage later. */
1463 gcc_assert (!DECL_ONE_ONLY (fndecl));
1465 DECL_INTERFACE_KNOWN (fn) = true;
1468 DECL_ARTIFICIAL (fn) = true;
1470 /* Update various inline related declaration properties. */
1471 //DECL_DECLARED_INLINE_P (fn) = true;
1472 DECL_DISREGARD_INLINE_LIMITS (fn) = true;
1473 TREE_NO_WARNING (fn) = 1;
1475 return fn;
1478 /* Return true if CONTRACT is checked or assumed under the current build
1479 configuration. */
1481 bool
1482 contract_active_p (tree contract)
1484 return get_contract_semantic (contract) != CCS_IGNORE;
1487 static bool
1488 has_active_contract_condition (tree d, tree_code c)
1490 for (tree as = DECL_CONTRACTS (d) ; as != NULL_TREE; as = TREE_CHAIN (as))
1492 tree contract = TREE_VALUE (TREE_VALUE (as));
1493 if (TREE_CODE (contract) == c && contract_active_p (contract))
1494 return true;
1496 return false;
1499 /* True if D has any checked or assumed preconditions. */
1501 static bool
1502 has_active_preconditions (tree d)
1504 return has_active_contract_condition (d, PRECONDITION_STMT);
1507 /* True if D has any checked or assumed postconditions. */
1509 static bool
1510 has_active_postconditions (tree d)
1512 return has_active_contract_condition (d, POSTCONDITION_STMT);
1515 /* Return true if any contract in the CONTRACT list is checked or assumed
1516 under the current build configuration. */
1518 bool
1519 contract_any_active_p (tree contract)
1521 for (; contract != NULL_TREE; contract = CONTRACT_CHAIN (contract))
1522 if (contract_active_p (TREE_VALUE (TREE_VALUE (contract))))
1523 return true;
1524 return false;
1527 /* Do we need to mess with contracts for DECL1? */
1529 static bool
1530 handle_contracts_p (tree decl1)
1532 return (flag_contracts
1533 && !processing_template_decl
1534 && DECL_ABSTRACT_ORIGIN (decl1) == NULL_TREE
1535 && contract_any_active_p (DECL_CONTRACTS (decl1)));
1538 /* Should we break out DECL1's pre/post contracts into separate functions?
1539 FIXME I'd like this to default to 0, but that will need an overhaul to the
1540 return identifier handling to just refer to the RESULT_DECL. */
1542 static bool
1543 outline_contracts_p (tree decl1)
1545 return (!DECL_CONSTRUCTOR_P (decl1)
1546 && !DECL_DESTRUCTOR_P (decl1));
1549 /* Build the precondition checking function for D. */
1551 static tree
1552 build_precondition_function (tree d)
1554 if (!has_active_preconditions (d))
1555 return NULL_TREE;
1557 return build_contract_condition_function (d, /*pre=*/true);
1560 /* Build the postcondition checking function for D. If the return
1561 type is undeduced, don't build the function yet. We do that in
1562 apply_deduced_return_type. */
1564 static tree
1565 build_postcondition_function (tree d)
1567 if (!has_active_postconditions (d))
1568 return NULL_TREE;
1570 tree type = TREE_TYPE (TREE_TYPE (d));
1571 if (is_auto (type))
1572 return NULL_TREE;
1574 return build_contract_condition_function (d, /*pre=*/false);
1577 static void
1578 build_contract_function_decls (tree d)
1580 /* Constructors and destructors have their contracts inserted inline. */
1581 if (!outline_contracts_p (d))
1582 return;
1584 /* Build the pre/post functions (or not). */
1585 tree pre = build_precondition_function (d);
1586 tree post = build_postcondition_function (d);
1587 set_contract_functions (d, pre, post);
1590 static const char *
1591 get_contract_level_name (tree contract)
1593 if (CONTRACT_LITERAL_MODE_P (contract))
1594 return "";
1595 if (tree mode = CONTRACT_MODE (contract))
1596 if (tree level = TREE_VALUE (mode))
1597 return IDENTIFIER_POINTER (level);
1598 return "default";
1601 static const char *
1602 get_contract_role_name (tree contract)
1604 if (CONTRACT_LITERAL_MODE_P (contract))
1605 return "";
1606 if (tree mode = CONTRACT_MODE (contract))
1607 if (tree role = TREE_PURPOSE (mode))
1608 return IDENTIFIER_POINTER (role);
1609 return "default";
1612 /* Build a layout-compatible internal version of std::contract_violation. */
1614 static tree
1615 get_pseudo_contract_violation_type ()
1617 if (!pseudo_contract_violation_type)
1619 /* Must match <contract>:
1620 class contract_violation {
1621 const char* _M_file;
1622 const char* _M_function;
1623 const char* _M_comment;
1624 const char* _M_level;
1625 const char* _M_role;
1626 uint_least32_t _M_line;
1627 signed char _M_continue;
1628 If this changes, also update the initializer in
1629 build_contract_violation. */
1630 const tree types[] = { const_string_type_node,
1631 const_string_type_node,
1632 const_string_type_node,
1633 const_string_type_node,
1634 const_string_type_node,
1635 uint_least32_type_node,
1636 signed_char_type_node };
1637 tree fields = NULL_TREE;
1638 for (tree type : types)
1640 /* finish_builtin_struct wants fieldss chained in reverse. */
1641 tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1642 NULL_TREE, type);
1643 DECL_CHAIN (next) = fields;
1644 fields = next;
1646 iloc_sentinel ils (input_location);
1647 input_location = BUILTINS_LOCATION;
1648 pseudo_contract_violation_type = make_class_type (RECORD_TYPE);
1649 finish_builtin_struct (pseudo_contract_violation_type,
1650 "__pseudo_contract_violation",
1651 fields, NULL_TREE);
1652 CLASSTYPE_AS_BASE (pseudo_contract_violation_type)
1653 = pseudo_contract_violation_type;
1654 DECL_CONTEXT (TYPE_NAME (pseudo_contract_violation_type))
1655 = FROB_CONTEXT (global_namespace);
1656 TREE_PUBLIC (TYPE_NAME (pseudo_contract_violation_type)) = true;
1657 CLASSTYPE_LITERAL_P (pseudo_contract_violation_type) = true;
1658 CLASSTYPE_LAZY_COPY_CTOR (pseudo_contract_violation_type) = true;
1659 xref_basetypes (pseudo_contract_violation_type, /*bases=*/NULL_TREE);
1660 pseudo_contract_violation_type
1661 = cp_build_qualified_type (pseudo_contract_violation_type,
1662 TYPE_QUAL_CONST);
1664 return pseudo_contract_violation_type;
1667 /* Return a VAR_DECL to pass to handle_contract_violation. */
1669 static tree
1670 build_contract_violation (tree contract, contract_continuation cmode)
1672 expanded_location loc = expand_location (EXPR_LOCATION (contract));
1673 const char *function = fndecl_name (DECL_ORIGIN (current_function_decl));
1674 const char *level = get_contract_level_name (contract);
1675 const char *role = get_contract_role_name (contract);
1677 /* Must match the type layout in get_pseudo_contract_violation_type. */
1678 tree ctor = build_constructor_va
1679 (init_list_type_node, 7,
1680 NULL_TREE, build_string_literal (loc.file),
1681 NULL_TREE, build_string_literal (function),
1682 NULL_TREE, CONTRACT_COMMENT (contract),
1683 NULL_TREE, build_string_literal (level),
1684 NULL_TREE, build_string_literal (role),
1685 NULL_TREE, build_int_cst (uint_least32_type_node, loc.line),
1686 NULL_TREE, build_int_cst (signed_char_type_node, cmode));
1688 ctor = finish_compound_literal (get_pseudo_contract_violation_type (),
1689 ctor, tf_none);
1690 protected_set_expr_location (ctor, EXPR_LOCATION (contract));
1691 return ctor;
1694 /* Return handle_contract_violation(), declaring it if needed. */
1696 static tree
1697 declare_handle_contract_violation ()
1699 tree fnname = get_identifier ("handle_contract_violation");
1700 tree viol_name = get_identifier ("contract_violation");
1701 tree l = lookup_qualified_name (global_namespace, fnname,
1702 LOOK_want::HIDDEN_FRIEND);
1703 for (tree f: lkp_range (l))
1704 if (TREE_CODE (f) == FUNCTION_DECL)
1706 tree parms = TYPE_ARG_TYPES (TREE_TYPE (f));
1707 if (remaining_arguments (parms) != 1)
1708 continue;
1709 tree parmtype = non_reference (TREE_VALUE (parms));
1710 if (CLASS_TYPE_P (parmtype)
1711 && TYPE_IDENTIFIER (parmtype) == viol_name)
1712 return f;
1715 tree id_exp = get_identifier ("experimental");
1716 tree ns_exp = lookup_qualified_name (std_node, id_exp);
1718 tree violation = error_mark_node;
1719 if (TREE_CODE (ns_exp) == NAMESPACE_DECL)
1720 violation = lookup_qualified_name (ns_exp, viol_name,
1721 LOOK_want::TYPE
1722 |LOOK_want::HIDDEN_FRIEND);
1724 if (TREE_CODE (violation) == TYPE_DECL)
1725 violation = TREE_TYPE (violation);
1726 else
1728 push_nested_namespace (std_node);
1729 push_namespace (id_exp, /*inline*/false);
1730 violation = make_class_type (RECORD_TYPE);
1731 create_implicit_typedef (viol_name, violation);
1732 DECL_SOURCE_LOCATION (TYPE_NAME (violation)) = BUILTINS_LOCATION;
1733 DECL_CONTEXT (TYPE_NAME (violation)) = current_namespace;
1734 pushdecl_namespace_level (TYPE_NAME (violation), /*hidden*/true);
1735 pop_namespace ();
1736 pop_nested_namespace (std_node);
1739 tree argtype = cp_build_qualified_type (violation, TYPE_QUAL_CONST);
1740 argtype = cp_build_reference_type (argtype, /*rval*/false);
1741 tree fntype = build_function_type_list (void_type_node, argtype, NULL_TREE);
1743 push_nested_namespace (global_namespace);
1744 tree fn = build_cp_library_fn_ptr ("handle_contract_violation", fntype,
1745 ECF_COLD);
1746 pushdecl_namespace_level (fn, /*hiding*/true);
1747 pop_nested_namespace (global_namespace);
1749 return fn;
1752 /* Build the call to handle_contract_violation for CONTRACT. */
1754 static void
1755 build_contract_handler_call (tree contract,
1756 contract_continuation cmode)
1758 tree violation = build_contract_violation (contract, cmode);
1759 tree violation_fn = declare_handle_contract_violation ();
1760 tree call = build_call_n (violation_fn, 1, build_address (violation));
1761 finish_expr_stmt (call);
1764 /* Generate the code that checks or assumes a contract, but do not attach
1765 it to the current context. This is called during genericization. */
1767 tree
1768 build_contract_check (tree contract)
1770 contract_semantic semantic = get_contract_semantic (contract);
1771 if (semantic == CCS_INVALID)
1772 return NULL_TREE;
1774 /* Ignored contracts are never checked or assumed. */
1775 if (semantic == CCS_IGNORE)
1776 return void_node;
1778 remap_dummy_this (current_function_decl, &CONTRACT_CONDITION (contract));
1779 tree condition = CONTRACT_CONDITION (contract);
1780 if (condition == error_mark_node)
1781 return NULL_TREE;
1783 location_t loc = EXPR_LOCATION (contract);
1785 if (semantic == CCS_ASSUME)
1786 return build_assume_call (loc, condition);
1788 tree if_stmt = begin_if_stmt ();
1789 tree cond = build_x_unary_op (loc,
1790 TRUTH_NOT_EXPR,
1791 condition, NULL_TREE,
1792 tf_warning_or_error);
1793 finish_if_stmt_cond (cond, if_stmt);
1795 /* Get the continuation mode. */
1796 contract_continuation cmode;
1797 switch (semantic)
1799 case CCS_NEVER: cmode = NEVER_CONTINUE; break;
1800 case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
1801 default: gcc_unreachable ();
1804 build_contract_handler_call (contract, cmode);
1805 if (cmode == NEVER_CONTINUE)
1806 finish_expr_stmt (build_call_a (terminate_fn, 0, nullptr));
1808 finish_then_clause (if_stmt);
1809 tree scope = IF_SCOPE (if_stmt);
1810 IF_SCOPE (if_stmt) = NULL;
1811 return do_poplevel (scope);
1814 /* Add the contract statement CONTRACT to the current block if valid. */
1816 static void
1817 emit_contract_statement (tree contract)
1819 /* Only add valid contracts. */
1820 if (get_contract_semantic (contract) != CCS_INVALID
1821 && CONTRACT_CONDITION (contract) != error_mark_node)
1822 add_stmt (contract);
1825 /* Generate the statement for the given contract attribute by adding the
1826 statement to the current block. Returns the next contract in the chain. */
1828 static tree
1829 emit_contract_attr (tree attr)
1831 gcc_assert (TREE_CODE (attr) == TREE_LIST);
1833 emit_contract_statement (CONTRACT_STATEMENT (attr));
1835 return CONTRACT_CHAIN (attr);
1838 /* Add the statements of contract attributes ATTRS to the current block. */
1840 static void
1841 emit_contract_conditions (tree attrs, tree_code code)
1843 if (!attrs) return;
1844 gcc_assert (TREE_CODE (attrs) == TREE_LIST);
1845 gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1846 while (attrs)
1848 tree contract = CONTRACT_STATEMENT (attrs);
1849 if (TREE_CODE (contract) == code)
1850 attrs = emit_contract_attr (attrs);
1851 else
1852 attrs = CONTRACT_CHAIN (attrs);
1856 /* Emit the statement for an assertion attribute. */
1858 void
1859 emit_assertion (tree attr)
1861 emit_contract_attr (attr);
1864 /* Emit statements for precondition attributes. */
1866 static void
1867 emit_preconditions (tree attr)
1869 return emit_contract_conditions (attr, PRECONDITION_STMT);
1872 /* Emit statements for postcondition attributes. */
1874 static void
1875 emit_postconditions (tree attr)
1877 return emit_contract_conditions (attr, POSTCONDITION_STMT);
1880 /* We're compiling the pre/postcondition function CONDFN; remap any FN
1881 attributes that match CODE and emit them. */
1883 static void
1884 remap_and_emit_conditions (tree fn, tree condfn, tree_code code)
1886 gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
1887 for (tree attr = DECL_CONTRACTS (fn); attr;
1888 attr = CONTRACT_CHAIN (attr))
1890 tree contract = CONTRACT_STATEMENT (attr);
1891 if (TREE_CODE (contract) == code)
1893 contract = copy_node (contract);
1894 remap_contract (fn, condfn, contract, /*duplicate_p=*/false);
1895 emit_contract_statement (contract);
1900 /* Converts a contract condition to bool and ensures it has a locaiton. */
1902 tree
1903 finish_contract_condition (cp_expr condition)
1905 /* Ensure we have the condition location saved in case we later need to
1906 emit a conversion error during template instantiation and wouldn't
1907 otherwise have it. */
1908 if (!CAN_HAVE_LOCATION_P (condition) || EXCEPTIONAL_CLASS_P (condition))
1910 condition = build1_loc (condition.get_location (), VIEW_CONVERT_EXPR,
1911 TREE_TYPE (condition), condition);
1912 EXPR_LOCATION_WRAPPER_P (condition) = 1;
1915 if (condition == error_mark_node || type_dependent_expression_p (condition))
1916 return condition;
1918 return condition_conversion (condition);
1921 void
1922 maybe_update_postconditions (tree fco)
1924 /* Update any postconditions and the postcondition checking function
1925 as needed. If there are postconditions, we'll use those to rewrite
1926 return statements to check postconditions. */
1927 if (has_active_postconditions (fco))
1929 rebuild_postconditions (fco);
1930 tree post = build_postcondition_function (fco);
1931 set_postcondition_function (fco, post);
1935 /* Called on attribute lists that must not contain contracts. If any
1936 contracts are present, issue an error diagnostic and return true. */
1938 bool
1939 diagnose_misapplied_contracts (tree attributes)
1941 if (attributes == NULL_TREE)
1942 return false;
1944 tree contract_attr = find_contract (attributes);
1945 if (!contract_attr)
1946 return false;
1948 error_at (EXPR_LOCATION (CONTRACT_STATEMENT (contract_attr)),
1949 "contracts must appertain to a function type");
1951 /* Invalidate the contract so we don't treat it as valid later on. */
1952 invalidate_contract (TREE_VALUE (TREE_VALUE (contract_attr)));
1954 return true;
1957 /* Build and return an argument list containing all the parameters of the
1958 (presumably guarded) FUNCTION_DECL FN. This can be used to forward all of
1959 FN's arguments to a function taking the same list of arguments -- namely
1960 the unchecked form of FN.
1962 We use CALL_FROM_THUNK_P instead of forward_parm for forwarding
1963 semantics. */
1965 static vec<tree, va_gc> *
1966 build_arg_list (tree fn)
1968 vec<tree, va_gc> *args = make_tree_vector ();
1969 for (tree t = DECL_ARGUMENTS (fn); t; t = DECL_CHAIN (t))
1970 vec_safe_push (args, t);
1971 return args;
1974 void
1975 start_function_contracts (tree decl1)
1977 if (!handle_contracts_p (decl1))
1978 return;
1980 /* For cdtors, we evaluate the contracts check inline. */
1981 if (!outline_contracts_p (decl1))
1982 return;
1984 /* Contracts may have just been added without a chance to parse them, though
1985 we still need the PRE_FN available to generate a call to it. */
1986 if (!DECL_PRE_FN (decl1))
1987 build_contract_function_decls (decl1);
1991 /* If we have a precondition function and it's valid, call it. */
1993 static void
1994 add_pre_condition_fn_call (tree fndecl)
1996 /* If we're starting a guarded function with valid contracts, we need to
1997 insert a call to the pre function. */
1998 gcc_checking_assert (DECL_PRE_FN (fndecl)
1999 && DECL_PRE_FN (fndecl) != error_mark_node);
2001 releasing_vec args = build_arg_list (fndecl);
2002 tree call = build_call_a (DECL_PRE_FN (fndecl), args->length (),
2003 args->address ());
2004 CALL_FROM_THUNK_P (call) = true;
2005 finish_expr_stmt (call);
2008 /* Build and add a call to the post-condition checking function, when that
2009 is in use. */
2011 static void
2012 add_post_condition_fn_call (tree fndecl)
2014 gcc_checking_assert (DECL_POST_FN (fndecl)
2015 && DECL_POST_FN (fndecl) != error_mark_node);
2017 releasing_vec args = build_arg_list (fndecl);
2018 if (get_postcondition_result_parameter (fndecl))
2019 vec_safe_push (args, DECL_RESULT (fndecl));
2020 tree call = build_call_a (DECL_POST_FN (fndecl), args->length (),
2021 args->address ());
2022 CALL_FROM_THUNK_P (call) = true;
2023 finish_expr_stmt (call);
2026 /* Add a call or a direct evaluation of the pre checks. */
2028 static void
2029 apply_preconditions (tree fndecl)
2031 if (outline_contracts_p (fndecl))
2032 add_pre_condition_fn_call (fndecl);
2033 else
2034 emit_preconditions (DECL_CONTRACTS (fndecl));
2037 /* Add a call or a direct evaluation of the post checks. */
2039 static void
2040 apply_postconditions (tree fndecl)
2042 if (outline_contracts_p (fndecl))
2043 add_post_condition_fn_call (fndecl);
2044 else
2045 emit_postconditions (DECL_CONTRACTS (fndecl));
2048 /* Add contract handling to the function in FNDECL.
2050 When we have only pre-conditions, this simply prepends a call (or a direct
2051 evaluation, for cdtors) to the existing function body.
2053 When we have post conditions we build a try-finally block.
2054 If the function might throw then the handler in the try-finally is an
2055 EH_ELSE expression, where the post condition check is applied to the
2056 non-exceptional path, and an empty statement is added to the EH path. If
2057 the function has a non-throwing eh spec, then the handler is simply the
2058 post-condition checker. */
2060 void
2061 maybe_apply_function_contracts (tree fndecl)
2063 if (!handle_contracts_p (fndecl))
2064 /* We did nothing and the original function body statement list will be
2065 popped by our caller. */
2066 return;
2068 bool do_pre = has_active_preconditions (fndecl);
2069 bool do_post = has_active_postconditions (fndecl);
2070 /* We should not have reached here with nothing to do... */
2071 gcc_checking_assert (do_pre || do_post);
2073 /* This copies the approach used for function try blocks. */
2074 tree fnbody = pop_stmt_list (DECL_SAVED_TREE (fndecl));
2075 DECL_SAVED_TREE (fndecl) = push_stmt_list ();
2076 tree compound_stmt = begin_compound_stmt (0);
2077 current_binding_level->artificial = 1;
2079 /* Do not add locations for the synthesised code. */
2080 location_t loc = UNKNOWN_LOCATION;
2082 /* For other cases, we call a function to process the check. */
2084 /* If we have a pre, but not a post, then just emit that and we are done. */
2085 if (!do_post)
2087 apply_preconditions (fndecl);
2088 add_stmt (fnbody);
2089 finish_compound_stmt (compound_stmt);
2090 return;
2093 if (do_pre)
2094 /* Add a precondition call, if we have one. */
2095 apply_preconditions (fndecl);
2096 tree try_fin = build_stmt (loc, TRY_FINALLY_EXPR, fnbody, NULL_TREE);
2097 add_stmt (try_fin);
2098 TREE_OPERAND (try_fin, 1) = push_stmt_list ();
2099 /* If we have exceptions, and a function that might throw, then add
2100 an EH_ELSE clause that allows the exception to propagate upwards
2101 without encountering the post-condition checks. */
2102 if (flag_exceptions && !type_noexcept_p (TREE_TYPE (fndecl)))
2104 tree eh_else = build_stmt (loc, EH_ELSE_EXPR, NULL_TREE, NULL_TREE);
2105 add_stmt (eh_else);
2106 TREE_OPERAND (eh_else, 0) = push_stmt_list ();
2107 apply_postconditions (fndecl);
2108 TREE_OPERAND (eh_else, 0) = pop_stmt_list (TREE_OPERAND (eh_else, 0));
2109 TREE_OPERAND (eh_else, 1) = build_empty_stmt (loc);
2111 else
2112 apply_postconditions (fndecl);
2113 TREE_OPERAND (try_fin, 1) = pop_stmt_list (TREE_OPERAND (try_fin, 1));
2114 finish_compound_stmt (compound_stmt);
2115 /* The DECL_SAVED_TREE stmt list will be popped by our caller. */
2118 /* Finish up the pre & post function definitions for a guarded FNDECL,
2119 and compile those functions all the way to assembler language output. */
2121 void
2122 finish_function_contracts (tree fndecl)
2124 if (!handle_contracts_p (fndecl)
2125 || !outline_contracts_p (fndecl))
2126 return;
2128 for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
2130 tree contract = CONTRACT_STATEMENT (ca);
2131 if (!CONTRACT_CONDITION (contract)
2132 || CONTRACT_CONDITION_DEFERRED_P (contract)
2133 || CONTRACT_CONDITION (contract) == error_mark_node)
2134 return;
2137 int flags = SF_DEFAULT | SF_PRE_PARSED;
2139 /* If either the pre or post functions are bad, don't bother emitting
2140 any contracts. The program is already ill-formed. */
2141 tree pre = DECL_PRE_FN (fndecl);
2142 tree post = DECL_POST_FN (fndecl);
2143 if (pre == error_mark_node || post == error_mark_node)
2144 return;
2146 if (pre && DECL_INITIAL (fndecl) != error_mark_node)
2148 DECL_PENDING_INLINE_P (pre) = false;
2149 start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
2150 remap_and_emit_conditions (fndecl, pre, PRECONDITION_STMT);
2151 tree finished_pre = finish_function (false);
2152 expand_or_defer_fn (finished_pre);
2155 if (post && DECL_INITIAL (fndecl) != error_mark_node)
2157 DECL_PENDING_INLINE_P (post) = false;
2158 start_preparsed_function (post,
2159 DECL_ATTRIBUTES (post),
2160 flags);
2161 remap_and_emit_conditions (fndecl, post, POSTCONDITION_STMT);
2162 if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post))))
2163 finish_return_stmt (get_postcondition_result_parameter (fndecl));
2165 tree finished_post = finish_function (false);
2166 expand_or_defer_fn (finished_post);
2171 /* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
2172 guarded functions. */
2174 void
2175 duplicate_contracts (tree newdecl, tree olddecl)
2177 if (TREE_CODE (newdecl) == TEMPLATE_DECL)
2178 newdecl = DECL_TEMPLATE_RESULT (newdecl);
2179 if (TREE_CODE (olddecl) == TEMPLATE_DECL)
2180 olddecl = DECL_TEMPLATE_RESULT (olddecl);
2182 /* Compare contracts to see if they match. */
2183 tree old_contracts = DECL_CONTRACTS (olddecl);
2184 tree new_contracts = DECL_CONTRACTS (newdecl);
2186 if (!old_contracts && !new_contracts)
2187 return;
2189 location_t old_loc = DECL_SOURCE_LOCATION (olddecl);
2190 location_t new_loc = DECL_SOURCE_LOCATION (newdecl);
2192 /* If both declarations specify contracts, ensure they match.
2194 TODO: This handles a potential error a little oddly. Consider:
2196 struct B {
2197 virtual void f(int n) [[pre: n == 0]];
2199 struct D : B {
2200 void f(int n) override; // inherits contracts
2202 void D::f(int n) [[pre: n == 0]] // OK
2205 It's okay because we're explicitly restating the inherited contract.
2206 Changing the precondition on the definition D::f causes match_contracts
2207 to complain about the mismatch.
2209 This would previously have been diagnosed as adding contracts to an
2210 override, but this seems like it should be well-formed. */
2211 if (old_contracts && new_contracts)
2213 if (!match_contract_conditions (old_loc, old_contracts,
2214 new_loc, new_contracts,
2215 cmc_declaration))
2216 return;
2217 if (DECL_UNIQUE_FRIEND_P (newdecl))
2218 /* Newdecl's contracts are still DEFERRED_PARSE, and we're about to
2219 collapse it into olddecl, so stash away olddecl's contracts for
2220 later comparison. */
2221 defer_guarded_contract_match (olddecl, olddecl, old_contracts);
2224 /* Handle cases where contracts are omitted in one or the other
2225 declaration. */
2226 if (old_contracts)
2228 /* Contracts have been previously specified by are no omitted. The
2229 new declaration inherits the existing contracts. */
2230 if (!new_contracts)
2231 copy_contract_attributes (newdecl, olddecl);
2233 /* In all cases, remove existing contracts from OLDDECL to prevent the
2234 attribute merging function from adding excess contracts. */
2235 remove_contract_attributes (olddecl);
2237 else if (!old_contracts)
2239 /* We are adding contracts to a declaration. */
2240 if (new_contracts)
2242 /* We can't add to a previously defined function. */
2243 if (DECL_INITIAL (olddecl))
2245 auto_diagnostic_group d;
2246 error_at (new_loc, "cannot add contracts after definition");
2247 inform (DECL_SOURCE_LOCATION (olddecl), "original definition here");
2248 return;
2251 /* We can't add to an unguarded virtual function declaration. */
2252 if (DECL_VIRTUAL_P (olddecl) && new_contracts)
2254 auto_diagnostic_group d;
2255 error_at (new_loc, "cannot add contracts to a virtual function");
2256 inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here");
2257 return;
2260 /* Depending on the "first declaration" rule, we may not be able
2261 to add contracts to a function after the fact. */
2262 if (flag_contract_strict_declarations)
2264 warning_at (new_loc,
2265 OPT_fcontract_strict_declarations_,
2266 "declaration adds contracts to %q#D",
2267 olddecl);
2268 return;
2271 /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to
2272 remap them because NEWDECL's parameters will replace those of
2273 OLDDECL. Remove the contracts from NEWDECL so they aren't
2274 cloned when merging. */
2275 copy_contract_attributes (olddecl, newdecl);
2276 remove_contract_attributes (newdecl);
2281 /* Replace the any contract attributes on OVERRIDER with a copy where any
2282 references to BASEFN's PARM_DECLs have been rewritten to the corresponding
2283 PARM_DECL in OVERRIDER. */
2285 void
2286 inherit_base_contracts (tree overrider, tree basefn)
2288 tree last = NULL_TREE, contract_attrs = NULL_TREE;
2289 for (tree a = DECL_CONTRACTS (basefn);
2290 a != NULL_TREE;
2291 a = CONTRACT_CHAIN (a))
2293 tree c = copy_node (a);
2294 TREE_VALUE (c) = build_tree_list (TREE_PURPOSE (TREE_VALUE (c)),
2295 copy_node (CONTRACT_STATEMENT (c)));
2297 tree src = basefn;
2298 tree dst = overrider;
2299 remap_contract (src, dst, CONTRACT_STATEMENT (c), /*duplicate_p=*/true);
2301 CONTRACT_COMMENT (CONTRACT_STATEMENT (c)) =
2302 copy_node (CONTRACT_COMMENT (CONTRACT_STATEMENT (c)));
2304 chainon (last, c);
2305 last = c;
2306 if (!contract_attrs)
2307 contract_attrs = c;
2310 set_decl_contracts (overrider, contract_attrs);
2313 #include "gt-cp-contracts.h"