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