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