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