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)
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/>. */
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
37 handle_contract_violation(__pseudo_contract_violation{
39 "main.cpp", // file_name,
40 "fun", // function_name,
42 "default", // assertion_level,
43 "default", // assertion_role,
44 maybe_continue, // continuation_mode
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.
91 We implement the checking as follows:
93 For functions with no post-conditions we wrap the original function body as
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 ();
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
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. */
135 #include "coretypes.h"
137 #include "stringpool.h"
138 #include "diagnostic.h"
140 #include "contracts.h"
142 #include "tree-inline.h"
144 #include "tree-iterator.h"
145 #include "print-tree.h"
146 #include "stor-layout.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] = {
162 validate_contract_role (contract_role
*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");
174 lookup_concrete_semantic (const char *name
)
176 if (strcmp (name
, "ignore") == 0)
178 if (strcmp (name
, "assume") == 0)
180 if (strcmp (name
, "check_never_continue") == 0
181 || strcmp (name
, "never") == 0
182 || strcmp (name
, "abort") == 0)
184 if (strcmp (name
, "check_maybe_continue") == 0
185 || strcmp (name
, "maybe") == 0)
187 error ("'%s' is not a valid explicit concrete semantic", name
);
191 /* Compare role and name up to either the NUL terminator or the first
192 occurrence of colon. */
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
)
201 return strncmp (role
, name
, role_len
) == 0;
205 role_name_equal (contract_role
*role
, const char *name
)
207 if (role
->name
== NULL
)
209 return role_name_equal (role
->name
, name
);
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
))
221 if (role_name_equal (name
, "default") || role_name_equal (name
, "review"))
223 setup_default_contract_role (false);
224 return get_contract_role (name
);
230 add_contract_role (const char *name
,
231 contract_semantic des
,
232 contract_semantic aus
,
233 contract_semantic axs
,
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
))
242 if (potential
->name
!= NULL
&& !update
)
244 potential
->name
= name
;
245 potential
->default_semantic
= des
;
246 potential
->audit_semantic
= aus
;
247 potential
->axiom_semantic
= axs
;
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
;
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
)
281 add_contract_role ("default", CCS_IGNORE
, CCS_IGNORE
, axiom
, update
);
282 add_contract_role ("review", CCS_IGNORE
, CCS_IGNORE
, CCS_IGNORE
, update
);
285 add_contract_role ("default", check
, CCS_IGNORE
, axiom
, update
);
286 add_contract_role ("review", check
, CCS_IGNORE
, CCS_IGNORE
, update
);
289 add_contract_role ("default", check
, check
, axiom
, update
);
290 add_contract_role ("review", check
, check
, CCS_IGNORE
, update
);
296 map_contract_semantic (const char *ident
)
298 if (strcmp (ident
, "ignore") == 0)
300 else if (strcmp (ident
, "assume") == 0)
302 else if (strcmp (ident
, "check_never_continue") == 0)
304 else if (strcmp (ident
, "check_maybe_continue") == 0)
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
;
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");
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
;
340 error ("%<-fcontract-build-level=%> must be off|default|audit");
342 setup_default_contract_role ();
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");
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;
361 error ("%<-fcontract-assumption-mode=%> must be %<on%> or %<off%>");
363 setup_default_contract_role ();
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");
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;
382 error ("%<-fcontract-continuation-mode=%> must be %<on%> or %<off%>");
384 setup_default_contract_role ();
388 handle_OPT_fcontract_role_ (const char *arg
)
390 const char *name
= arg
;
391 const char *vals
= strchr (name
, ':');
394 error ("%<-fcontract-role=%> must be in the form role:semantics");
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
, ',');
405 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
408 *aus
= '\0'; // null terminate des
409 aus
= aus
+ 1; // move past null
411 axs
= strchr (aus
, ',');
414 error ("%<-fcontract-role=%> semantics must include default,audit,axiom values");
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
);
425 if (dess
== CCS_INVALID
|| auss
== CCS_INVALID
|| axss
== CCS_INVALID
)
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");
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
);
446 // TODO: not enough space?
447 error ("%<-fcontract-level=%> too many custom roles");
451 validate_contract_role (role
);
455 handle_OPT_fcontract_semantic_ (const char *arg
)
457 if (!strchr (arg
, ':'))
459 error ("%<-fcontract-semantic=%> must be in the form level:semantic");
463 if (contracts_std
|| contracts_p1332_default
)
465 error ("%<-fcontract-semantic=%> cannot be mixed with std/p1332 contract flags");
468 contracts_p1429
= true;
470 contract_role
*role
= get_contract_role ("default");
473 error ("%<-fcontract-semantic=%> cannot find default role");
477 const char *semantic
= strchr (arg
, ':') + 1;
478 contract_semantic sem
= lookup_concrete_semantic (semantic
);
479 if (sem
== CCS_INVALID
)
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
;
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. */
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
)));
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. */
533 else if (mode
.kind
== contract_mode::cm_invalid
)
535 else if (mode
.kind
== contract_mode::cm_explicit
)
536 return mode
.get_semantic ();
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
;
553 /* Return true if any contract in CONTRACT_ATTRs is not yet parsed. */
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
)))
564 /* Returns true if all attributes are contracts. */
567 all_attributes_are_contracts_p (tree attributes
)
569 for (; attributes
; attributes
= TREE_CHAIN (attributes
))
570 if (!cxx_contract_attribute_p (attributes
))
575 /* Mark most of a contract as being invalid. */
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
;
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. */
594 make_postcondition_variable (cp_expr id
, tree type
)
596 if (id
== error_mark_node
)
599 tree decl
= build_lang_decl (PARM_DECL
, id
, type
);
600 DECL_ARTIFICIAL (decl
) = true;
601 DECL_SOURCE_LOCATION (decl
) = id
.get_location ();
607 /* As above, except that the type is unknown. */
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
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
))
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"));
640 /* Instantiate each postcondition with the return type to finalize the
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
))
653 tree contract
= TREE_VALUE (TREE_VALUE (attributes
));
654 if (TREE_CODE (contract
) != POSTCONDITION_STMT
)
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
)
664 tree oldvar
= POSTCONDITION_IDENTIFIER (contract
);
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
)
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
);
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
);
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 ());
717 /* FIXME cases where we end up here
718 #line macro usage (oof)
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
);
730 /* Build a contract statement. */
733 grok_contract (tree attribute
, tree mode
, tree result
, cp_expr condition
,
736 if (condition
== error_mark_node
)
737 return error_mark_node
;
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
;
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
753 tree type
= void_type_node
;
754 if (code
!= POSTCONDITION_STMT
)
755 contract
= build3_loc (loc
, code
, type
, mode
, NULL_TREE
, NULL_TREE
);
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
;
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
;
783 /* Build the contract attribute specifier where IDENTIFIER is one of 'pre',
784 'post' or 'assert' and CONTRACT is the underlying statement. */
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;
806 /* Update condition of a late-parsed contract and postcondition variable,
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
827 cxx_contract_attribute_p (const_tree attr
)
829 if (attr
== NULL_TREE
830 || TREE_CODE (attr
) != TREE_LIST
)
833 if (!TREE_PURPOSE (attr
) || TREE_CODE (TREE_PURPOSE (attr
)) != TREE_LIST
)
835 if (!TREE_VALUE (attr
) || TREE_CODE (TREE_VALUE (attr
)) != TREE_LIST
)
837 if (!TREE_VALUE (TREE_VALUE (attr
)))
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. */
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. */
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. */
878 /* There are leading contracts. */
881 while (cxx_contract_attribute_p (p
))
889 /* Remove contracts from ATTRIBUTES. */
891 tree
splice_out_contracts (tree attributes
)
893 tree head
= find_first_non_contract (attributes
);
897 /* Splice out remaining contracts. */
898 tree p
= TREE_CHAIN (head
);
902 if (cxx_contract_attribute_p (p
))
904 /* Skip a sequence of contracts and then link q to the next
905 non-contract attribute. */
908 while (cxx_contract_attribute_p (p
));
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
))
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. */
940 get_postcondition_result_parameter (tree d
)
942 if (!d
|| d
== error_mark_node
)
945 if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (d
))))
948 tree post
= DECL_POST_FN (d
);
949 if (!post
|| post
== error_mark_node
)
952 for (tree arg
= DECL_ARGUMENTS (post
); arg
; arg
= TREE_CHAIN (arg
))
953 if (!TREE_CHAIN (arg
))
960 /* For use with the tree inliner. This preserves non-mapped local variables,
961 such as postcondition result variables, during remapping. */
964 retain_decl (tree decl
, copy_body_data
*)
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
989 This is also used to reuse a parent type's contracts on virtual methods. */
992 remap_contract (tree src
, tree dst
, tree contract
, bool duplicate_p
)
995 hash_map
<tree
, tree
> decl_map
;
997 memset (&id
, 0, sizeof (id
));
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. */
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
;
1030 sp
= DECL_CHAIN (sp
), dp
= DECL_CHAIN (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
);
1045 gcc_assert (sp
&& dp
);
1050 insert_decl_map (&id
, sp
, dp
);
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
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. */
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
))
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. */
1086 remap_dummy_this_1 (tree
*tp
, int *, void *data
)
1088 if (!is_this_parameter (*tp
))
1090 tree fn
= (tree
)data
;
1091 *tp
= DECL_ARGUMENTS (fn
);
1095 /* Replace all references to dummy this parameters in EXPR with references to
1096 the first argument of the FUNCTION_DECL FN. */
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. */
1109 contract_valid_p (tree contract
)
1111 return CONTRACT_CONDITION (contract
) != error_mark_node
;
1114 /* True if the contract attribute is valid. */
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. */
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");
1144 /* A deferred contract tentatively matches. */
1145 if (CONTRACT_CONDITION_DEFERRED_P (new_contract
))
1148 /* Compare the conditions of the contracts. We fold immediately to avoid
1149 issues comparing contracts on overrides that use parameters -- see
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
;
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");
1178 /* Compare the contract attributes of OLDDECL and NEWDECL. Returns true
1179 if the contracts match, and false if they differ. */
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
)
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
))
1199 if (check_for_mismatched_contracts (old_attrs
, new_attrs
, ctx
))
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
;
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");
1217 ? "original declaration with fewer contracts here"
1218 : "original declaration with more contracts here");
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
;
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
));
1248 for (tree pending
= *pending_guarded_decls
.get (fndecl
);
1250 pending
= TREE_CHAIN (pending
))
1252 if (TREE_VALUE (pending
) == contracts
)
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. */
1263 match_deferred_contracts (tree decl
)
1265 tree
*tp
= pending_guarded_decls
.get (decl
);
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. */
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. */
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. */
1320 set_precondition_function (tree d
, tree 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. */
1331 set_postcondition_function (tree d
, tree 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. */
1343 set_contract_functions (tree d
, tree pre
, tree post
)
1346 set_precondition_function (d
, pre
);
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. */
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
)))
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
;
1377 last
= TREE_CHAIN (last
) = copy_decl (p
);
1378 DECL_CONTEXT (last
) = decl
;
1383 /* Build a declaration for the pre- or postcondition of a guarded FNDECL. */
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
));
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
;
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;
1478 /* Return true if CONTRACT is checked or assumed under the current build
1482 contract_active_p (tree contract
)
1484 return get_contract_semantic (contract
) != CCS_IGNORE
;
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
))
1499 /* True if D has any checked or assumed preconditions. */
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. */
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. */
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
))))
1527 /* Do we need to mess with contracts for DECL1? */
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. */
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. */
1552 build_precondition_function (tree d
)
1554 if (!has_active_preconditions (d
))
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. */
1565 build_postcondition_function (tree d
)
1567 if (!has_active_postconditions (d
))
1570 tree type
= TREE_TYPE (TREE_TYPE (d
));
1574 return build_contract_condition_function (d
, /*pre=*/false);
1578 build_contract_function_decls (tree d
)
1580 /* Constructors and destructors have their contracts inserted inline. */
1581 if (!outline_contracts_p (d
))
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
);
1591 get_contract_level_name (tree contract
)
1593 if (CONTRACT_LITERAL_MODE_P (contract
))
1595 if (tree mode
= CONTRACT_MODE (contract
))
1596 if (tree level
= TREE_VALUE (mode
))
1597 return IDENTIFIER_POINTER (level
);
1602 get_contract_role_name (tree contract
)
1604 if (CONTRACT_LITERAL_MODE_P (contract
))
1606 if (tree mode
= CONTRACT_MODE (contract
))
1607 if (tree role
= TREE_PURPOSE (mode
))
1608 return IDENTIFIER_POINTER (role
);
1612 /* Build a layout-compatible internal version of std::contract_violation. */
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
,
1643 DECL_CHAIN (next
) = fields
;
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",
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
,
1664 return pseudo_contract_violation_type
;
1667 /* Return a VAR_DECL to pass to handle_contract_violation. */
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 (),
1690 protected_set_expr_location (ctor
, EXPR_LOCATION (contract
));
1694 /* Return handle_contract_violation(), declaring it if needed. */
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)
1709 tree parmtype
= non_reference (TREE_VALUE (parms
));
1710 if (CLASS_TYPE_P (parmtype
)
1711 && TYPE_IDENTIFIER (parmtype
) == viol_name
)
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
,
1722 |LOOK_want::HIDDEN_FRIEND
);
1724 if (TREE_CODE (violation
) == TYPE_DECL
)
1725 violation
= TREE_TYPE (violation
);
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);
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
,
1746 pushdecl_namespace_level (fn
, /*hiding*/true);
1747 pop_nested_namespace (global_namespace
);
1752 /* Build the call to handle_contract_violation for CONTRACT. */
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. */
1768 build_contract_check (tree contract
)
1770 contract_semantic semantic
= get_contract_semantic (contract
);
1771 if (semantic
== CCS_INVALID
)
1774 /* Ignored contracts are never checked or assumed. */
1775 if (semantic
== CCS_IGNORE
)
1778 remap_dummy_this (current_function_decl
, &CONTRACT_CONDITION (contract
));
1779 tree condition
= CONTRACT_CONDITION (contract
);
1780 if (condition
== error_mark_node
)
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
,
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
;
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. */
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. */
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. */
1841 emit_contract_conditions (tree attrs
, tree_code code
)
1844 gcc_assert (TREE_CODE (attrs
) == TREE_LIST
);
1845 gcc_assert (code
== PRECONDITION_STMT
|| code
== POSTCONDITION_STMT
);
1848 tree contract
= CONTRACT_STATEMENT (attrs
);
1849 if (TREE_CODE (contract
) == code
)
1850 attrs
= emit_contract_attr (attrs
);
1852 attrs
= CONTRACT_CHAIN (attrs
);
1856 /* Emit the statement for an assertion attribute. */
1859 emit_assertion (tree attr
)
1861 emit_contract_attr (attr
);
1864 /* Emit statements for precondition attributes. */
1867 emit_preconditions (tree attr
)
1869 return emit_contract_conditions (attr
, PRECONDITION_STMT
);
1872 /* Emit statements for postcondition attributes. */
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. */
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. */
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
))
1918 return condition_conversion (condition
);
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. */
1939 diagnose_misapplied_contracts (tree attributes
)
1941 if (attributes
== NULL_TREE
)
1944 tree contract_attr
= find_contract (attributes
);
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
)));
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
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
);
1975 start_function_contracts (tree decl1
)
1977 if (!handle_contracts_p (decl1
))
1980 /* For cdtors, we evaluate the contracts check inline. */
1981 if (!outline_contracts_p (decl1
))
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. */
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 (),
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
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 (),
2022 CALL_FROM_THUNK_P (call
) = true;
2023 finish_expr_stmt (call
);
2026 /* Add a call or a direct evaluation of the pre checks. */
2029 apply_preconditions (tree fndecl
)
2031 if (outline_contracts_p (fndecl
))
2032 add_pre_condition_fn_call (fndecl
);
2034 emit_preconditions (DECL_CONTRACTS (fndecl
));
2037 /* Add a call or a direct evaluation of the post checks. */
2040 apply_postconditions (tree fndecl
)
2042 if (outline_contracts_p (fndecl
))
2043 add_post_condition_fn_call (fndecl
);
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. */
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. */
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. */
2087 apply_preconditions (fndecl
);
2089 finish_compound_stmt (compound_stmt
);
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
);
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
);
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
);
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. */
2122 finish_function_contracts (tree fndecl
)
2124 if (!handle_contracts_p (fndecl
)
2125 || !outline_contracts_p (fndecl
))
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
)
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
)
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
),
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. */
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
)
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:
2197 virtual void f(int n) [[pre: n == 0]];
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
,
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
2228 /* Contracts have been previously specified by are no omitted. The
2229 new declaration inherits the existing 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. */
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");
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");
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",
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. */
2286 inherit_base_contracts (tree overrider
, tree basefn
)
2288 tree last
= NULL_TREE
, contract_attrs
= NULL_TREE
;
2289 for (tree a
= DECL_CONTRACTS (basefn
);
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
)));
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
)));
2306 if (!contract_attrs
)
2310 set_decl_contracts (overrider
, contract_attrs
);
2313 #include "gt-cp-contracts.h"