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