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