LCOV - code coverage report
Current view: top level - gcc/cp - contracts.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.5 % 1340 1280
Test Date: 2026-09-12 16:25:28 Functions: 100.0 % 98 98
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* C++ contracts.
       2              : 
       3              :    Copyright (C) 2020-2026 Free Software Foundation, Inc.
       4              :    Originally by Jeff Chapman II (jchapman@lock3software.com) for proposed
       5              :    C++20 contracts.
       6              :    Rewritten for C++26 contracts by:
       7              :      Nina Ranns (dinka.ranns@googlemail.com)
       8              :      Iain Sandoe (iain@sandoe.co.uk)
       9              :      Ville Voutilainen (ville.voutilainen@gmail.com).
      10              : 
      11              : This file is part of GCC.
      12              : 
      13              : GCC is free software; you can redistribute it and/or modify
      14              : it under the terms of the GNU General Public License as published by
      15              : the Free Software Foundation; either version 3, or (at your option)
      16              : any later version.
      17              : 
      18              : GCC is distributed in the hope that it will be useful,
      19              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      20              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21              : GNU General Public License for more details.
      22              : 
      23              : You should have received a copy of the GNU General Public License
      24              : along with GCC; see the file COPYING3.  If not see
      25              : <http://www.gnu.org/licenses/>.  */
      26              : 
      27              : #include "config.h"
      28              : #include "system.h"
      29              : #include "coretypes.h"
      30              : #include "cp-tree.h"
      31              : #include "stringpool.h"
      32              : #include "diagnostic.h"
      33              : #include "options.h"
      34              : #include "contracts.h"
      35              : #include "tree.h"
      36              : #include "tree-inline.h"
      37              : #include "attribs.h"
      38              : #include "tree-iterator.h"
      39              : #include "print-tree.h"
      40              : #include "stor-layout.h"
      41              : #include "intl.h"
      42              : #include "cgraph.h"
      43              : #include "opts.h"
      44              : #include "output.h"
      45              : 
      46              : /*  Design notes.
      47              : 
      48              :   There are three phases:
      49              :     1. Parsing and semantic checks.
      50              :        Most of the code for this is in the parser, with helpers provided here.
      51              :     2. Emitting contract assertion AST nodes into function bodies.
      52              :        This is initiated from "finish_function ()"
      53              :     3. Lowering the contract assertion AST nodes to control flow, constant
      54              :        data and calls to the violation handler.
      55              :        This is initiated from "cp_genericize ()".
      56              : 
      57              :   The organisation of the code in this file is intended to follow those three
      58              :   phases where possible.
      59              : 
      60              :   Contract Assertion State
      61              :   ========================
      62              : 
      63              :   contract_assert () does not require any special handling and can be
      64              :   represented directly by AST inserted in the function body.
      65              : 
      66              :   'pre' and 'post' function contract specifiers require most of the special
      67              :   handling, since they must be tracked across re-declarations of functions and
      68              :   there are constraints on how such specifiers may change in these cases.
      69              : 
      70              :   The contracts specification identifies a "first declaration" of any given
      71              :   function - which is the first encountered when parsing a given TU.
      72              :   Subsequent re-declarations may not add or change the function contract
      73              :   specifiers from any introduced on this first declaration.  It is, however,
      74              :   permitted to omit specifiers on re-declarations.
      75              : 
      76              :   Since the implementation of GCC's (re-)declarations is a destructive merge
      77              :   we need to keep some state on the side to determine whether the re-declaration
      78              :   rules are met.  In this current design we have chosen not to add another tree
      79              :   to each function decl but, instead, keep a map from function decl to contract
      80              :   specifier state.  In this state we record the 'first declaration' specifiers
      81              :   which are used to validate re-declaration(s) and to report the initial state
      82              :   in diagnostics.
      83              : 
      84              :   We need (for example) to compare
      85              :     pre ( x > 2 ) equal to
      86              :     pre ( z > 2 ) when x and z refer to the same function parameter in a
      87              :     re-declaration.
      88              : 
      89              :   The mechanism used to determine if two contracts are the same is to compare
      90              :   the folded trees.  This makes use of current compiler machinery, rather than
      91              :   constructing some new AST comparison scheme.  However, it does introduce an
      92              :   additional complexity in that we need to defer such comparison until parsing
      93              :   is complete - and function contract specifiers in class declarations must be
      94              :   deferred parses, since it is also permitted for specifiers to refer to class
      95              :   members.
      96              : 
      97              :   When we encounter a definition, the parameter names in a function decl are
      98              :   re-written to match those of the definition (thus the expected names will
      99              :   appear in debug information etc).  At this point, we also need to re-map
     100              :   any function parameter names that appear in function contract specifiers
     101              :   to agree with those of the definition - although we intend to keep the
     102              :   'first declaration' record consistent for diagnostics.
     103              : 
     104              :   Since we shared some code from the C++2a contracts implementation, pre and
     105              :   post specifiers are represented by chains of attributes, where the payload
     106              :   of the attribute is an AST node.  However during the parse, these are not
     107              :   inserted into the function bodies, but kept in the decl-keyed state described
     108              :   above.  A future improvement planned here is to store the specifiers using a
     109              :   tree vec instead of the attribute list.
     110              : 
     111              :   Emitting contract AST
     112              :   =====================
     113              : 
     114              :   When we reach `finish_function ()` and therefore are committed to potentially
     115              :   emitting code for an instance, we build a new variant of the function body
     116              :   with the pre-condition AST inserted before the user's function body, and the
     117              :   post condition AST (if any) linked into the function return.
     118              : 
     119              :   Lowering the contract assertion AST
     120              :   ===================================
     121              : 
     122              :   In all cases (pre, post, contract_assert) the AST node is lowered to control
     123              :   flow and (potentially) calls to the violation handler and/or termination.
     124              :   This is done during `cp_genericize ()`.  In the current implementation, the
     125              :   decision on the control flow is made on the basis of the setting of a command-
     126              :   line flag that determines a TU-wide contract evaluation semantic, which has
     127              :   the following initial set of behaviours:
     128              : 
     129              :     'ignore'        : contract assertion AST is lowered to 'nothing',
     130              :                       i.e. omitted.
     131              :     'enforce'       : contract assertion AST is lowered to a check, if this
     132              :                       fails a violation handler is called, followed by
     133              :                       std::terminate().
     134              :     'quick_enforce' : contract assertion AST is lowered to a check, if this
     135              :                       fails, std::terminate () is called.
     136              :     'observe'       : contract assertion AST is lowered to a check, if this
     137              :                       fails, a violation handler is called, the code then
     138              :                       continues.
     139              : 
     140              :   In each case, the "check" might be a simple 'if' (when it is determined that
     141              :   the assertion condition does not throw) or the condition evaluation will be
     142              :   wrapped in a try-catch block that treats any exception thrown when evaluating
     143              :   the check as equivalent to a failed check.  It is noted in the violation data
     144              :   object whether a check failed because of an exception raised in evaluation.
     145              : 
     146              :   At present, a simple (but potentially space-inefficient) scheme is used to
     147              :   store constant data objects that represent the read-only data for the
     148              :   violation.  The exact form of this is subject to revision as it represents
     149              :   ABI that must be agreed between implementations (as of this point, that
     150              :   discussion is not yet concluded).  */
     151              : 
     152              : /* Contract matching.  */
     153              : 
     154              : bool comparing_contracts;
     155              : 
     156              : /* True if the contract is valid.  */
     157              : 
     158              : static bool
     159          108 : contract_valid_p (tree contract)
     160              : {
     161          108 :   return CONTRACT_CONDITION (contract) != error_mark_node;
     162              : }
     163              : 
     164              : /* Compare the contract conditions of OLD_CONTRACT and NEW_CONTRACT.
     165              :    Returns false if the conditions are equivalent, and true otherwise.  */
     166              : 
     167              : static bool
     168           54 : mismatched_contracts_p (tree old_contract, tree new_contract)
     169              : {
     170              :   /* Different kinds of contracts do not match.  */
     171           54 :   if (TREE_CODE (old_contract) != TREE_CODE (new_contract))
     172              :     {
     173            0 :       auto_diagnostic_group d;
     174            0 :       error_at (EXPR_LOCATION (new_contract),
     175              :                 "mismatched contract specifier in declaration");
     176            0 :       inform (EXPR_LOCATION (old_contract), "previous contract here");
     177            0 :       return true;
     178            0 :     }
     179              : 
     180              :   /* A deferred contract tentatively matches.  */
     181           54 :   if (CONTRACT_CONDITION_DEFERRED_P (new_contract))
     182              :     return false;
     183              : 
     184              :   /* Compare the conditions of the contracts.  */
     185           54 :   tree t1 = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
     186           54 :   tree t2 = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
     187              : 
     188              :   /* Compare the contracts. */
     189              : 
     190           54 :   bool saved_comparing_contracts = comparing_contracts;
     191           54 :   comparing_contracts = true;
     192           54 :   bool matching_p = cp_tree_equal (t1, t2);
     193           54 :   comparing_contracts = saved_comparing_contracts;
     194              : 
     195           54 :   if (!matching_p)
     196              :     {
     197           15 :       auto_diagnostic_group d;
     198           15 :       error_at (EXPR_LOCATION (CONTRACT_CONDITION (new_contract)),
     199              :                 "mismatched contract condition in declaration");
     200           15 :       inform (EXPR_LOCATION (CONTRACT_CONDITION (old_contract)),
     201              :               "previous contract here");
     202           15 :       return true;
     203           15 :     }
     204              : 
     205              :   return false;
     206              : }
     207              : 
     208              : /* Compare the contract specifiers of OLDDECL and NEWDECL. Returns true
     209              :    if the contracts match, and false if they differ.  */
     210              : 
     211              : static bool
     212           57 : match_contract_specifiers (location_t oldloc, tree old_contracts,
     213              :                            location_t newloc, tree new_contracts)
     214              : {
     215              :   /* Contracts only match if they are both specified.  */
     216           57 :   if (!old_contracts || !new_contracts)
     217              :     return true;
     218              : 
     219           57 :   int old_len = TREE_VEC_LENGTH (old_contracts);
     220           57 :   int new_len = TREE_VEC_LENGTH (new_contracts);
     221              : 
     222              :   /* If we don't have the same number, the contracts don't match.  */
     223           57 :   if (old_len != new_len)
     224              :     {
     225            6 :       auto_diagnostic_group d;
     226            6 :       error_at (newloc,
     227              :                 "declaration has a different number of contracts than "
     228              :                 "previously declared");
     229            6 :       inform (oldloc,
     230              :               new_len > old_len
     231              :               ? "previous declaration with fewer contracts here"
     232              :               : "previous declaration with more contracts here");
     233            6 :       return false;
     234            6 :     }
     235              : 
     236              :   /* Compare each contract in turn.  */
     237           90 :   for (int ix = 0; ix < MIN (old_len, new_len); ix++)
     238              :     {
     239           54 :       tree old_contract = TREE_VEC_ELT (old_contracts, ix);
     240           54 :       tree new_contract = TREE_VEC_ELT (new_contracts, ix);
     241              : 
     242              :       /* If either contract is ill-formed, skip the rest of the comparison,
     243              :          since we've already diagnosed an error.  */
     244           54 :       if (!contract_valid_p (new_contract) || !contract_valid_p (old_contract))
     245              :         return false;
     246              : 
     247           54 :       if (mismatched_contracts_p (old_contract, new_contract))
     248              :         return false;
     249              :     }
     250              : 
     251              : 
     252              :   return true;
     253              : }
     254              : 
     255              : /* Return true if CONTRACT is checked under the current semantic.  */
     256              : 
     257              : static bool
     258         3413 : contract_active_p (tree contract)
     259              : {
     260         1194 :   return get_evaluation_semantic (contract) != CES_IGNORE;
     261              : }
     262              : 
     263              : /* Return true if any contract of FNDECL is checked under the
     264              :    current semantic.  */
     265              : 
     266              : static bool
     267     62196405 : contract_any_active_p (tree fndecl)
     268              : {
     269     62196405 :   tree contracts = get_fn_contract_specifiers (fndecl);
     270     62196405 :   if (!contracts)
     271              :     return false;
     272              : 
     273         2227 :   for (tree contract : tree_vec_range (contracts))
     274         2219 :     if (contract_active_p (contract))
     275         2203 :       return true;
     276            8 :   return false;
     277              : }
     278              : 
     279              : /* True if FNDECL has any checked contracts whose TREE_CODE is
     280              :    C.  */
     281              : 
     282              : static bool
     283      1079114 : has_active_contract_condition (tree fndecl, tree_code c)
     284              : {
     285      1079114 :   tree contracts = get_fn_contract_specifiers (fndecl);
     286      1079114 :   if (!contracts)
     287              :     return false;
     288              : 
     289         3452 :   for (tree contract : tree_vec_range (contracts))
     290         3726 :     if (TREE_CODE (contract) == c && contract_active_p (contract))
     291         1194 :       return true;
     292          920 :   return false;
     293              : }
     294              : 
     295              : /* True if FNDECL has any checked or assumed preconditions.  */
     296              : 
     297              : static bool
     298         1011 : has_active_preconditions (tree fndecl)
     299              : {
     300            0 :   return has_active_contract_condition (fndecl, PRECONDITION_STMT);
     301              : }
     302              : 
     303              : /* True if FNDECL has any checked or assumed postconditions.  */
     304              : 
     305              : static bool
     306      1078103 : has_active_postconditions (tree fndecl)
     307              : {
     308            0 :   return has_active_contract_condition (fndecl, POSTCONDITION_STMT);
     309              : }
     310              : 
     311              : /* Return true if any contract in CONTRACTS is not yet parsed.  */
     312              : 
     313              : bool
     314         1371 : contract_any_deferred_p (tree contracts)
     315              : {
     316         1371 :   if (!contracts)
     317              :     return false;
     318              : 
     319         2524 :   for (tree contract : tree_vec_range (contracts))
     320         1698 :     if (CONTRACT_CONDITION_DEFERRED_P (contract))
     321          454 :       return true;
     322          826 :   return false;
     323              : }
     324              : 
     325              : /* Returns true if function decl FNDECL has contracts and we need to
     326              :    process them for the purposes of either building caller or definition
     327              :    contract checks.
     328              :    This function does not take into account whether caller or definition
     329              :    side checking is enabled. Those checks will be done from the calling
     330              :    function which will be able to determine whether it is doing caller
     331              :    or definition contract handling.  */
     332              : 
     333              : static bool
     334    653799139 : handle_contracts_p (tree fndecl)
     335              : {
     336    653799139 :   return (flag_contracts
     337     97279826 :           && !processing_template_decl
     338     62196489 :           && (CONTRACT_HELPER (fndecl) == ldf_contract_none)
     339    715995544 :           && contract_any_active_p (fndecl));
     340              : }
     341              : 
     342              : /* For use with the tree inliner. This preserves non-mapped local variables,
     343              :    such as postcondition result variables, during remapping.  */
     344              : 
     345              : static tree
     346          752 : retain_decl (tree decl, copy_body_data *)
     347              : {
     348          752 :   return decl;
     349              : }
     350              : 
     351              : /* Lookup a name in std::, or inject it.  */
     352              : 
     353              : static tree
     354          190 : lookup_std_type (tree name_id)
     355              : {
     356          190 :   tree res_type = lookup_qualified_name
     357          190 :     (std_node, name_id, LOOK_want::TYPE | LOOK_want::HIDDEN_FRIEND);
     358              : 
     359          190 :   if (TREE_CODE (res_type) == TYPE_DECL)
     360           49 :     res_type = TREE_TYPE (res_type);
     361              :   else
     362              :     {
     363          141 :       push_nested_namespace (std_node);
     364          141 :       res_type = make_class_type (RECORD_TYPE);
     365          141 :       create_implicit_typedef (name_id, res_type);
     366          141 :       DECL_SOURCE_LOCATION (TYPE_NAME (res_type)) = BUILTINS_LOCATION;
     367          141 :       DECL_CONTEXT (TYPE_NAME (res_type)) = current_namespace;
     368          141 :       pushdecl_namespace_level (TYPE_NAME (res_type), /*hidden*/true);
     369          141 :       pop_nested_namespace (std_node);
     370              :     }
     371          190 :   return res_type;
     372              : }
     373              : 
     374              : /* Get constract_assertion_kind of the specified contract. Used when building
     375              :   contract_violation object.  */
     376              : 
     377              : static contract_assertion_kind
     378         1036 : get_contract_assertion_kind (tree contract)
     379              : {
     380         1036 :   if (CONTRACT_ASSERTION_KIND (contract))
     381              :     {
     382         1036 :       tree s = CONTRACT_ASSERTION_KIND (contract);
     383         1036 :       tree i = (TREE_CODE (s) == INTEGER_CST) ? s
     384            0 :                                               : DECL_INITIAL (STRIP_NOPS (s));
     385         1036 :       gcc_checking_assert (!type_dependent_expression_p (s) && i);
     386         1036 :       return (contract_assertion_kind) tree_to_uhwi (i);
     387              :     }
     388              : 
     389            0 :   switch (TREE_CODE (contract))
     390              :   {
     391              :     case ASSERTION_STMT:        return CAK_ASSERT;
     392              :     case PRECONDITION_STMT:     return CAK_PRE;
     393              :     case POSTCONDITION_STMT:    return CAK_POST;
     394            0 :     default: break;
     395              :   }
     396              : 
     397            0 :   gcc_unreachable ();
     398              : }
     399              : 
     400              : /* Get contract_evaluation_semantic of the specified contract.  */
     401              : 
     402              : contract_evaluation_semantic
     403         5415 : get_evaluation_semantic (const_tree contract)
     404              : {
     405         5415 :   if (CONTRACT_EVALUATION_SEMANTIC (contract))
     406              :     {
     407         5415 :       tree s = CONTRACT_EVALUATION_SEMANTIC (contract);
     408         5415 :       tree i = (TREE_CODE (s) == INTEGER_CST) ? s
     409            0 :                                               : DECL_INITIAL (STRIP_NOPS (s));
     410         5415 :       gcc_checking_assert (!type_dependent_expression_p (s) && i);
     411         5415 :       switch (contract_evaluation_semantic ev =
     412         5415 :               (contract_evaluation_semantic) tree_to_uhwi (i))
     413              :         {
     414              :         /* This needs to be kept in step with any added semantics.  */
     415         5415 :         case CES_IGNORE:
     416         5415 :         case CES_OBSERVE:
     417         5415 :         case CES_ENFORCE:
     418         5415 :         case CES_QUICK:
     419         5415 :           return ev;
     420              :         default:
     421              :           break;
     422              :         }
     423              :     }
     424              : 
     425            0 :   gcc_unreachable ();
     426              : }
     427              : 
     428              : /* Get location of the last contract in CONTRACTS.  */
     429              : 
     430              : static location_t
     431         1451 : get_contract_end_loc (tree contracts)
     432              : {
     433         2902 :   gcc_checking_assert (contracts && TREE_VEC_LENGTH (contracts) > 0);
     434         1451 :   tree last = TREE_VEC_ELT (contracts, TREE_VEC_LENGTH (contracts) - 1);
     435         1451 :   return EXPR_LOCATION (last);
     436              : }
     437              : 
     438              : /* Build the contract specifiers for a function from CONTRACTS, which are in
     439              :    source order.  Returns NULL_TREE when there are none.  */
     440              : 
     441              : tree
     442     22637523 : build_contract_specifiers (vec<tree, va_gc> *contracts)
     443              : {
     444     22637523 :   unsigned len = vec_safe_length (contracts);
     445     22637523 :   if (!len)
     446              :     return NULL_TREE;
     447              : 
     448          924 :   tree specs = make_tree_vec (len);
     449         3343 :   for (unsigned ix = 0; ix < len; ix++)
     450         1495 :     TREE_VEC_ELT (specs, ix) = (*contracts)[ix];
     451              :   return specs;
     452              : }
     453              : 
     454              : /* Append the contract specifiers in SECOND to those in FIRST, either of
     455              :    which may be NULL_TREE.  Neither input is modified.  */
     456              : 
     457              : tree
     458     22792644 : contract_specifiers_concat (tree first, tree second)
     459              : {
     460     22792644 :   if (!first)
     461              :     return second;
     462            0 :   if (!second)
     463              :     return first;
     464              : 
     465            0 :   int flen = TREE_VEC_LENGTH (first);
     466            0 :   int slen = TREE_VEC_LENGTH (second);
     467            0 :   tree specs = make_tree_vec (flen + slen);
     468            0 :   for (int ix = 0; ix < flen; ix++)
     469            0 :     TREE_VEC_ELT (specs, ix) = TREE_VEC_ELT (first, ix);
     470            0 :   for (int ix = 0; ix < slen; ix++)
     471            0 :     TREE_VEC_ELT (specs, flen + ix) = TREE_VEC_ELT (second, ix);
     472              :   return specs;
     473              : }
     474              : 
     475              : struct GTY(()) contract_decl
     476              : {
     477              :   tree contract_specifiers;
     478              :   location_t note_loc;
     479              : };
     480              : 
     481              : static GTY(()) hash_map<tree, contract_decl> *contract_decl_map;
     482              : 
     483              : /* Converts a contract condition to bool and ensures it has a location.  */
     484              : 
     485              : tree
     486         2205 : finish_contract_condition (cp_expr condition)
     487              : {
     488         2205 :   if (!condition || error_operand_p (condition))
     489              :     return condition;
     490              : 
     491              :   /* Ensure we have the condition location saved in case we later need to
     492              :      emit a conversion error during template instantiation and wouldn't
     493              :      otherwise have it.  This differs from maybe_wrap_with_location in that
     494              :      it allows wrappers on EXCEPTIONAL_CLASS_P which includes CONSTRUCTORs.  */
     495         2185 :   if (!CAN_HAVE_LOCATION_P (condition)
     496          121 :       && condition.get_location () != UNKNOWN_LOCATION)
     497              :     {
     498          121 :       tree_code code
     499          117 :         = (((CONSTANT_CLASS_P (condition) && TREE_CODE (condition) != STRING_CST)
     500            4 :             || (TREE_CODE (condition) == CONST_DECL && !TREE_STATIC (condition)))
     501          121 :           ? NON_LVALUE_EXPR : VIEW_CONVERT_EXPR);
     502          121 :       condition = build1_loc (condition.get_location (), code,
     503          121 :                               TREE_TYPE (condition), condition);
     504          121 :       EXPR_LOCATION_WRAPPER_P (condition) = true;
     505              :     }
     506              : 
     507         2185 :   if (type_dependent_expression_p (condition))
     508              :     return condition;
     509              : 
     510         1643 :   return condition_conversion (condition);
     511              : }
     512              : 
     513              : /* Wrap the DECL into VIEW_CONVERT_EXPR representing const qualified version
     514              :    of the declaration.  */
     515              : 
     516              : tree
     517         3431 : view_as_const (tree decl)
     518              : {
     519         3431 :   if (decl
     520         3431 :       && !CP_TYPE_CONST_P (TREE_TYPE (decl)))
     521              :     {
     522         2423 :       gcc_checking_assert (!contract_const_wrapper_p (decl));
     523         2423 :       tree ctype = TREE_TYPE (decl);
     524         2423 :       location_t loc =
     525         2423 :           EXPR_P (decl) ? EXPR_LOCATION (decl) : DECL_SOURCE_LOCATION (decl);
     526         2423 :       ctype = cp_build_qualified_type (ctype, (cp_type_quals (ctype)
     527              :                                                | TYPE_QUAL_CONST));
     528         2423 :       decl = build1 (VIEW_CONVERT_EXPR, ctype, decl);
     529         2423 :       SET_EXPR_LOCATION (decl, loc);
     530              :       /* Mark the VCE as contract const wrapper.  */
     531         2423 :       CONST_WRAPPER_P (decl) = true;
     532              :     }
     533         3431 :   return decl;
     534              : }
     535              : 
     536              : /* Constify access to DECL from within the contract condition.  */
     537              : 
     538              : tree
     539         2615 : constify_contract_access (tree decl)
     540              : {
     541              :   /* We check if we have a variable, a parameter, a variable of reference type,
     542              :    * or a parameter of reference type
     543              :    */
     544         2615 :   if (!TREE_READONLY (decl)
     545         2615 :       && (VAR_P (decl)
     546         2156 :           || (TREE_CODE (decl) == PARM_DECL)
     547          722 :           || (REFERENCE_REF_P (decl)
     548          140 :               && (VAR_P (TREE_OPERAND (decl, 0))
     549          132 :                   || (TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL)
     550            9 :                   || (TREE_CODE (TREE_OPERAND (decl, 0))
     551              :                       == TEMPLATE_PARM_INDEX)))))
     552         1754 :     decl = view_as_const (decl);
     553              : 
     554         2615 :   return decl;
     555              : }
     556              : 
     557              : /* Indicate that PARM_DECL DECL is ODR used in a postcondition.  */
     558              : 
     559              : static void
     560          728 : set_parm_used_in_post (tree decl, bool constify = true)
     561              : {
     562          728 :   gcc_checking_assert (TREE_CODE (decl) == PARM_DECL);
     563          728 :   DECL_LANG_FLAG_4 (decl) = constify;
     564          728 : }
     565              : 
     566              : /* Test if PARM_DECL is ODR used in a postcondition.  */
     567              : 
     568              : static bool
     569          785 : parm_used_in_post_p (const_tree decl)
     570              : {
     571              :   /* Check if this parameter is odr used within a function's postcondition  */
     572          785 :   return ((TREE_CODE (decl) == PARM_DECL) && DECL_LANG_FLAG_4 (decl));
     573              : }
     574              : 
     575              : /* If declaration DECL is a PARM_DECL and it appears in a postcondition, then
     576              :    check that it is not a non-const by-value param. LOCATION is where the
     577              :    expression was found and is used for diagnostic purposes.  */
     578              : 
     579              : void
     580    751878675 : check_param_in_postcondition (tree decl, location_t location)
     581              : {
     582    751878675 :   if (processing_postcondition
     583         1498 :       && TREE_CODE (decl) == PARM_DECL
     584              :       /* TREE_CODE (decl) == PARM_DECL only holds for non-reference
     585              :          parameters.  */
     586          907 :       && !cp_unevaluated_operand
     587              :       /* Return value parameter has DECL_ARTIFICIAL flag set. The flag
     588              :          presence of the flag should be sufficient to distinguish the
     589              :          return value parameter in this context.  */
     590    751879366 :       && !(DECL_ARTIFICIAL (decl)))
     591              :     {
     592          481 :       set_parm_used_in_post (decl);
     593              : 
     594          481 :       if (!dependent_type_p (TREE_TYPE (decl))
     595          481 :           && !CP_TYPE_CONST_P (TREE_TYPE (decl)))
     596              :         {
     597          114 :           auto_diagnostic_group d;
     598          114 :           error_at (location,
     599              :                     "a value parameter used in a postcondition must be const");
     600          114 :           inform (DECL_SOURCE_LOCATION (decl), "parameter declared here");
     601          114 :         }
     602              :     }
     603    751878675 : }
     604              : 
     605              : /* Check if parameters used in postconditions are const qualified on
     606              :    a redeclaration that does not specify contracts or on an instantiation
     607              :    of a function template.  */
     608              : 
     609              : void
     610    147971845 : check_postconditions_in_redecl (tree olddecl, tree newdecl)
     611              : {
     612    147971845 :   tree contract_spec = get_fn_contract_specifiers (olddecl);
     613    147971845 :   if (!contract_spec)
     614              :     return;
     615              : 
     616          478 :   tree t1 = FUNCTION_FIRST_USER_PARM (olddecl);
     617          478 :   tree t2 = FUNCTION_FIRST_USER_PARM (newdecl);
     618              : 
     619         1741 :   for (; t1 && t1 != void_list_node;
     620          785 :        t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
     621              :     {
     622          785 :       if (parm_used_in_post_p (t1))
     623              :         {
     624          247 :           set_parm_used_in_post (t2);
     625          247 :           if (!dependent_type_p (TREE_TYPE (t2))
     626          193 :               && !CP_TYPE_CONST_P (TREE_TYPE (t2))
     627          340 :               && !TREE_READONLY (t2))
     628              :             {
     629           93 :               auto_diagnostic_group d;
     630           93 :               error_at (DECL_SOURCE_LOCATION (t2),
     631              :                         "value parameter %qE used in a postcondition must be "
     632              :                         "const", t2);
     633           93 :               inform (DECL_SOURCE_LOCATION (olddecl),
     634              :                       "previous declaration here");
     635           93 :             }
     636              :         }
     637              :     }
     638              : }
     639              : 
     640              : /* Map from FUNCTION_DECL to a FUNCTION_DECL for either the PRE_FN or POST_FN.
     641              :    These are used to parse contract conditions and are called inside the body
     642              :    of the guarded function.  */
     643              : static GTY(()) hash_map<tree, tree> *decl_pre_fn;
     644              : static GTY(()) hash_map<tree, tree> *decl_post_fn;
     645              : 
     646              : /* Given a pre or post function decl (for an outlined check function) return
     647              :    the decl for the function for which the outlined checks are being
     648              :    performed.  */
     649              : static GTY(()) hash_map<tree, tree> *orig_from_outlined;
     650              : 
     651              : /* Makes PRE the precondition function for FNDECL.  */
     652              : 
     653              : static void
     654           14 : set_precondition_function (tree fndecl, tree pre)
     655              : {
     656           14 :   gcc_assert (pre);
     657           14 :   hash_map_maybe_create<hm_ggc> (decl_pre_fn);
     658           14 :   gcc_checking_assert (!decl_pre_fn->get (fndecl));
     659           14 :   decl_pre_fn->put (fndecl, pre);
     660              : 
     661           14 :   hash_map_maybe_create<hm_ggc> (orig_from_outlined);
     662           14 :   gcc_checking_assert (!orig_from_outlined->get (pre));
     663           14 :   orig_from_outlined->put (pre, fndecl);
     664           14 : }
     665              : 
     666              : /* Makes POST the postcondition function for FNDECL.  */
     667              : 
     668              : static void
     669           45 : set_postcondition_function (tree fndecl, tree post)
     670              : {
     671           45 :   gcc_checking_assert (post);
     672           45 :   hash_map_maybe_create<hm_ggc> (decl_post_fn);
     673           45 :   gcc_checking_assert (!decl_post_fn->get (fndecl));
     674           45 :   decl_post_fn->put (fndecl, post);
     675              : 
     676           45 :   hash_map_maybe_create<hm_ggc> (orig_from_outlined);
     677           45 :   gcc_checking_assert (!orig_from_outlined->get (post));
     678           45 :   orig_from_outlined->put (post, fndecl);
     679           45 : }
     680              : 
     681              : /* For a given pre or post condition function, find the checked function.  */
     682              : tree
     683           32 : get_orig_for_outlined (tree fndecl)
     684              : {
     685           32 :   gcc_checking_assert (fndecl);
     686           32 :   tree *result = hash_map_safe_get (orig_from_outlined, fndecl);
     687           32 :   return result ? *result : NULL_TREE ;
     688              : }
     689              : 
     690              : /* For a given function OLD_FN set suitable names for NEW_FN (which is an
     691              :    outlined contract check) usually by appending '.pre' or '.post'.
     692              : 
     693              :    For functions with special meaning names (i.e. main and cdtors) we need to
     694              :    make special provisions and therefore handle all the contracts function
     695              :    name changes here, rather than requiring a separate update to mangle.cc.
     696              : 
     697              :    PRE specifies if we need an identifier for a pre or post contract check.  */
     698              : 
     699              : static void
     700           87 : contracts_fixup_names (tree new_fn, tree old_fn, bool pre, bool wrapper)
     701              : {
     702           87 :   bool cdtor = DECL_CXX_CONSTRUCTOR_P (old_fn)
     703           87 :                || DECL_CXX_DESTRUCTOR_P (old_fn);
     704           87 :   const char *fname = IDENTIFIER_POINTER (DECL_NAME (old_fn));
     705          132 :   const char *append = wrapper ? "contract_wrapper"
     706           59 :                                : (pre ? "pre" : "post");
     707           87 :   size_t len = strlen (fname);
     708              :   /* Cdtor names have a space at the end.  We need to remove that space
     709              :      when forming the new identifier.  */
     710           87 :   char *nn = xasprintf ("%.*s%s%s",
     711            0 :                         cdtor ? (int)len-1 : int(len),
     712              :                         fname,
     713              :                         JOIN_STR,
     714              :                         append);
     715           87 :   DECL_NAME (new_fn) = get_identifier (nn);
     716           87 :   free (nn);
     717              : 
     718              :   /* Now do the mangled version.  */
     719           87 :   fname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (old_fn));
     720           87 :   nn = xasprintf ("%s%s%s", fname, JOIN_STR, append);
     721           87 :   SET_DECL_ASSEMBLER_NAME (new_fn, get_identifier (nn));
     722           87 :   free (nn);
     723           87 : }
     724              : 
     725              : /* Build a declaration for the pre- or postcondition of a guarded FNDECL.  */
     726              : 
     727              : static tree
     728           59 : build_contract_condition_function (tree fndecl, bool pre)
     729              : {
     730           59 :   if (error_operand_p (fndecl))
     731            0 :     return error_mark_node;
     732              : 
     733              :   /* Start the copy.  */
     734           59 :   tree fn = copy_decl (fndecl);
     735              : 
     736              :   /* Don't propagate declaration attributes to the checking function,
     737              :      including the original contracts.  */
     738           59 :   DECL_ATTRIBUTES (fn) = NULL_TREE;
     739              : 
     740              :   /* If requested, disable optimisation of checking functions; this can, in
     741              :      some cases, prevent UB from eliding the checks themselves.  */
     742           59 :   if (flag_contract_disable_optimized_checks)
     743            0 :     DECL_ATTRIBUTES (fn)
     744            0 :       = tree_cons (get_identifier ("optimize"),
     745              :                    build_tree_list (NULL_TREE, build_string (3, "-O0")),
     746              :                    NULL_TREE);
     747              : 
     748              :   /* Now parse and add any internal representation of these attrs to the
     749              :      decl.  */
     750           59 :   if (DECL_ATTRIBUTES (fn))
     751            0 :     cplus_decl_attributes (&fn, DECL_ATTRIBUTES (fn), 0);
     752              : 
     753              :   /* A possible later optimization may delete unused args to prevent extra arg
     754              :      passing.  */
     755              :   /* Handle the args list.  */
     756           59 :   tree arg_types = NULL_TREE;
     757           59 :   tree *last = &arg_types;
     758           59 :   for (tree arg_type = TYPE_ARG_TYPES (TREE_TYPE (fn));
     759          151 :       arg_type && arg_type != void_list_node;
     760           92 :       arg_type = TREE_CHAIN (arg_type))
     761              :     {
     762           92 :       if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
     763           92 :           && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type)
     764           36 :       continue;
     765           56 :       *last = build_tree_list (TREE_PURPOSE (arg_type), TREE_VALUE (arg_type));
     766           56 :       last = &TREE_CHAIN (*last);
     767              :     }
     768              : 
     769              :   /* Copy the function parameters, if present.  Disable warnings for them.  */
     770           59 :   DECL_ARGUMENTS (fn) = NULL_TREE;
     771           59 :   if (DECL_ARGUMENTS (fndecl))
     772              :     {
     773           54 :       tree *last_a = &DECL_ARGUMENTS (fn);
     774          146 :       for (tree p = DECL_ARGUMENTS (fndecl); p; p = TREE_CHAIN (p))
     775              :         {
     776           92 :           *last_a = copy_decl (p);
     777           92 :           suppress_warning (*last_a);
     778           92 :           DECL_CONTEXT (*last_a) = fn;
     779           92 :           last_a = &TREE_CHAIN (*last_a);
     780              :         }
     781              :     }
     782              : 
     783           59 :   tree orig_fn_value_type = TREE_TYPE (TREE_TYPE (fn));
     784           59 :   if (!pre && !VOID_TYPE_P (orig_fn_value_type))
     785              :     {
     786              :       /* For post contracts that deal with a non-void function, append a
     787              :          parameter to pass the return value.  */
     788           35 :       tree name = get_identifier ("__r");
     789           35 :       tree parm = build_lang_decl (PARM_DECL, name, orig_fn_value_type);
     790           35 :       DECL_CONTEXT (parm) = fn;
     791           35 :       DECL_ARTIFICIAL (parm) = true;
     792           35 :       suppress_warning (parm);
     793           35 :       DECL_ARGUMENTS (fn) = chainon (DECL_ARGUMENTS (fn), parm);
     794           35 :       *last = build_tree_list (NULL_TREE, orig_fn_value_type);
     795           35 :       last = &TREE_CHAIN (*last);
     796              :     }
     797              : 
     798           59 :   *last = void_list_node;
     799              : 
     800           59 :   tree adjusted_type = NULL_TREE;
     801              : 
     802              :   /* The handlers are void fns.  */
     803           59 :   if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl))
     804           36 :     adjusted_type = build_method_type_directly (DECL_CONTEXT (fndecl),
     805              :                                                 void_type_node,
     806              :                                                 arg_types);
     807              :   else
     808           23 :     adjusted_type = build_function_type (void_type_node, arg_types);
     809              : 
     810              :   /* If the original function is noexcept, build a noexcept function.  */
     811           59 :   if (flag_exceptions && type_noexcept_p (TREE_TYPE (fndecl)))
     812            8 :     adjusted_type = build_exception_variant (adjusted_type, noexcept_true_spec);
     813              : 
     814           59 :   TREE_TYPE (fn) = adjusted_type;
     815           59 :   DECL_RESULT (fn) = NULL_TREE; /* Let the start function code fill it in.  */
     816              : 
     817              :   /* The contract check functions are never a cdtor, nor virtual.  */
     818           59 :   DECL_CXX_DESTRUCTOR_P (fn) = DECL_CXX_CONSTRUCTOR_P (fn) = 0;
     819           59 :   DECL_VIRTUAL_P (fn) = false;
     820              : 
     821              :   /* Append .pre / .post to a usable name for the original function.  */
     822           59 :   contracts_fixup_names (fn, fndecl, pre, /*wrapper*/false);
     823              : 
     824           59 :   DECL_INITIAL (fn) = NULL_TREE;
     825          104 :   CONTRACT_HELPER (fn) = pre ? ldf_contract_pre : ldf_contract_post;
     826              :   /* We might have a pre/post for a wrapper.  */
     827           59 :   DECL_CONTRACT_WRAPPER (fn) = DECL_CONTRACT_WRAPPER (fndecl);
     828              : 
     829              :   /* Make these functions internal if we can, i.e. if the guarded function is
     830              :      not vague linkage, or if we can put them in a comdat group with the
     831              :      guarded function.  */
     832           59 :   if (!DECL_WEAK (fndecl) || HAVE_COMDAT_GROUP)
     833              :     {
     834           59 :       TREE_PUBLIC (fn) = false;
     835           59 :       DECL_EXTERNAL (fn) = false;
     836           59 :       DECL_WEAK (fn) = false;
     837           59 :       DECL_COMDAT (fn) = false;
     838              : 
     839              :       /* We may not have set the comdat group on the guarded function yet.
     840              :          If we haven't, we'll add this to the same group in comdat_linkage
     841              :          later.  Otherwise, add it to the same comdat group now.  */
     842           59 :       if (DECL_ONE_ONLY (fndecl))
     843              :         {
     844            0 :           symtab_node *n = symtab_node::get (fndecl);
     845            0 :           cgraph_node::get_create (fn)->add_to_same_comdat_group (n);
     846              :         }
     847              : 
     848              :     }
     849              : 
     850           59 :   DECL_INTERFACE_KNOWN (fn) = true;
     851           59 :   DECL_ARTIFICIAL (fn) = true;
     852           59 :   suppress_warning (fn);
     853              : 
     854           59 :   return fn;
     855              : }
     856              : 
     857              : /* Build the precondition checking function for FNDECL.  */
     858              : 
     859              : static tree
     860           26 : build_precondition_function (tree fndecl)
     861              : {
     862           26 :   if (!has_active_preconditions (fndecl))
     863              :     return NULL_TREE;
     864              : 
     865           14 :   return build_contract_condition_function (fndecl, /*pre=*/true);
     866              : }
     867              : 
     868              : /* Build the postcondition checking function for FNDECL.  If the return
     869              :    type is undeduced, don't build the function yet.  We do that in
     870              :    apply_deduced_return_type.  */
     871              : 
     872              : static tree
     873           57 : build_postcondition_function (tree fndecl)
     874              : {
     875           57 :   if (!has_active_postconditions (fndecl))
     876              :     return NULL_TREE;
     877              : 
     878           45 :   tree type = TREE_TYPE (TREE_TYPE (fndecl));
     879           45 :   if (is_auto (type))
     880              :     return NULL_TREE;
     881              : 
     882           45 :   return build_contract_condition_function (fndecl, /*pre=*/false);
     883              : }
     884              : 
     885              : /* If we're outlining the contract, build the functions to do the
     886              :    precondition and postcondition checks, and associate them with
     887              :    the function decl FNDECL.
     888              :  */
     889              : 
     890              : static void
     891           26 : build_contract_function_decls (tree fndecl)
     892              : {
     893              :   /* Build the pre/post functions (or not).  */
     894           26 :   if (!get_precondition_function (fndecl))
     895           26 :     if (tree pre = build_precondition_function (fndecl))
     896           14 :       set_precondition_function (fndecl, pre);
     897              : 
     898           26 :   if (!get_postcondition_function (fndecl))
     899           26 :     if (tree post = build_postcondition_function (fndecl))
     900           14 :       set_postcondition_function (fndecl, post);
     901           26 : }
     902              : 
     903              : /* Map from FUNCTION_DECL to a FUNCTION_DECL for contract wrapper.  */
     904              : 
     905              : static GTY(()) hash_map<tree, tree> *decl_wrapper_fn = nullptr;
     906              : 
     907              : /* Map from the function decl of a wrapper to the function that it wraps.  */
     908              : 
     909              : static GTY(()) hash_map<tree, tree> *decl_for_wrapper = nullptr;
     910              : 
     911              : /* Makes wrapper the precondition function for FNDECL.  */
     912              : 
     913              : static void
     914           28 : set_contract_wrapper_function (tree fndecl, tree wrapper)
     915              : {
     916           28 :   gcc_checking_assert (wrapper && fndecl);
     917           28 :   hash_map_maybe_create<hm_ggc> (decl_wrapper_fn);
     918           28 :   gcc_checking_assert (decl_wrapper_fn && !decl_wrapper_fn->get (fndecl));
     919           28 :   decl_wrapper_fn->put (fndecl, wrapper);
     920              : 
     921              :   /* We need to know the wrapped function when composing the diagnostic.  */
     922           28 :   hash_map_maybe_create<hm_ggc> (decl_for_wrapper);
     923           28 :   gcc_checking_assert (decl_for_wrapper && !decl_for_wrapper->get (wrapper));
     924           28 :   decl_for_wrapper->put (wrapper, fndecl);
     925           28 : }
     926              : 
     927              : /* Returns the wrapper function decl for FNDECL, or null if not set.  */
     928              : 
     929              : static tree
     930           28 : get_contract_wrapper_function (tree fndecl)
     931              : {
     932           28 :   gcc_checking_assert (fndecl);
     933           28 :   tree *result = hash_map_safe_get (decl_wrapper_fn, fndecl);
     934           13 :   return result ? *result : NULL_TREE;
     935              : }
     936              : 
     937              : /* Given a wrapper function WRAPPER, find the original function decl.  */
     938              : 
     939              : static tree
     940           40 : get_orig_func_for_wrapper (tree wrapper)
     941              : {
     942           40 :   gcc_checking_assert (wrapper);
     943           40 :   tree *result = hash_map_safe_get (decl_for_wrapper, wrapper);
     944           40 :   return result ? *result : NULL_TREE;
     945              : }
     946              : 
     947              : /* Build a declaration for the contract wrapper of a caller FNDECL.
     948              :    We're making a caller side contract check wrapper. For caller side contract
     949              :    checks, postconditions are only checked if check_post is true.
     950              :    Defer the attachment of the contracts to this function until the callee
     951              :    is non-dependent, or we get cases where the conditions can be non-dependent
     952              :    but still need tsubst-ing.  */
     953              : 
     954              : static tree
     955           28 : build_contract_wrapper_function (tree fndecl)
     956              : {
     957           28 :   if (error_operand_p (fndecl))
     958            0 :     return error_mark_node;
     959              : 
     960              :   /* We should not be trying to build wrappers for templates or functions that
     961              :      are still dependent.  */
     962           28 :   gcc_checking_assert (!processing_template_decl
     963              :                        && !TYPE_DEPENDENT_P (TREE_TYPE (fndecl)));
     964              : 
     965           28 :   location_t loc = DECL_SOURCE_LOCATION (fndecl);
     966              : 
     967              :   /* Fill in the names later.  */
     968           28 :   tree wrapdecl
     969           28 :     = build_lang_decl_loc (loc, FUNCTION_DECL, NULL_TREE, TREE_TYPE (fndecl));
     970              : 
     971              :   /* Put the wrapper in the same context as the callee.  */
     972           28 :   DECL_CONTEXT (wrapdecl) = DECL_CONTEXT (fndecl);
     973              : 
     974              :   /* This declaration is a contract wrapper function.  */
     975           28 :   DECL_CONTRACT_WRAPPER (wrapdecl) = true;
     976              : 
     977           28 :   contracts_fixup_names (wrapdecl, fndecl, /*pre*/false, /*wrapper*/true);
     978              : 
     979           28 :   DECL_SOURCE_LOCATION (wrapdecl) = loc;
     980              :   /* The declaration was implicitly generated by the compiler.  */
     981           28 :   DECL_ARTIFICIAL (wrapdecl) = true;
     982              :   /* Declaration, no definition yet.  */
     983           28 :   DECL_INITIAL (wrapdecl) = NULL_TREE;
     984              : 
     985              :   /* Let the start function code fill in the result decl.  */
     986           28 :   DECL_RESULT (wrapdecl) = NULL_TREE;
     987              : 
     988              :   /* Copy the function parameters, if present.  Suppress (e.g. unused)
     989              :      warnings on them.  */
     990           28 :   DECL_ARGUMENTS (wrapdecl) = NULL_TREE;
     991           28 :   if (tree p = DECL_ARGUMENTS (fndecl))
     992              :     {
     993           28 :       tree *last_a = &DECL_ARGUMENTS (wrapdecl);
     994           87 :       for (; p; p = TREE_CHAIN (p))
     995              :         {
     996           59 :           *last_a = copy_decl (p);
     997           59 :           suppress_warning (*last_a);
     998           59 :           DECL_CONTEXT (*last_a) = wrapdecl;
     999           59 :           last_a = &TREE_CHAIN (*last_a);
    1000              :         }
    1001              :     }
    1002              : 
    1003              :   /* Copy selected attributes from the original function.  */
    1004           28 :   TREE_USED (wrapdecl) = TREE_USED (fndecl);
    1005              : 
    1006              :   /* Copy any alignment added.  */
    1007           28 :   if (DECL_ALIGN (fndecl))
    1008           28 :     SET_DECL_ALIGN (wrapdecl, DECL_ALIGN (fndecl));
    1009           28 :   DECL_USER_ALIGN (wrapdecl) = DECL_USER_ALIGN (fndecl);
    1010              : 
    1011              :   /* Make this function internal.  */
    1012           28 :   TREE_PUBLIC (wrapdecl) = false;
    1013           28 :   DECL_EXTERNAL (wrapdecl) = false;
    1014           28 :   DECL_WEAK (wrapdecl) = false;
    1015              : 
    1016              :   /* We know this is an internal function.  */
    1017           28 :   DECL_INTERFACE_KNOWN (wrapdecl) = true;
    1018           28 :   return wrapdecl;
    1019              : }
    1020              : 
    1021              : static tree
    1022           28 : get_or_create_contract_wrapper_function (tree fndecl)
    1023              : {
    1024           28 :   tree wrapdecl = get_contract_wrapper_function (fndecl);
    1025           28 :   if (!wrapdecl)
    1026              :     {
    1027           28 :       wrapdecl = build_contract_wrapper_function (fndecl);
    1028           28 :       set_contract_wrapper_function (fndecl, wrapdecl);
    1029              :     }
    1030           28 :   return wrapdecl;
    1031              : }
    1032              : 
    1033              : void
    1034    168707840 : start_function_contracts (tree fndecl)
    1035              : {
    1036    168707840 :   if (error_operand_p (fndecl))
    1037              :     return;
    1038              : 
    1039    168707840 :   if (!handle_contracts_p (fndecl))
    1040              :     return;
    1041              : 
    1042              :   /* If this is not a client side check and definition side checks are
    1043              :      disabled, do nothing.  */
    1044          608 :   if (!flag_contracts_definition_check
    1045          608 :       && !DECL_CONTRACT_WRAPPER (fndecl))
    1046              :     return;
    1047              : 
    1048              :   /* Check that the postcondition result name, if any, does not shadow a
    1049              :      function parameter.  */
    1050          606 :   if (tree specs = get_fn_contract_specifiers (fndecl))
    1051         1522 :     for (tree ca : tree_vec_range (specs))
    1052          916 :       if (POSTCONDITION_P (ca))
    1053          377 :         if (tree id = POSTCONDITION_IDENTIFIER (ca))
    1054              :           {
    1055          168 :             if (id == error_mark_node)
    1056              :               {
    1057            3 :                 CONTRACT_CONDITION (ca) = error_mark_node;
    1058            3 :                 continue;
    1059              :               }
    1060          165 :             tree r_name = tree_strip_any_location_wrapper (id);
    1061          165 :             if (TREE_CODE (id) == PARM_DECL)
    1062          165 :               r_name = DECL_NAME (id);
    1063          165 :             gcc_checking_assert (r_name
    1064              :                                  && TREE_CODE (r_name) == IDENTIFIER_NODE);
    1065          165 :             tree seen = lookup_name (r_name);
    1066          165 :             if (seen
    1067            3 :                 && TREE_CODE (seen) == PARM_DECL
    1068          168 :                 && DECL_CONTEXT (seen) == fndecl)
    1069              :               {
    1070            3 :                 auto_diagnostic_group d;
    1071            3 :                 location_t id_l = location_wrapper_p (id)
    1072            3 :                                   ? EXPR_LOCATION (id)
    1073            3 :                                   : DECL_SOURCE_LOCATION (id);
    1074            3 :                 location_t co_l = EXPR_LOCATION (ca);
    1075            3 :                 if (id_l != UNKNOWN_LOCATION)
    1076            3 :                   co_l = make_location (id_l, co_l, co_l);
    1077            3 :                 error_at (co_l, "contract postcondition result name shadows a"
    1078              :                           " function parameter");
    1079            3 :                 inform (DECL_SOURCE_LOCATION (seen),
    1080              :                         "parameter declared here");
    1081            3 :                 POSTCONDITION_IDENTIFIER (ca) = error_mark_node;
    1082            3 :                 CONTRACT_CONDITION (ca) = error_mark_node;
    1083            3 :               }
    1084              :           }
    1085              : 
    1086              :   /* If we are expanding contract assertions inline then no need to declare
    1087              :      the outline function decls.  */
    1088          606 :   if (!flag_contract_checks_outlined)
    1089              :     return;
    1090              : 
    1091              :   /* Contracts may have just been added without a chance to parse them, though
    1092              :      we still need the PRE_FN available to generate a call to it.  */
    1093              :   /* Do we already have declarations generated ? */
    1094           26 :   if (!DECL_PRE_FN (fndecl) && !DECL_POST_FN (fndecl))
    1095           26 :     build_contract_function_decls (fndecl);
    1096              : }
    1097              : 
    1098              : void
    1099      1077061 : maybe_update_postconditions (tree fndecl)
    1100              : {
    1101              :   /* Update any postconditions and the postcondition checking function
    1102              :      as needed.  If there are postconditions, we'll use those to rewrite
    1103              :      return statements to check postconditions.  */
    1104      1077061 :   if (has_active_postconditions (fndecl))
    1105              :     {
    1106           31 :       rebuild_postconditions (fndecl);
    1107           31 :       tree post = build_postcondition_function (fndecl);
    1108           31 :       set_postcondition_function (fndecl, post);
    1109              :     }
    1110      1077061 : }
    1111              : 
    1112              : /* Build and return an argument list containing all the parameters of the
    1113              :    (presumably guarded) function decl FNDECL.  This can be used to forward
    1114              :    all of FNDECL arguments to a function taking the same list of arguments
    1115              :    -- namely the unchecked form of FNDECL.
    1116              : 
    1117              :    We use CALL_FROM_THUNK_P instead of forward_parm for forwarding
    1118              :    semantics.  */
    1119              : 
    1120              : static vec<tree, va_gc> *
    1121           56 : build_arg_list (tree fndecl)
    1122              : {
    1123           56 :   vec<tree, va_gc> *args = make_tree_vector ();
    1124          155 :   for (tree t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t))
    1125           99 :     vec_safe_push (args, t);
    1126           56 :   return args;
    1127              : }
    1128              : 
    1129              : /* Build and return a thunk like call to FUNC from CALLER using the supplied
    1130              :    arguments.  The call is like a thunk call in the fact that we do not
    1131              :    want to create additional copies of the arguments.  We can not simply reuse
    1132              :    the thunk machinery as it does more than we want.  More specifically, we
    1133              :    don't want to mark the calling function as `DECL_THUNK_P` for this
    1134              :    particular purpose, we only want the special treatment for the parameters
    1135              :    of the call we are about to generate.  We temporarily mark the calling
    1136              :    function as DECL_THUNK_P so build_call_a does the right thing.  */
    1137              : 
    1138              : static tree
    1139           56 : build_thunk_like_call (tree func, int n, tree *argarray)
    1140              : {
    1141           56 :   bool old_decl_thunk_p = DECL_THUNK_P (current_function_decl);
    1142           56 :   LANG_DECL_FN_CHECK (current_function_decl)->thunk_p  = true;
    1143              : 
    1144           56 :   tree call = build_call_a (func, n, argarray);
    1145              : 
    1146              :   /* Revert the `DECL_THUNK_P` flag.  */
    1147           56 :   LANG_DECL_FN_CHECK (current_function_decl)->thunk_p = old_decl_thunk_p;
    1148              : 
    1149              :   /* Mark the call as a thunk call to allow for correct gimplification
    1150              :    of the arguments.  */
    1151           56 :   CALL_FROM_THUNK_P (call) = true;
    1152              : 
    1153           56 :   return call;
    1154              : }
    1155              : 
    1156              : /* If we have a precondition function and it's valid, call it.  */
    1157              : 
    1158              : static void
    1159           14 : add_pre_condition_fn_call (tree fndecl)
    1160              : {
    1161              :   /* If we're starting a guarded function with valid contracts, we need to
    1162              :      insert a call to the pre function.  */
    1163           14 :   gcc_checking_assert (DECL_PRE_FN (fndecl)
    1164              :                        && DECL_PRE_FN (fndecl) != error_mark_node);
    1165              : 
    1166           14 :   releasing_vec args = build_arg_list (fndecl);
    1167           14 :   tree call = build_thunk_like_call (DECL_PRE_FN (fndecl),
    1168           14 :                                      args->length (), args->address ());
    1169              : 
    1170           14 :   finish_expr_stmt (call);
    1171           14 : }
    1172              : 
    1173              : /* Returns the parameter corresponding to the return value of a guarded
    1174              :    function FNDECL.  Returns NULL_TREE if FNDECL has no postconditions or
    1175              :    is void.  */
    1176              : 
    1177              : static tree
    1178           14 : get_postcondition_result_parameter (tree fndecl)
    1179              : {
    1180           14 :   if (!fndecl || fndecl == error_mark_node)
    1181              :     return NULL_TREE;
    1182              : 
    1183           14 :   if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))))
    1184              :     return NULL_TREE;
    1185              : 
    1186            4 :   tree post = DECL_POST_FN (fndecl);
    1187            4 :   if (!post || post == error_mark_node)
    1188              :     return NULL_TREE;
    1189              : 
    1190              :   /* The last param is the return value.  */
    1191            4 :   return tree_last (DECL_ARGUMENTS (post));
    1192              : }
    1193              : 
    1194              : /* Build and add a call to the post-condition checking function, when that
    1195              :    is in use.  */
    1196              : 
    1197              : static void
    1198           14 : add_post_condition_fn_call (tree fndecl)
    1199              : {
    1200           14 :   gcc_checking_assert (DECL_POST_FN (fndecl)
    1201              :                        && DECL_POST_FN (fndecl) != error_mark_node);
    1202              : 
    1203           14 :   releasing_vec args = build_arg_list (fndecl);
    1204           14 :   if (get_postcondition_result_parameter (fndecl))
    1205            4 :     vec_safe_push (args, DECL_RESULT (fndecl));
    1206           14 :   tree call = build_thunk_like_call (DECL_POST_FN (fndecl),
    1207           14 :                                      args->length (), args->address ());
    1208           14 :   finish_expr_stmt (call);
    1209           14 : }
    1210              : 
    1211              : /* Copy (possibly a sub-set of) contracts from CONTRACTS on FNDECL.  */
    1212              : 
    1213              : static tree
    1214          653 : copy_contracts_list (tree contracts, tree fndecl,
    1215              :                      contract_match_kind remap_kind = cmk_all)
    1216              : {
    1217          653 :   if (!contracts)
    1218              :     return NULL_TREE;
    1219              : 
    1220          653 :   auto_vec<tree> copies (TREE_VEC_LENGTH (contracts));
    1221         1740 :   for (tree contract : tree_vec_range (contracts))
    1222              :     {
    1223         1087 :       if ((remap_kind == cmk_pre
    1224          619 :            && TREE_CODE (contract) == POSTCONDITION_STMT)
    1225          991 :           || (remap_kind == cmk_post
    1226          468 :               && TREE_CODE (contract) == PRECONDITION_STMT))
    1227          203 :         continue;
    1228              : 
    1229          884 :       tree c = copy_node (contract);
    1230              : 
    1231          884 :       copy_body_data id;
    1232          884 :       hash_map<tree, tree> decl_map;
    1233              : 
    1234          884 :       memset (&id, 0, sizeof (id));
    1235              : 
    1236          884 :       id.src_fn = fndecl;
    1237          884 :       id.dst_fn = fndecl;
    1238          884 :       id.src_cfun = DECL_STRUCT_FUNCTION (fndecl);
    1239          884 :       id.decl_map = &decl_map;
    1240              : 
    1241          884 :       id.copy_decl = retain_decl;
    1242              : 
    1243          884 :       id.transform_call_graph_edges = CB_CGE_DUPLICATE;
    1244          884 :       id.transform_new_cfg = false;
    1245          884 :       id.transform_return_to_modify = false;
    1246          884 :       id.transform_parameter = true;
    1247              : 
    1248              :       /* Make sure not to unshare trees behind the front-end's back
    1249              :          since front-end specific mechanisms may rely on sharing.  */
    1250          884 :       id.regimplify = false;
    1251          884 :       id.do_not_unshare = true;
    1252          884 :       id.do_not_fold = true;
    1253              : 
    1254              :       /* We're not inside any EH region.  */
    1255          884 :       id.eh_lp_nr = 0;
    1256          884 :       walk_tree (&CONTRACT_CONDITION (c), copy_tree_body_r, &id, NULL);
    1257              : 
    1258          884 :       CONTRACT_COMMENT (c) = copy_node (CONTRACT_COMMENT (c));
    1259              : 
    1260          884 :       copies.quick_push (c);
    1261          884 :     }
    1262              : 
    1263          653 :   if (copies.is_empty ())
    1264              :     return NULL_TREE;
    1265              : 
    1266          653 :   tree new_contracts = make_tree_vec (copies.length ());
    1267         2190 :   for (unsigned ix = 0; ix < copies.length (); ix++)
    1268          884 :     TREE_VEC_ELT (new_contracts, ix) = copies[ix];
    1269              :   return new_contracts;
    1270          653 : }
    1271              : 
    1272              : /* Returns a copy of FNDECL contracts. This is used when emitting a contract.
    1273              :  If we were to emit the original contract tree, any folding of the contract
    1274              :  condition would affect the original contract too. The original contract
    1275              :  tree needs to be preserved in case it is used to apply to a different
    1276              :  function (for inheritance or wrapping reasons). */
    1277              : 
    1278              : static tree
    1279          653 : copy_contracts (tree fndecl, contract_match_kind remap_kind = cmk_all)
    1280              : {
    1281          653 :   tree contracts = get_fn_contract_specifiers (fndecl);
    1282          653 :   return copy_contracts_list (contracts, fndecl, remap_kind);
    1283              : }
    1284              : 
    1285              : /* Add the contract statement CONTRACT to the current block if valid.  */
    1286              : 
    1287              : static bool
    1288          916 : emit_contract_statement (tree contract)
    1289              : {
    1290              :   /* Only add valid contracts.  */
    1291          916 :   if (contract == error_mark_node
    1292          916 :       || CONTRACT_CONDITION (contract) == error_mark_node)
    1293              :     return false;
    1294              : 
    1295          899 :   if (get_evaluation_semantic (contract) == CES_INVALID)
    1296              :     return false;
    1297              : 
    1298          899 :   add_stmt (contract);
    1299          899 :   return true;
    1300              : }
    1301              : 
    1302              : /* Add a call or a direct evaluation of the pre checks.  */
    1303              : 
    1304              : static void
    1305          427 : apply_preconditions (tree fndecl)
    1306              : {
    1307          427 :   if (flag_contract_checks_outlined)
    1308           14 :     add_pre_condition_fn_call (fndecl);
    1309              :   else
    1310              :   {
    1311          413 :     if (tree contract_copy = copy_contracts (fndecl, cmk_pre))
    1312          936 :       for (tree contract : tree_vec_range (contract_copy))
    1313          523 :         emit_contract_statement (contract);
    1314              :   }
    1315          427 : }
    1316              : 
    1317              : /* Add a call or a direct evaluation of the post checks.  */
    1318              : 
    1319              : static void
    1320          254 : apply_postconditions (tree fndecl)
    1321              : {
    1322          254 :   if (flag_contract_checks_outlined)
    1323           14 :     add_post_condition_fn_call (fndecl);
    1324              :   else
    1325              :     {
    1326          240 :       if (tree contract_copy = copy_contracts (fndecl, cmk_post))
    1327          601 :         for (tree contract : tree_vec_range (contract_copy))
    1328          361 :           emit_contract_statement (contract);
    1329              :     }
    1330          254 : }
    1331              : 
    1332              : /* Add contract handling to the function in FNDECL.
    1333              : 
    1334              :    When we have only pre-conditions, this simply prepends a call (or a direct
    1335              :    evaluation, for cdtors) to the existing function body.
    1336              : 
    1337              :    When we have post conditions we build a try-finally block.
    1338              :    If the function might throw then the handler in the try-finally is an
    1339              :    EH_ELSE expression, where the post condition check is applied to the
    1340              :    non-exceptional path, and an empty statement is added to the EH path.  If
    1341              :    the function has a non-throwing eh spec, then the handler is simply the
    1342              :    post-condition checker.  */
    1343              : 
    1344              : void
    1345    151970183 : maybe_apply_function_contracts (tree fndecl)
    1346              : {
    1347    151970183 :   if (!handle_contracts_p (fndecl))
    1348              :     /* We did nothing and the original function body statement list will be
    1349              :        popped by our caller.  */
    1350              :     return;
    1351              : 
    1352              :   /* If this is not a client side check and definition side checks are
    1353              :      disabled, do nothing.  */
    1354          608 :   if (!flag_contracts_definition_check
    1355          608 :       && !DECL_CONTRACT_WRAPPER (fndecl))
    1356              :     return;
    1357              : 
    1358          606 :   bool do_pre = has_active_preconditions (fndecl);
    1359          606 :   bool do_post = has_active_postconditions (fndecl);
    1360              :   /* We should not have reached here with nothing to do... */
    1361          606 :   gcc_checking_assert (do_pre || do_post);
    1362              : 
    1363              :   /* If the function is noexcept, the user's written body will be wrapped in a
    1364              :      MUST_NOT_THROW expression.  In that case we leave the MUST_NOT_THROW in
    1365              :      place and do our replacement inside it.  */
    1366          606 :   tree fnbody;
    1367          606 :   if (TYPE_NOEXCEPT_P (TREE_TYPE (fndecl)))
    1368              :     {
    1369           42 :       tree m_n_t_expr = expr_first (DECL_SAVED_TREE (fndecl));
    1370           42 :       gcc_checking_assert (TREE_CODE (m_n_t_expr) == MUST_NOT_THROW_EXPR);
    1371           42 :       fnbody = TREE_OPERAND (m_n_t_expr, 0);
    1372           42 :       TREE_OPERAND (m_n_t_expr, 0) = push_stmt_list ();
    1373              :     }
    1374              :   else
    1375              :     {
    1376          564 :       fnbody = DECL_SAVED_TREE (fndecl);
    1377          564 :       DECL_SAVED_TREE (fndecl) = push_stmt_list ();
    1378              :     }
    1379              : 
    1380              :   /* If we have a lambda with captures, ensure that those captures are in-
    1381              :      scope for pre and post conditions.  */
    1382          628 :   if (LAMBDA_FUNCTION_P (fndecl)
    1383          628 :       && TREE_CODE (fnbody) == BIND_EXPR)
    1384              :     {
    1385            0 :       tree extract = BIND_EXPR_BODY (fnbody);
    1386            0 :       BIND_EXPR_BODY (fnbody) = NULL_TREE;
    1387            0 :       add_stmt (fnbody);
    1388            0 :       BIND_EXPR_BODY (fnbody) = push_stmt_list ();
    1389            0 :       fnbody = extract;
    1390              :     }
    1391              : 
    1392              :   /* Now add the pre and post conditions to the existing function body.
    1393              :      This copies the approach used for function try blocks.  */
    1394          606 :   tree compound_stmt = begin_compound_stmt (0);
    1395          606 :   current_binding_level->artificial = true;
    1396              : 
    1397              :   /* Do not add locations for the synthesised code.  */
    1398          606 :   location_t loc = UNKNOWN_LOCATION;
    1399              : 
    1400              :   /* For other cases, we call a function to process the check.  */
    1401              : 
    1402              :   /* If we have a pre, but not a post, then just emit that and we are done.  */
    1403          606 :   if (!do_post)
    1404              :     {
    1405          352 :       apply_preconditions (fndecl);
    1406          352 :       add_stmt (fnbody);
    1407          352 :       finish_compound_stmt (compound_stmt);
    1408          352 :       return;
    1409              :     }
    1410              : 
    1411          254 :   if (do_pre)
    1412              :     /* Add a precondition call, if we have one. */
    1413           75 :     apply_preconditions (fndecl);
    1414          254 :   tree try_fin = build_stmt (loc, TRY_FINALLY_EXPR, fnbody, NULL_TREE);
    1415          254 :   add_stmt (try_fin);
    1416          254 :   TREE_OPERAND (try_fin, 1) = push_stmt_list ();
    1417              :   /* If we have exceptions, and a function that might throw, then add
    1418              :      an EH_ELSE clause that allows the exception to propagate upwards
    1419              :      without encountering the post-condition checks.  */
    1420          254 :   if (flag_exceptions && !type_noexcept_p (TREE_TYPE (fndecl)))
    1421              :     {
    1422          240 :       tree eh_else = build_stmt (loc, EH_ELSE_EXPR, NULL_TREE, NULL_TREE);
    1423          240 :       add_stmt (eh_else);
    1424          240 :       TREE_OPERAND (eh_else, 0) = push_stmt_list ();
    1425          240 :       apply_postconditions (fndecl);
    1426          240 :       TREE_OPERAND (eh_else, 0) = pop_stmt_list (TREE_OPERAND (eh_else, 0));
    1427          240 :       TREE_OPERAND (eh_else, 1) = void_node;
    1428              :     }
    1429              :   else
    1430           14 :     apply_postconditions (fndecl);
    1431          254 :   TREE_OPERAND (try_fin, 1) = pop_stmt_list (TREE_OPERAND (try_fin, 1));
    1432          254 :   finish_compound_stmt (compound_stmt);
    1433              :   /* The DECL_SAVED_TREE stmt list will be popped by our caller.  */
    1434              : }
    1435              : 
    1436              : /* Rewrite the condition of contract in place, so that references to SRC's
    1437              :    parameters are updated to refer to DST's parameters. The postcondition
    1438              :    result variable is left unchanged.
    1439              : 
    1440              :    When declarations are merged, we sometimes need to update contracts to
    1441              :    refer to new parameters.
    1442              : 
    1443              :    If DUPLICATE_P is true, this is called by duplicate_decls to rewrite
    1444              :    contracts in terms of a new set of parameters.  This also preserves the
    1445              :    references to postcondition results, which are not replaced during
    1446              :    merging.  */
    1447              : 
    1448              : static void
    1449          356 : remap_contract (tree src, tree dst, tree contract, bool duplicate_p)
    1450              : {
    1451          356 :   copy_body_data id;
    1452          356 :   hash_map<tree, tree> decl_map;
    1453              : 
    1454          356 :   memset (&id, 0, sizeof (id));
    1455          356 :   id.src_fn = src;
    1456          356 :   id.dst_fn = dst;
    1457          356 :   id.src_cfun = DECL_STRUCT_FUNCTION (src);
    1458          356 :   id.decl_map = &decl_map;
    1459              : 
    1460              :   /* If we're merging contracts, don't copy local variables.  */
    1461          356 :   id.copy_decl = duplicate_p ? retain_decl : copy_decl_no_change;
    1462              : 
    1463          356 :   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
    1464          356 :   id.transform_new_cfg = false;
    1465          356 :   id.transform_return_to_modify = false;
    1466          356 :   id.transform_parameter = true;
    1467              : 
    1468              :   /* Make sure not to unshare trees behind the front-end's back
    1469              :      since front-end specific mechanisms may rely on sharing.  */
    1470          356 :   id.regimplify = false;
    1471          356 :   id.do_not_unshare = true;
    1472          356 :   id.do_not_fold = true;
    1473              : 
    1474              :   /* We're not inside any EH region.  */
    1475          356 :   id.eh_lp_nr = 0;
    1476              : 
    1477          356 :   bool do_remap = false;
    1478              : 
    1479              :   /* Insert parameter remappings.  */
    1480          356 :   gcc_checking_assert (TREE_CODE (src) == FUNCTION_DECL);
    1481          356 :   gcc_checking_assert (TREE_CODE (dst) == FUNCTION_DECL);
    1482              : 
    1483          356 :   int src_num_artificial_args = num_artificial_parms_for (src);
    1484          356 :   int dst_num_artificial_args = num_artificial_parms_for (dst);
    1485              : 
    1486          356 :   for (tree sp = DECL_ARGUMENTS (src), dp = DECL_ARGUMENTS (dst);
    1487         1038 :        sp || dp;
    1488          682 :        sp = DECL_CHAIN (sp), dp = DECL_CHAIN (dp))
    1489              :     {
    1490          688 :       if (!sp && dp
    1491            6 :           && TREE_CODE (contract) == POSTCONDITION_STMT
    1492          694 :           && DECL_CHAIN (dp) == NULL_TREE)
    1493              :         {
    1494            6 :           gcc_assert (!duplicate_p);
    1495            6 :           if (tree result = POSTCONDITION_IDENTIFIER (contract))
    1496              :             {
    1497            6 :               gcc_assert (DECL_P (result));
    1498            6 :               insert_decl_map (&id, result, dp);
    1499            6 :               do_remap = true;
    1500              :             }
    1501              :           break;
    1502              :         }
    1503          682 :       gcc_assert (sp && dp);
    1504              : 
    1505          682 :       if (sp == dp)
    1506          304 :         continue;
    1507              : 
    1508          378 :       insert_decl_map (&id, sp, dp);
    1509          378 :       do_remap = true;
    1510              : 
    1511              :       /* First artificial arg is *this. We want to remap that.  However, we
    1512              :          want to skip _in_charge param and __vtt_parm.  Do so now.  */
    1513          378 :       if (src_num_artificial_args > 0)
    1514              :         {
    1515          113 :           while (--src_num_artificial_args,src_num_artificial_args > 0)
    1516            0 :             sp = DECL_CHAIN (sp);
    1517              :         }
    1518          378 :       if (dst_num_artificial_args > 0)
    1519              :         {
    1520          113 :           while (--dst_num_artificial_args,dst_num_artificial_args > 0)
    1521            0 :             dp = DECL_CHAIN (dp);
    1522              :         }
    1523              :     }
    1524              : 
    1525          356 :   if (!do_remap)
    1526          162 :     return;
    1527              : 
    1528          194 :   walk_tree (&CONTRACT_CONDITION (contract), copy_tree_body_r, &id, NULL);
    1529          356 : }
    1530              : 
    1531              : /* Returns a copy of SOURCE contracts where any references to SOURCE's
    1532              :    PARM_DECLs have been rewritten to the corresponding PARM_DECL in DEST.  */
    1533              : 
    1534              : tree
    1535          243 : copy_and_remap_contracts (tree dest, tree source,
    1536              :                           contract_match_kind remap_kind)
    1537              : {
    1538          243 :   tree contracts = get_fn_contract_specifiers (source);
    1539          243 :   if (!contracts)
    1540              :     return NULL_TREE;
    1541              : 
    1542          243 :   auto_vec<tree> copies (TREE_VEC_LENGTH (contracts));
    1543          571 :   for (tree contract : tree_vec_range (contracts))
    1544              :     {
    1545          328 :       if ((remap_kind == cmk_pre
    1546           10 :            && TREE_CODE (contract) == POSTCONDITION_STMT)
    1547          324 :           || (remap_kind == cmk_post
    1548            0 :               && TREE_CODE (contract) == PRECONDITION_STMT))
    1549            4 :         continue;
    1550              : 
    1551          324 :       tree stmt = copy_node (contract);
    1552              : 
    1553              :       /* If we have an erroneous postcondition identifier, we also mark the
    1554              :          condition as invalid so only need to check that.  */
    1555          324 :       if (CONTRACT_CONDITION (stmt) != error_mark_node)
    1556          324 :         remap_contract (source, dest, stmt, /*duplicate_p=*/true);
    1557              : 
    1558          324 :       if (TREE_CODE (stmt) == POSTCONDITION_STMT)
    1559              :         {
    1560              :           /* If we have a postcondition return value placeholder, then
    1561              :              ensure the copied one has the correct context.  */
    1562          110 :           tree var = POSTCONDITION_IDENTIFIER (stmt);
    1563          110 :           if (var && var != error_mark_node)
    1564           24 :             DECL_CONTEXT (var) = dest;
    1565              :         }
    1566              : 
    1567          324 :       if (CONTRACT_COMMENT (stmt) != error_mark_node)
    1568          324 :         CONTRACT_COMMENT (stmt) = copy_node (CONTRACT_COMMENT (stmt));
    1569              : 
    1570          324 :       copies.quick_push (stmt);
    1571              :     }
    1572              : 
    1573          243 :   if (copies.is_empty ())
    1574              :     return NULL_TREE;
    1575              : 
    1576          243 :   tree contracts_copy = make_tree_vec (copies.length ());
    1577          810 :   for (unsigned ix = 0; ix < copies.length (); ix++)
    1578          324 :     TREE_VEC_ELT (contracts_copy, ix) = copies[ix];
    1579              : 
    1580              :   return contracts_copy;
    1581          243 : }
    1582              : 
    1583              : /* Set the (maybe) parsed contract specifiers CONTRACTS for DECL.
    1584              :    CONTRACTS is either  NULL_TREE or a TREE_VEC of contract statements.  */
    1585              : 
    1586              : void
    1587         1788 : set_fn_contract_specifiers (tree decl, tree contracts)
    1588              : {
    1589         1788 :   if (!decl || error_operand_p (decl))
    1590            0 :     return;
    1591              : 
    1592         1788 :   gcc_checking_assert (!contracts || TREE_CODE (contracts) == TREE_VEC);
    1593              : 
    1594         1788 :   bool existed = false;
    1595         1788 :   contract_decl& rd
    1596         1788 :     = hash_map_safe_get_or_insert<hm_ggc> (contract_decl_map, decl, &existed);
    1597         1788 :   if (!existed)
    1598              :     {
    1599              :       /* This is the first time we encountered this decl, save the location
    1600              :          for error messages.  This will ensure all error messages refer to the
    1601              :          contracts used for the function.  */
    1602         1379 :       location_t decl_loc = DECL_SOURCE_LOCATION (decl);
    1603         1379 :       location_t cont_end = decl_loc;
    1604         1379 :       if (contracts)
    1605         1379 :         cont_end = get_contract_end_loc (contracts);
    1606         1379 :       rd.note_loc = make_location (decl_loc, decl_loc, cont_end);
    1607              :     }
    1608         1788 :   rd.contract_specifiers = contracts;
    1609              : }
    1610              : 
    1611              : /* Update the entry for DECL in the map of contract specifiers with the
    1612              :   contracts in CONTRACTS.  */
    1613              : 
    1614              : void
    1615          436 : update_fn_contract_specifiers (tree decl, tree contracts)
    1616              : {
    1617          436 :   if (!decl || error_operand_p (decl))
    1618            0 :     return;
    1619              : 
    1620          436 :   bool existed = false;
    1621          436 :   contract_decl& rd
    1622          436 :     = hash_map_safe_get_or_insert<hm_ggc> (contract_decl_map, decl, &existed);
    1623          436 :   gcc_checking_assert (existed);
    1624              : 
    1625              :   /* We should only get here when we parse deferred contracts.  */
    1626          436 :   gcc_checking_assert (!contract_any_deferred_p (contracts));
    1627              : 
    1628          436 :   rd.contract_specifiers = contracts;
    1629              : }
    1630              : 
    1631              : /* When a decl is about to be removed, then we need to release its content and
    1632              :    then take it out of the map.  */
    1633              : 
    1634              : void
    1635      1523343 : remove_decl_with_fn_contracts_specifiers (tree decl)
    1636              : {
    1637      1523546 :   if (contract_decl *p = hash_map_safe_get (contract_decl_map, decl))
    1638              :     {
    1639          164 :       p->contract_specifiers = NULL_TREE;
    1640          164 :       contract_decl_map->remove (decl);
    1641              :     }
    1642      1523343 : }
    1643              : 
    1644              : /* If this function has contract specifiers, then remove them, but leave the
    1645              :    function registered.  */
    1646              : 
    1647              : void
    1648       479311 : remove_fn_contract_specifiers (tree decl)
    1649              : {
    1650       479362 :   if (contract_decl *p = hash_map_safe_get (contract_decl_map, decl))
    1651              :     {
    1652           49 :       p->contract_specifiers = NULL_TREE;
    1653              :     }
    1654       479311 : }
    1655              : 
    1656              : /* Get the contract specifier list for this DECL if there is one.  */
    1657              : 
    1658              : tree
    1659    556540940 : get_fn_contract_specifiers (tree decl)
    1660              : {
    1661    557049325 :   if (contract_decl *p = hash_map_safe_get (contract_decl_map, decl))
    1662         9140 :     return p->contract_specifiers;
    1663              :   return NULL_TREE;
    1664              : }
    1665              : 
    1666              : /* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
    1667              :    guarded functions.  */
    1668              : 
    1669              : void
    1670     19829594 : check_redecl_contract (tree newdecl, tree olddecl)
    1671              : {
    1672     19829594 :   if (!flag_contracts)
    1673              :     return;
    1674              : 
    1675      1874508 :   if (TREE_CODE (newdecl) == TEMPLATE_DECL)
    1676       426360 :     newdecl = DECL_TEMPLATE_RESULT (newdecl);
    1677      1874508 :   if (TREE_CODE (olddecl) == TEMPLATE_DECL)
    1678       426360 :     olddecl = DECL_TEMPLATE_RESULT (olddecl);
    1679              : 
    1680      1874508 :   tree new_contracts = get_fn_contract_specifiers (newdecl);
    1681      1874508 :   tree old_contracts = get_fn_contract_specifiers (olddecl);
    1682              : 
    1683      1874508 :   if (!old_contracts && !new_contracts)
    1684              :     return;
    1685              : 
    1686              :   /* We should always be comparing with the 'first' declaration which should
    1687              :    have been recorded already (if it has contract specifiers).  However
    1688              :    if the new decl is trying to add contracts, that is an error and we do
    1689              :    not want to create a map entry yet.  */
    1690          199 :   contract_decl *rdp = hash_map_safe_get (contract_decl_map, olddecl);
    1691          199 :   gcc_checking_assert(rdp || !old_contracts);
    1692              : 
    1693          199 :   location_t new_loc = DECL_SOURCE_LOCATION (newdecl);
    1694          199 :   if (new_contracts && !old_contracts)
    1695              :     {
    1696           15 :       auto_diagnostic_group d;
    1697              :       /* If a re-declaration has contracts, they must be the same as those
    1698              :        that appear on the first declaration seen (they cannot be added).  */
    1699           15 :       location_t cont_end = get_contract_end_loc (new_contracts);
    1700           15 :       cont_end = make_location (new_loc, new_loc, cont_end);
    1701           15 :       error_at (cont_end, "declaration adds contracts to %q#D", olddecl);
    1702           15 :       inform (DECL_SOURCE_LOCATION (olddecl), "first declared here");
    1703           15 :       return;
    1704           15 :     }
    1705              : 
    1706          184 :   if (old_contracts && !new_contracts)
    1707              :     /* We allow re-declarations to omit contracts declared on the initial decl.
    1708              :        In fact, this is required if the conditions contain lambdas.  Check if
    1709              :        all the parameters are correctly const qualified. */
    1710          121 :     check_postconditions_in_redecl (olddecl, newdecl);
    1711           63 :   else if (old_contracts && new_contracts
    1712           63 :            && !contract_any_deferred_p (old_contracts)
    1713           57 :            && contract_any_deferred_p (new_contracts)
    1714           63 :            && DECL_UNIQUE_FRIEND_P (newdecl))
    1715              :     {
    1716              :       /* Put the deferred contracts on the olddecl so we parse it when
    1717              :          we can.  */
    1718            0 :       set_fn_contract_specifiers (olddecl, old_contracts);
    1719              :     }
    1720           63 :   else if (contract_any_deferred_p (old_contracts)
    1721           63 :            || contract_any_deferred_p (new_contracts))
    1722              :     {
    1723              :       /* TODO: ignore these and figure out how to process them later.  */
    1724              :       /* Note that a friend declaration has deferred contracts, but the
    1725              :          declaration of the same function outside the class definition
    1726              :          doesn't.  */
    1727              :     }
    1728              :   else
    1729              :     {
    1730           57 :       gcc_checking_assert (old_contracts);
    1731           57 :       location_t cont_end = get_contract_end_loc (new_contracts);
    1732           57 :       cont_end = make_location (new_loc, new_loc, cont_end);
    1733              :       /* We have two sets - they should match or we issue a diagnostic.  */
    1734           57 :       match_contract_specifiers (rdp->note_loc, old_contracts,
    1735              :                                  cont_end, new_contracts);
    1736              :     }
    1737              : 
    1738              :   return;
    1739              : }
    1740              : 
    1741              : /* Update the contracts of DEST to match the argument names from contracts
    1742              :   of SRC. When we merge two declarations in duplicate_decls, we preserve the
    1743              :   arguments from the new declaration, if the new declaration is a
    1744              :   definition. We need to update the contracts accordingly.  */
    1745              : 
    1746              : void
    1747     12347239 : update_contract_arguments (tree srcdecl, tree destdecl)
    1748              : {
    1749     12347239 :   tree src_contracts = get_fn_contract_specifiers (srcdecl);
    1750     12347239 :   tree dest_contracts = get_fn_contract_specifiers (destdecl);
    1751              : 
    1752     12347239 :   if (!src_contracts && !dest_contracts)
    1753              :     return;
    1754              : 
    1755              :   /* Check if src even has contracts. It is possible that a redeclaration
    1756              :     does not have contracts. Is this is the case, first apply contracts
    1757              :     to src.  */
    1758          130 :   if (!src_contracts)
    1759              :     {
    1760           91 :       if (contract_any_deferred_p (dest_contracts))
    1761              :         {
    1762            0 :           set_fn_contract_specifiers (srcdecl, dest_contracts);
    1763              :           /* Nothing more to do here.  */
    1764            0 :           return;
    1765              :         }
    1766              :       else
    1767           91 :         set_fn_contract_specifiers
    1768           91 :           (srcdecl, copy_and_remap_contracts (srcdecl, destdecl));
    1769              :     }
    1770              : 
    1771              :   /* For deferred contracts, we currently copy the tokens from the redeclaration
    1772              :     onto the decl that will be preserved. This is not ideal because the
    1773              :     redeclaration may have erroneous contracts.
    1774              :     For non deferred contracts we currently do copy and remap, which is doing
    1775              :     more than we need.  */
    1776          130 :   if (contract_any_deferred_p (src_contracts))
    1777            6 :     set_fn_contract_specifiers (destdecl, src_contracts);
    1778              :   else
    1779              :     {
    1780              :       /* Temporarily rename the arguments to get the right mapping.  */
    1781          124 :       tree tmp_arguments = DECL_ARGUMENTS (destdecl);
    1782          124 :       DECL_ARGUMENTS (destdecl) = DECL_ARGUMENTS (srcdecl);
    1783          124 :       set_fn_contract_specifiers (destdecl,
    1784              :                                   copy_and_remap_contracts (destdecl, srcdecl));
    1785          124 :       DECL_ARGUMENTS (destdecl) = tmp_arguments;
    1786              :     }
    1787              : }
    1788              : 
    1789              : /* Checks if a contract check wrapper is needed for fndecl.  */
    1790              : 
    1791              : static bool
    1792          379 : should_contract_wrap_call (bool do_pre, bool do_post)
    1793              : {
    1794              :   /* Only if the target function actually has any contracts.  */
    1795            0 :   if (!do_pre && !do_post)
    1796              :     return false;
    1797              : 
    1798              : 
    1799          379 :   return ((flag_contract_client_check > 1)
    1800          379 :           || ((flag_contract_client_check > 0)
    1801              :               && do_pre));
    1802              : }
    1803              : 
    1804              : /* Possibly replace call with a call to a wrapper function which
    1805              :    will do the contracts check required around a CALL to FNDECL.  */
    1806              : 
    1807              : tree
    1808    171124291 : maybe_contract_wrap_call (tree fndecl, tree call)
    1809              : {
    1810              :   /* We can be called from build_cxx_call without a known callee.  */
    1811    171124291 :   if (!fndecl)
    1812              :     return call;
    1813              : 
    1814    164413405 :   if (error_operand_p (fndecl) || !call || call == error_mark_node)
    1815            0 :     return error_mark_node;
    1816              : 
    1817    164413405 :   if (!handle_contracts_p (fndecl))
    1818              :     return call;
    1819              : 
    1820          379 :   bool do_pre = has_active_preconditions (fndecl);
    1821          379 :   bool do_post = has_active_postconditions (fndecl);
    1822              : 
    1823              :   /* Check if we need a wrapper.  */
    1824          387 :   if (!should_contract_wrap_call (do_pre, do_post))
    1825              :     return call;
    1826              : 
    1827              :   /* Build the declaration of the wrapper, if we need to.  */
    1828           28 :   tree wrapdecl = get_or_create_contract_wrapper_function (fndecl);
    1829              : 
    1830           28 :   unsigned nargs = call_expr_nargs (call);
    1831           28 :   vec<tree, va_gc> *argwrap;
    1832           28 :   vec_alloc (argwrap, nargs);
    1833              : 
    1834           28 :   tree arg;
    1835           28 :   call_expr_arg_iterator iter;
    1836          115 :   FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
    1837           59 :     argwrap->quick_push (arg);
    1838              : 
    1839           28 :   tree wrapcall = build_call_expr_loc_vec (DECL_SOURCE_LOCATION (wrapdecl),
    1840              :                                            wrapdecl, argwrap);
    1841              : 
    1842           28 :   return wrapcall;
    1843              : }
    1844              : 
    1845              : /* Map traversal callback to define a wrapper function.
    1846              :    This generates code for client-side contract check wrappers and the
    1847              :    noexcept wrapper around the contract violation handler.  */
    1848              : 
    1849              : bool
    1850           64 : define_contract_wrapper_func (const tree& fndecl, const tree& wrapdecl, void*)
    1851              : {
    1852              :   /* If we already built this function on a previous pass, then do nothing.  */
    1853           64 :   if (DECL_INITIAL (wrapdecl) && DECL_INITIAL (wrapdecl) != error_mark_node)
    1854              :     return true;
    1855              : 
    1856           28 :   gcc_checking_assert (!DECL_HAS_CONTRACTS_P (wrapdecl));
    1857              :   /* We check postconditions if postcondition checks are enabled for clients.
    1858              :     We should not get here unless there are some checks to make.  */
    1859           28 :   bool check_post = flag_contract_client_check > 1;
    1860              :   /* For wrappers on CDTORs we need to refer to the original contracts,
    1861              :      when the wrapper is around a clone.  */
    1862           56 :   set_fn_contract_specifiers ( wrapdecl,
    1863           28 :                       copy_and_remap_contracts (wrapdecl, DECL_ORIGIN (fndecl),
    1864              :                                                 check_post? cmk_all : cmk_pre));
    1865              : 
    1866           28 :   start_preparsed_function (wrapdecl, /*DECL_ATTRIBUTES*/NULL_TREE,
    1867              :                             SF_DEFAULT | SF_PRE_PARSED);
    1868           28 :   tree body = begin_function_body ();
    1869           28 :   tree compound_stmt = begin_compound_stmt (BCS_FN_BODY);
    1870              : 
    1871           28 :   vec<tree, va_gc> * args = build_arg_list (wrapdecl);
    1872              : 
    1873              :   /* We do not support contracts on virtual functions yet.  */
    1874           28 :   gcc_checking_assert (!DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)
    1875              :                        || !DECL_VIRTUAL_P (fndecl));
    1876              : 
    1877           28 :   tree call = build_thunk_like_call (fndecl, args->length (), args->address ());
    1878              : 
    1879           28 :   finish_return_stmt (call);
    1880              : 
    1881           28 :   finish_compound_stmt (compound_stmt);
    1882           28 :   finish_function_body (body);
    1883           28 :   expand_or_defer_fn (finish_function (/*inline_p=*/false));
    1884           28 :   return true;
    1885              : }
    1886              : 
    1887              : /* If any wrapper functions have been declared, emit their definition.
    1888              :    This might be called multiple times, as we instantiate functions. When
    1889              :    the processing here adds more wrappers, then flag to the caller that
    1890              :    possible additional instantiations should be considered.
    1891              :    Once instantiations are complete, this will be called with done == true.  */
    1892              : 
    1893              : bool
    1894        57334 : emit_contract_wrapper_func (bool done)
    1895              : {
    1896        57334 :   if (!decl_wrapper_fn || decl_wrapper_fn->is_empty ())
    1897              :     return false;
    1898           38 :   size_t start_elements = decl_wrapper_fn->elements ();
    1899          102 :   decl_wrapper_fn->traverse<void *, define_contract_wrapper_func>(NULL);
    1900           38 :   bool more = decl_wrapper_fn->elements () > start_elements;
    1901           38 :   if (done)
    1902           15 :     decl_wrapper_fn->empty ();
    1903           15 :   gcc_checking_assert (!done || !more);
    1904              :   return more;
    1905              : }
    1906              : 
    1907              : /* Mark most of a contract as being invalid.  */
    1908              : 
    1909              : tree
    1910           15 : invalidate_contract (tree contract)
    1911              : {
    1912           15 :   if (TREE_CODE (contract) == POSTCONDITION_STMT
    1913           15 :       && POSTCONDITION_IDENTIFIER (contract))
    1914           15 :     POSTCONDITION_IDENTIFIER (contract) = error_mark_node;
    1915           15 :   CONTRACT_CONDITION (contract) = error_mark_node;
    1916           15 :   CONTRACT_COMMENT (contract) = error_mark_node;
    1917           15 :   return contract;
    1918              : }
    1919              : 
    1920              : /* Returns an invented parameter declaration of the form 'TYPE ID' for the
    1921              :    purpose of parsing the postcondition.
    1922              : 
    1923              :    We use a PARM_DECL instead of a VAR_DECL so that tsubst forces a lookup
    1924              :    in local specializations when we instantiate these things later.  */
    1925              : 
    1926              : tree
    1927          202 : make_postcondition_variable (cp_expr id, tree type)
    1928              : {
    1929          202 :   if (id == error_mark_node)
    1930              :     return id;
    1931          202 :   gcc_checking_assert (scope_chain && scope_chain->bindings
    1932              :                        && scope_chain->bindings->kind == sk_contract);
    1933              : 
    1934          202 :   tree decl = build_lang_decl (PARM_DECL, id, type);
    1935          202 :   DECL_ARTIFICIAL (decl) = true;
    1936          202 :   DECL_SOURCE_LOCATION (decl) = id.get_location ();
    1937          202 :   return pushdecl (decl);
    1938              : }
    1939              : 
    1940              : /* As above, except that the type is unknown.  */
    1941              : 
    1942              : tree
    1943          124 : make_postcondition_variable (cp_expr id)
    1944              : {
    1945          124 :   return make_postcondition_variable (id, make_auto ());
    1946              : }
    1947              : 
    1948              : /* Check that the TYPE is valid for a named postcondition variable on
    1949              :    function decl FNDECL. Emit a diagnostic if it is not.  Returns TRUE if
    1950              :    the result is OK and false otherwise.  */
    1951              : 
    1952              : bool
    1953          254 : check_postcondition_result (tree fndecl, tree type, location_t loc)
    1954              : {
    1955              :   /* Do not be confused by targetm.cxx.cdtor_return_this ();
    1956              :      conceptually, cdtors have no return value.  */
    1957          254 :   if (VOID_TYPE_P (type)
    1958          478 :       || DECL_CONSTRUCTOR_P (fndecl)
    1959          493 :       || DECL_DESTRUCTOR_P (fndecl))
    1960              :     {
    1961           45 :       error_at (loc,
    1962           30 :                 DECL_CONSTRUCTOR_P (fndecl)
    1963              :                 ? G_("constructor does not return a value to test")
    1964           12 :                 : DECL_DESTRUCTOR_P (fndecl)
    1965           12 :                 ? G_("destructor does not return a value to test")
    1966              :                 : G_("function does not return a value to test"));
    1967           15 :       return false;
    1968              :     }
    1969              : 
    1970              :   return true;
    1971              : }
    1972              : 
    1973              : /* Instantiate each postcondition with the return type to finalize the
    1974              :    contract specifiers on a function decl FNDECL.  */
    1975              : 
    1976              : void
    1977          931 : rebuild_postconditions (tree fndecl)
    1978              : {
    1979          931 :   if (!fndecl || fndecl == error_mark_node || processing_template_decl)
    1980              :     return;
    1981              : 
    1982          572 :   tree type = TREE_TYPE (TREE_TYPE (fndecl));
    1983              : 
    1984              :   /* If the return type is undeduced, defer until later.  */
    1985          572 :   if (type_uses_auto (type))
    1986              :     return;
    1987              : 
    1988          536 :   tree contract_spec = get_fn_contract_specifiers (fndecl);
    1989          536 :   if (!contract_spec)
    1990              :     return;
    1991              : 
    1992         1173 :   for (tree contract : tree_vec_range (contract_spec))
    1993              :     {
    1994          713 :       if (TREE_CODE (contract) != POSTCONDITION_STMT)
    1995          517 :         continue;
    1996          266 :       tree condition = CONTRACT_CONDITION (contract);
    1997          266 :       if (!condition || condition == error_mark_node)
    1998            0 :         continue;
    1999              : 
    2000              :       /* If any conditions are deferred, they're all deferred.  Note that
    2001              :          we don't have to instantiate postconditions in that case because
    2002              :          the type is available through the declaration.  */
    2003          266 :       if (TREE_CODE (condition) == DEFERRED_PARSE)
    2004           76 :         return;
    2005              : 
    2006          190 :       tree oldvar = POSTCONDITION_IDENTIFIER (contract);
    2007          190 :       if (!oldvar)
    2008           67 :         continue;
    2009              : 
    2010          123 :       gcc_checking_assert (!DECL_CONTEXT (oldvar)
    2011              :                            || DECL_CONTEXT (oldvar) == fndecl);
    2012          123 :       DECL_CONTEXT (oldvar) = fndecl;
    2013              : 
    2014              :       /* Check the postcondition variable.  */
    2015          123 :       location_t loc = DECL_SOURCE_LOCATION (oldvar);
    2016          123 :       if (!check_postcondition_result (fndecl, type, loc))
    2017              :         {
    2018            3 :           invalidate_contract (contract);
    2019            3 :           continue;
    2020              :         }
    2021              : 
    2022              :       /* A concrete late-parsed result variable still needs validation, but
    2023              :          not rebuilding.  Rebuild only one whose type was undeduced.  */
    2024          120 :       if (!type_uses_auto (TREE_TYPE (oldvar)))
    2025            0 :         continue;
    2026              : 
    2027              :       /* "Instantiate" the result variable using the known type.  */
    2028          120 :       tree newvar = copy_node (oldvar);
    2029          120 :       TREE_TYPE (newvar) = type;
    2030              : 
    2031              :       /* Make parameters and result available for substitution.  */
    2032          120 :       local_specialization_stack stack (lss_copy);
    2033          278 :       for (tree t = DECL_ARGUMENTS (fndecl); t != NULL_TREE; t = TREE_CHAIN (t))
    2034          158 :         register_local_identity (t);
    2035          120 :       register_local_specialization (newvar, oldvar);
    2036              : 
    2037          120 :       begin_scope (sk_contract, fndecl);
    2038          120 :       bool old_pc = processing_postcondition;
    2039          120 :       processing_postcondition = true;
    2040              : 
    2041          120 :       condition = tsubst_expr (condition, make_tree_vec (0),
    2042              :                                tf_warning_or_error, fndecl);
    2043              : 
    2044              :       /* Update the contract condition and result.  */
    2045          120 :       POSTCONDITION_IDENTIFIER (contract) = newvar;
    2046          120 :       CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
    2047          120 :       processing_postcondition = old_pc;
    2048          120 :       gcc_checking_assert (scope_chain && scope_chain->bindings
    2049              :                            && scope_chain->bindings->kind == sk_contract);
    2050          120 :       pop_bindings_and_leave_scope ();
    2051          120 :     }
    2052              : }
    2053              : 
    2054              : /* Make a string of the contract condition, if it is available.  */
    2055              : 
    2056              : static tree
    2057         1646 : build_comment (cp_expr condition)
    2058              : {
    2059              :   /* Try to get the actual source text for the condition; if that fails pretty
    2060              :      print the resulting tree.  */
    2061         1646 :   char *str = get_source_text_between (global_dc->get_file_cache (),
    2062              :                                        condition.get_start (),
    2063              :                                        condition.get_finish ());
    2064         1646 :   if (!str)
    2065              :     {
    2066            2 :       const char *str = expr_to_string (condition);
    2067            2 :       return build_string_literal (strlen (str) + 1, str);
    2068              :     }
    2069              : 
    2070         1644 :   tree t = build_string_literal (strlen (str) + 1, str);
    2071         1644 :   free (str);
    2072         1644 :   return t;
    2073              : }
    2074              : 
    2075              : /* Build a contract statement.  */
    2076              : 
    2077              : tree
    2078         1692 : grok_contract (tree contract_spec, tree mode, tree result, cp_expr condition,
    2079              :                location_t loc)
    2080              : {
    2081         1692 :   if (condition == error_mark_node)
    2082              :     return error_mark_node;
    2083              : 
    2084         1661 :   tree_code code;
    2085         1661 :   contract_assertion_kind kind = CAK_INVALID;
    2086         1661 :   if (id_equal (contract_spec, "contract_assert"))
    2087              :     {
    2088              :       code = ASSERTION_STMT;
    2089              :       kind = CAK_ASSERT;
    2090              :     }
    2091         1497 :   else if (id_equal (contract_spec, "pre"))
    2092              :     {
    2093              :       code = PRECONDITION_STMT;
    2094              :       kind = CAK_PRE;
    2095              :     }
    2096          802 :   else if (id_equal (contract_spec,"post"))
    2097              :     {
    2098              :       code = POSTCONDITION_STMT;
    2099              :       kind = CAK_POST;
    2100              :     }
    2101              :   else
    2102            0 :     gcc_unreachable ();
    2103              : 
    2104              :   /* Build the contract. The condition is added later.  In the case that
    2105              :      the contract is deferred, result an plain identifier, not a result
    2106              :      variable.  */
    2107          802 :   tree contract;
    2108          802 :   if (code != POSTCONDITION_STMT)
    2109          859 :     contract = build5_loc (loc, code, void_type_node, mode,
    2110              :                            NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
    2111              :   else
    2112              :     {
    2113          802 :       contract = build_nt (code, mode, NULL_TREE, NULL_TREE,
    2114              :                            NULL_TREE, NULL_TREE, result);
    2115          802 :       TREE_TYPE (contract) = void_type_node;
    2116          802 :       SET_EXPR_LOCATION (contract, loc);
    2117              :     }
    2118              : 
    2119              :   /* Determine the assertion kind.  */
    2120         1661 :   CONTRACT_ASSERTION_KIND (contract) = build_int_cst (uint16_type_node, kind);
    2121              : 
    2122              :   /* Determine the evaluation semantic.  This is now an override, so that if
    2123              :      not set we will get the default (currently enforce).  */
    2124         1661 :   CONTRACT_EVALUATION_SEMANTIC (contract)
    2125         3322 :     = build_int_cst (uint16_type_node, (uint16_t)
    2126         1661 :                      flag_contract_evaluation_semantic);
    2127              : 
    2128              :   /* If the contract is deferred, don't do anything with the condition.  */
    2129         1661 :   if (TREE_CODE (condition) == DEFERRED_PARSE)
    2130              :     {
    2131          794 :       CONTRACT_CONDITION (contract) = condition;
    2132          794 :       return contract;
    2133              :     }
    2134              : 
    2135              :   /* Generate the comment from the original condition.  */
    2136          867 :   CONTRACT_COMMENT (contract) = build_comment (condition);
    2137              : 
    2138              :   /* The condition is converted to bool.  */
    2139          867 :   condition = finish_contract_condition (condition);
    2140              : 
    2141          867 :   if (condition == error_mark_node)
    2142              :     return error_mark_node;
    2143              : 
    2144          863 :   CONTRACT_CONDITION (contract) = condition;
    2145              : 
    2146          863 :   return contract;
    2147              : }
    2148              : 
    2149              : /* Update condition of a late-parsed contract and postcondition variable,
    2150              :    if any.  */
    2151              : 
    2152              : void
    2153          779 : update_late_contract (tree contract, tree result, cp_expr condition)
    2154              : {
    2155          779 :   if (TREE_CODE (contract) == POSTCONDITION_STMT)
    2156          507 :     POSTCONDITION_IDENTIFIER (contract) = result;
    2157              : 
    2158              :   /* Generate the comment from the original condition.  */
    2159          779 :   CONTRACT_COMMENT (contract) = build_comment (condition);
    2160              : 
    2161              :   /* The condition is converted to bool.  */
    2162          779 :   condition = finish_contract_condition (condition);
    2163          779 :   CONTRACT_CONDITION (contract) = condition;
    2164          779 : }
    2165              : 
    2166              : /* Returns the precondition function for FNDECL, or null if not set.  */
    2167              : 
    2168              : tree
    2169      1929326 : get_precondition_function (tree fndecl)
    2170              : {
    2171      1929326 :   gcc_checking_assert (fndecl);
    2172      1929326 :   tree *result = hash_map_safe_get (decl_pre_fn, fndecl);
    2173           90 :   return result ? *result : NULL_TREE;
    2174              : }
    2175              : 
    2176              : /* Returns the postcondition function for FNDECL, or null if not set.  */
    2177              : 
    2178              : tree
    2179      1929330 : get_postcondition_function (tree fndecl)
    2180              : {
    2181      1929330 :   gcc_checking_assert (fndecl);
    2182      1929330 :   tree *result = hash_map_safe_get (decl_post_fn, fndecl);
    2183           70 :   return result ? *result : NULL_TREE;
    2184              : }
    2185              : 
    2186              : /* Set the PRE and POST functions for FNDECL.  Note that PRE and POST can
    2187              :    be null in this case.  If so the functions are not recorded.  Used by the
    2188              :    modules code.  */
    2189              : 
    2190              : void
    2191       472632 : set_contract_functions (tree fndecl, tree pre, tree post)
    2192              : {
    2193       472632 :   if (pre)
    2194            0 :     set_precondition_function (fndecl, pre);
    2195              : 
    2196       472632 :   if (post)
    2197            0 :     set_postcondition_function (fndecl, post);
    2198       472632 : }
    2199              : 
    2200              : 
    2201              : /* We're compiling the pre/postcondition function CONDFN; remap any FN
    2202              :    contracts that match CODE and emit them.  */
    2203              : 
    2204              : static void
    2205           28 : remap_and_emit_conditions (tree fn, tree condfn, tree_code code)
    2206              : {
    2207           28 :   gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
    2208           28 :   tree contract_spec = get_fn_contract_specifiers (fn);
    2209           28 :   if (!contract_spec)
    2210              :     return;
    2211              : 
    2212           68 :   for (tree contract : tree_vec_range (contract_spec))
    2213           40 :     if (TREE_CODE (contract) == code)
    2214              :       {
    2215           32 :         contract = copy_node (contract);
    2216           32 :         if (CONTRACT_CONDITION (contract) != error_mark_node)
    2217           32 :           remap_contract (fn, condfn, contract, /*duplicate_p=*/false);
    2218           32 :         emit_contract_statement (contract);
    2219              :       }
    2220              : }
    2221              : 
    2222              : /* Finish up the pre & post function definitions for a guarded FNDECL,
    2223              :    and compile those functions all the way to assembler language output.  */
    2224              : 
    2225              : void
    2226    168707804 : finish_function_outlined_contracts (tree fndecl)
    2227              : {
    2228              :   /* If the guarded func is either already decided to be ill-formed or is
    2229              :      not yet complete return early.  */
    2230    168707804 :   if (error_operand_p (fndecl)
    2231    168707804 :       || !DECL_INITIAL (fndecl)
    2232    337415608 :       || DECL_INITIAL (fndecl) == error_mark_node)
    2233              :     return;
    2234              : 
    2235              :   /* If there are no contracts here, or we're building them in-line then we
    2236              :      do not need to build the outlined functions.  */
    2237    168707711 :   if (!handle_contracts_p (fndecl)
    2238    168707711 :       || !flag_contract_checks_outlined)
    2239              :     return;
    2240              : 
    2241              :   /* If this is not a client side check and definition side checks are
    2242              :      disabled, do nothing.  */
    2243           26 :   if (!flag_contracts_definition_check
    2244           26 :       && !DECL_CONTRACT_WRAPPER (fndecl))
    2245              :     return;
    2246              : 
    2247              :   /* If either the pre or post functions are bad, don't bother emitting
    2248              :      any contracts.  The program is already ill-formed.  */
    2249           26 :   tree pre = DECL_PRE_FN (fndecl);
    2250           26 :   tree post = DECL_POST_FN (fndecl);
    2251           26 :   if (pre == error_mark_node || post == error_mark_node)
    2252              :     return;
    2253              : 
    2254              :   /* We are generating code, deferred parses should be complete.  */
    2255           26 :   tree contract_spec = get_fn_contract_specifiers (fndecl);
    2256           26 :   gcc_checking_assert (!contract_any_deferred_p (contract_spec));
    2257              : 
    2258           26 :   int flags = SF_DEFAULT | SF_PRE_PARSED;
    2259              : 
    2260           26 :   if (pre && !DECL_INITIAL (pre))
    2261              :     {
    2262           14 :       DECL_PENDING_INLINE_P (pre) = false;
    2263           14 :       start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
    2264           14 :       remap_and_emit_conditions (fndecl, pre, PRECONDITION_STMT);
    2265           14 :       finish_return_stmt (NULL_TREE);
    2266           14 :       pre = finish_function (false);
    2267           14 :       expand_or_defer_fn (pre);
    2268              :     }
    2269              : 
    2270           26 :   if (post && !DECL_INITIAL (post))
    2271              :     {
    2272           14 :       DECL_PENDING_INLINE_P (post) = false;
    2273           14 :       start_preparsed_function (post, DECL_ATTRIBUTES (post), flags);
    2274           14 :       remap_and_emit_conditions (fndecl, post, POSTCONDITION_STMT);
    2275           14 :       gcc_checking_assert (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post))));
    2276           14 :       finish_return_stmt (NULL_TREE);
    2277           14 :       post = finish_function (false);
    2278           14 :       expand_or_defer_fn (post);
    2279              :     }
    2280              : }
    2281              : 
    2282              : /* ===== Code generation ===== */
    2283              : 
    2284              : /* Insert a BUILT_IN_OBSERVABLE_CHECKPOINT epoch marker.  */
    2285              : 
    2286              : static void
    2287          534 : emit_builtin_observable_checkpoint ()
    2288              : {
    2289          534 :   tree fn = builtin_decl_explicit (BUILT_IN_OBSERVABLE_CHKPT);
    2290          534 :   releasing_vec vec;
    2291          534 :   fn = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
    2292          534 :   finish_expr_stmt (fn);
    2293          534 : }
    2294              : 
    2295              : /* Shared code between TU-local wrappers for the violation handler.  */
    2296              : 
    2297              : static tree
    2298          380 : declare_one_violation_handler_wrapper (tree fn_name, tree fn_type,
    2299              :                                        tree p1_type, tree p2_type)
    2300              : {
    2301          380 :   location_t loc = BUILTINS_LOCATION;
    2302          380 :   tree fn_decl = build_lang_decl_loc (loc, FUNCTION_DECL, fn_name, fn_type);
    2303          380 :   DECL_CONTEXT (fn_decl) = FROB_CONTEXT (global_namespace);
    2304          380 :   DECL_ARTIFICIAL (fn_decl) = true;
    2305          380 :   DECL_INITIAL (fn_decl) = error_mark_node;
    2306              :   /* Let the start function code fill in the result decl.  */
    2307          380 :   DECL_RESULT (fn_decl) = NULL_TREE;
    2308              :   /* Two args violation ref, dynamic info.  */
    2309          380 :   tree parms = cp_build_parm_decl (fn_decl, NULL_TREE, p1_type);
    2310          380 :   TREE_USED (parms) = true;
    2311          380 :   DECL_READ_P (parms) = true;
    2312          380 :   tree p2 = cp_build_parm_decl (fn_decl, NULL_TREE, p2_type);
    2313          380 :   TREE_USED (p2) = true;
    2314          380 :   DECL_READ_P (p2) = true;
    2315          380 :   DECL_CHAIN (parms) = p2;
    2316          380 :   DECL_ARGUMENTS (fn_decl) = parms;
    2317              :   /* Make this function internal.  */
    2318          380 :   TREE_PUBLIC (fn_decl) = false;
    2319          380 :   DECL_EXTERNAL (fn_decl) = false;
    2320          380 :   DECL_WEAK (fn_decl) = false;
    2321          380 :   return fn_decl;
    2322              : }
    2323              : 
    2324              : static GTY(()) tree tu_has_violation = NULL_TREE;
    2325              : static GTY(()) tree tu_has_violation_exception = NULL_TREE;
    2326              : 
    2327              : static void
    2328         1036 : declare_violation_handler_wrappers ()
    2329              : {
    2330         1036 :   if (tu_has_violation && tu_has_violation_exception)
    2331         1036 :     return;
    2332              : 
    2333          190 :   iloc_sentinel ils (input_location);
    2334          190 :   input_location = BUILTINS_LOCATION;
    2335          190 :   tree v_obj_type = builtin_contract_violation_type;
    2336          190 :   v_obj_type = cp_build_qualified_type (v_obj_type, TYPE_QUAL_CONST);
    2337          190 :   v_obj_type = cp_build_reference_type (v_obj_type, /*rval*/false);
    2338          190 :   tree fn_type = build_function_type_list (void_type_node, v_obj_type,
    2339              :                                            uint16_type_node, NULL_TREE);
    2340          190 :   tree fn_name = get_identifier ("__tu_has_violation_exception");
    2341          190 :   tu_has_violation_exception
    2342          190 :     = declare_one_violation_handler_wrapper (fn_name, fn_type, v_obj_type,
    2343              :                                              uint16_type_node);
    2344          190 :   fn_name = get_identifier ("__tu_has_violation");
    2345          190 :   tu_has_violation
    2346          190 :     = declare_one_violation_handler_wrapper (fn_name, fn_type, v_obj_type,
    2347              :                                              uint16_type_node);
    2348          190 : }
    2349              : 
    2350              : static GTY(()) tree tu_terminate_wrapper = NULL_TREE;
    2351              : 
    2352              : /* Declare a noipa wrapper around the call to std::terminate */
    2353              : 
    2354              : static tree
    2355         1038 : declare_terminate_wrapper ()
    2356              : {
    2357         1038 :   if (tu_terminate_wrapper)
    2358              :     return tu_terminate_wrapper;
    2359              : 
    2360          192 :   iloc_sentinel ils (input_location);
    2361          192 :   input_location = BUILTINS_LOCATION;
    2362              : 
    2363          192 :   tree fn_type = build_function_type_list (void_type_node, NULL_TREE);
    2364          192 :   if (!TREE_NOTHROW (terminate_fn))
    2365            0 :     fn_type = build_exception_variant (fn_type, noexcept_true_spec);
    2366          192 :   tree fn_name = get_identifier ("__tu_terminate_wrapper");
    2367              : 
    2368          192 :   tu_terminate_wrapper
    2369          192 :     = build_lang_decl_loc (input_location, FUNCTION_DECL, fn_name, fn_type);
    2370          192 :   DECL_CONTEXT (tu_terminate_wrapper) = FROB_CONTEXT(global_namespace);
    2371          192 :   DECL_ARTIFICIAL (tu_terminate_wrapper) = true;
    2372          192 :   DECL_INITIAL (tu_terminate_wrapper) = error_mark_node;
    2373              :   /* Let the start function code fill in the result decl.  */
    2374          192 :   DECL_RESULT (tu_terminate_wrapper) = NULL_TREE;
    2375              : 
    2376              :   /* Make this function internal.  */
    2377          192 :   TREE_PUBLIC (tu_terminate_wrapper) = false;
    2378          192 :   DECL_EXTERNAL (tu_terminate_wrapper) = false;
    2379          192 :   DECL_WEAK (tu_terminate_wrapper) = false;
    2380              : 
    2381          192 :   DECL_ATTRIBUTES (tu_terminate_wrapper)
    2382          192 :     = tree_cons (get_identifier ("noipa"), NULL, NULL_TREE);
    2383          192 :   cplus_decl_attributes (&tu_terminate_wrapper,
    2384          192 :                          DECL_ATTRIBUTES (tu_terminate_wrapper), 0);
    2385          192 :   return tu_terminate_wrapper;
    2386          192 : }
    2387              : 
    2388              : /* Define a noipa wrapper around the call to std::terminate */
    2389              : 
    2390              : static void
    2391          192 : build_terminate_wrapper ()
    2392              : {
    2393              :   /* We should not be trying to build this if we never used it.  */
    2394          192 :   gcc_checking_assert (tu_terminate_wrapper);
    2395              : 
    2396          192 :   start_preparsed_function (tu_terminate_wrapper,
    2397          192 :                             DECL_ATTRIBUTES(tu_terminate_wrapper),
    2398              :                             SF_DEFAULT | SF_PRE_PARSED);
    2399          192 :   tree body = begin_function_body ();
    2400          192 :   tree compound_stmt = begin_compound_stmt (BCS_FN_BODY);
    2401          192 :   finish_expr_stmt (build_call_a (terminate_fn, 0, nullptr));
    2402          192 :   finish_return_stmt (NULL_TREE);
    2403          192 :   finish_compound_stmt (compound_stmt);
    2404          192 :   finish_function_body (body);
    2405          192 :   tu_terminate_wrapper = finish_function (false);
    2406          192 :   expand_or_defer_fn (tu_terminate_wrapper);
    2407          192 : }
    2408              : 
    2409              : /* Lookup a name in std::contracts, or inject it.  */
    2410              : 
    2411              : static tree
    2412          148 : lookup_std_contracts_type (tree name_id)
    2413              : {
    2414          148 :   tree id_ns = get_identifier ("contracts");
    2415          148 :   tree ns = lookup_qualified_name (std_node, id_ns);
    2416              : 
    2417          148 :   tree res_type = error_mark_node;
    2418          148 :   if (TREE_CODE (ns) == NAMESPACE_DECL)
    2419            8 :     res_type = lookup_qualified_name
    2420            8 :       (ns, name_id, LOOK_want::TYPE | LOOK_want::HIDDEN_FRIEND);
    2421              : 
    2422          148 :   if (TREE_CODE (res_type) == TYPE_DECL)
    2423            8 :     res_type = TREE_TYPE (res_type);
    2424              :   else
    2425              :     {
    2426          140 :       push_nested_namespace (std_node);
    2427          140 :       push_namespace (id_ns, /*inline*/false);
    2428          140 :       res_type = make_class_type (RECORD_TYPE);
    2429          140 :       create_implicit_typedef (name_id, res_type);
    2430          140 :       DECL_SOURCE_LOCATION (TYPE_NAME (res_type)) = BUILTINS_LOCATION;
    2431          140 :       DECL_CONTEXT (TYPE_NAME (res_type)) = current_namespace;
    2432          140 :       pushdecl_namespace_level (TYPE_NAME (res_type), /*hidden*/true);
    2433          140 :       pop_namespace ();
    2434          140 :       pop_nested_namespace (std_node);
    2435              :     }
    2436          148 :   return res_type;
    2437              : }
    2438              : 
    2439              : /* Return handle_contract_violation (), declaring it if needed.  */
    2440              : 
    2441              : static tree
    2442          380 : declare_handle_contract_violation ()
    2443              : {
    2444              :   /* We may need to declare new types, ensure they are not considered
    2445              :      attached to a named module.  */
    2446          380 :   auto module_kind_override = make_temp_override
    2447          380 :     (module_kind, module_kind & ~(MK_PURVIEW | MK_ATTACH | MK_EXPORTING));
    2448          380 :   tree fnname = get_identifier ("handle_contract_violation");
    2449          380 :   tree viol_name = get_identifier ("contract_violation");
    2450          380 :   tree l = lookup_qualified_name (global_namespace, fnname,
    2451              :                                   LOOK_want::HIDDEN_FRIEND);
    2452          908 :   for (tree f: lkp_range (l))
    2453          380 :     if (TREE_CODE (f) == FUNCTION_DECL)
    2454              :         {
    2455          232 :           tree parms = TYPE_ARG_TYPES (TREE_TYPE (f));
    2456          232 :           if (remaining_arguments (parms) != 1)
    2457            0 :             continue;
    2458          232 :           tree parmtype = non_reference (TREE_VALUE (parms));
    2459          232 :           if (CLASS_TYPE_P (parmtype)
    2460          464 :               && TYPE_IDENTIFIER (parmtype) == viol_name)
    2461          232 :             return f;
    2462              :         }
    2463              : 
    2464          148 :   tree violation = lookup_std_contracts_type (viol_name);
    2465          148 :   tree fntype = NULL_TREE;
    2466          148 :   tree v_obj_ref = cp_build_qualified_type (violation, TYPE_QUAL_CONST);
    2467          148 :   v_obj_ref = cp_build_reference_type (v_obj_ref, /*rval*/false);
    2468          148 :   fntype = build_function_type_list (void_type_node, v_obj_ref, NULL_TREE);
    2469              : 
    2470          148 :   push_nested_namespace (global_namespace);
    2471          148 :   tree fndecl
    2472          148 :     = build_cp_library_fn_ptr ("handle_contract_violation", fntype, ECF_COLD);
    2473          148 :   pushdecl_namespace_level (fndecl, /*hiding*/true);
    2474          148 :   pop_nested_namespace (global_namespace);
    2475              : 
    2476              :   /* Build the parameter(s).  */
    2477          148 :   tree parms = cp_build_parm_decl (fndecl, NULL_TREE, v_obj_ref);
    2478          148 :   TREE_USED (parms) = true;
    2479          148 :   DECL_READ_P (parms) = true;
    2480          148 :   DECL_ARGUMENTS (fndecl) = parms;
    2481          148 :   return fndecl;
    2482          380 : }
    2483              : 
    2484              : /* Build the call to handle_contract_violation for VIOLATION.  */
    2485              : 
    2486              : static void
    2487          380 : build_contract_handler_call (tree violation)
    2488              : {
    2489          380 :   tree violation_fn = declare_handle_contract_violation ();
    2490          380 :   tree call = build_call_n (violation_fn, 1, violation);
    2491          380 :   finish_expr_stmt (call);
    2492          380 : }
    2493              : 
    2494              : /* If we have emitted any contracts in this TU that will call a violation
    2495              :    handler, then emit the wrappers for the handler.  */
    2496              : 
    2497              : void
    2498        25139 : maybe_emit_violation_handler_wrappers ()
    2499              : {
    2500              :   /* We might need the terminate wrapper, even if we do not use the violation
    2501              :      handler wrappers.  */
    2502        25139 :   if (tu_terminate_wrapper && flag_contracts_conservative_ipa)
    2503          192 :     build_terminate_wrapper ();
    2504              : 
    2505        25139 :   if (!tu_has_violation && !tu_has_violation_exception)
    2506              :     return;
    2507              : 
    2508          190 :   tree terminate_wrapper = terminate_fn;
    2509          190 :   if (flag_contracts_conservative_ipa)
    2510          190 :     terminate_wrapper = tu_terminate_wrapper;
    2511              : 
    2512              :   /* tu_has_violation */
    2513          190 :   start_preparsed_function (tu_has_violation, NULL_TREE,
    2514              :                             SF_DEFAULT | SF_PRE_PARSED);
    2515          190 :   tree body = begin_function_body ();
    2516          190 :   tree compound_stmt = begin_compound_stmt (BCS_FN_BODY);
    2517          190 :   tree v = DECL_ARGUMENTS (tu_has_violation);
    2518          190 :   tree semantic = DECL_CHAIN (v);
    2519              : 
    2520              :   /* We are going to call the handler.  */
    2521          190 :   build_contract_handler_call (v);
    2522              : 
    2523          190 :   tree if_observe = begin_if_stmt ();
    2524              :   /* if (observe) return; */
    2525          190 :   tree cond = build2 (EQ_EXPR, uint16_type_node, semantic,
    2526              :                       build_int_cst (uint16_type_node, (uint16_t)CES_OBSERVE));
    2527          190 :   finish_if_stmt_cond (cond, if_observe);
    2528          190 :   emit_builtin_observable_checkpoint ();
    2529          190 :   finish_then_clause (if_observe);
    2530          190 :   begin_else_clause (if_observe);
    2531              :   /* else terminate.  */
    2532          190 :   finish_expr_stmt (build_call_a (terminate_wrapper, 0, nullptr));
    2533          190 :   finish_else_clause (if_observe);
    2534          190 :   finish_if_stmt (if_observe);
    2535          190 :   finish_return_stmt (NULL_TREE);
    2536              : 
    2537          190 :   finish_compound_stmt (compound_stmt);
    2538          190 :   finish_function_body (body);
    2539          190 :   tu_has_violation = finish_function (false);
    2540          190 :   expand_or_defer_fn (tu_has_violation);
    2541              : 
    2542              :   /* tu_has_violation_exception */
    2543          190 :   start_preparsed_function (tu_has_violation_exception, NULL_TREE,
    2544              :                             SF_DEFAULT | SF_PRE_PARSED);
    2545          190 :   body = begin_function_body ();
    2546          190 :   compound_stmt = begin_compound_stmt (BCS_FN_BODY);
    2547          190 :   v = DECL_ARGUMENTS (tu_has_violation_exception);
    2548          190 :   semantic = DECL_CHAIN (v);
    2549          190 :   location_t loc = DECL_SOURCE_LOCATION (tu_has_violation_exception);
    2550              : 
    2551          190 :   tree a_type = strip_top_quals (non_reference (TREE_TYPE (v)));
    2552          190 :   tree v2 = build_decl (loc, VAR_DECL, NULL_TREE, a_type);
    2553          190 :   DECL_SOURCE_LOCATION (v2) = loc;
    2554          190 :   DECL_CONTEXT (v2) = current_function_decl;
    2555          190 :   DECL_ARTIFICIAL (v2) = true;
    2556          190 :   layout_decl (v2, 0);
    2557          190 :   v2 = pushdecl (v2);
    2558          190 :   add_decl_expr (v2);
    2559          190 :   tree r = cp_build_init_expr (v2, convert_from_reference (v));
    2560          190 :   finish_expr_stmt (r);
    2561          190 :   tree memb = lookup_member (a_type, get_identifier ("_M_detection_mode"),
    2562              :                      /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
    2563          190 :   r = build_class_member_access_expr (v2, memb, NULL_TREE, false,
    2564              :                                       tf_warning_or_error);
    2565          190 :   r = cp_build_modify_expr
    2566          190 :    (loc, r, NOP_EXPR,
    2567              :     build_int_cst (uint16_type_node, (uint16_t)CDM_EVAL_EXCEPTION),
    2568              :     tf_warning_or_error);
    2569          190 :   finish_expr_stmt (r);
    2570              :   /* We are going to call the handler.  */
    2571          190 :   build_contract_handler_call (v);
    2572              : 
    2573          190 :   if_observe = begin_if_stmt ();
    2574              :   /* if (observe) return; */
    2575          190 :   cond = build2 (EQ_EXPR, uint16_type_node, semantic,
    2576              :                  build_int_cst (uint16_type_node, (uint16_t)CES_OBSERVE));
    2577          190 :   finish_if_stmt_cond (cond, if_observe);
    2578          190 :   emit_builtin_observable_checkpoint ();
    2579          190 :   finish_then_clause (if_observe);
    2580          190 :   begin_else_clause (if_observe);
    2581              :   /* else terminate.  */
    2582          190 :   finish_expr_stmt (build_call_a (terminate_wrapper, 0, nullptr));
    2583          190 :   finish_else_clause (if_observe);
    2584          190 :   finish_if_stmt (if_observe);
    2585          190 :   finish_return_stmt (NULL_TREE);
    2586          190 :   finish_compound_stmt (compound_stmt);
    2587          190 :   finish_function_body (body);
    2588          190 :   tu_has_violation_exception = finish_function (false);
    2589          190 :   expand_or_defer_fn (tu_has_violation_exception);
    2590              : }
    2591              : 
    2592              : /* Build a layout-compatible internal version of contract_violation type.  */
    2593              : 
    2594              : static tree
    2595        25461 : get_contract_violation_fields ()
    2596              : {
    2597        25461 :   tree fields = NULL_TREE;
    2598              :   /* Must match <contracts>:
    2599              :   class contract_violation {
    2600              :     uint16_t _M_version;
    2601              :     assertion_kind _M_assertion_kind;
    2602              :     evaluation_semantic _M_evaluation_semantic;
    2603              :     detection_mode _M_detection_mode;
    2604              :     const char* _M_comment;
    2605              :     void *_M_src_loc_ptr;
    2606              :     __vendor_ext* _M_ext;
    2607              :   };
    2608              :     If this changes, also update the initializer in
    2609              :     build_contract_violation.  */
    2610        25461 :   const tree types[] = { uint16_type_node,
    2611              :                          uint16_type_node,
    2612              :                          uint16_type_node,
    2613              :                          uint16_type_node,
    2614        25461 :                          const_string_type_node,
    2615        25461 :                          ptr_type_node,
    2616              :                          ptr_type_node
    2617        25461 :                         };
    2618        25461 :  const char *names[] = { "_M_version",
    2619              :                          "_M_assertion_kind",
    2620              :                          "_M_evaluation_semantic",
    2621              :                          "_M_detection_mode",
    2622              :                          "_M_comment",
    2623              :                          "_M_src_loc_ptr",
    2624              :                          "_M_ext",
    2625              :                         };
    2626        25461 :   unsigned n = 0;
    2627       203688 :   for (tree type : types)
    2628              :     {
    2629              :       /* finish_builtin_struct wants fields chained in reverse.  */
    2630       178227 :       tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
    2631       178227 :                                   get_identifier(names[n++]), type);
    2632       178227 :       DECL_CHAIN (next) = fields;
    2633       178227 :       fields = next;
    2634              :     }
    2635        25461 :  return fields;
    2636              : }
    2637              : 
    2638              : /* Build a type to represent contract violation objects.  */
    2639              : 
    2640              : static tree
    2641        25461 : init_builtin_contract_violation_type ()
    2642              : {
    2643        25461 :   if (builtin_contract_violation_type)
    2644              :     return builtin_contract_violation_type;
    2645              : 
    2646        25461 :   tree fields = get_contract_violation_fields ();
    2647              : 
    2648        25461 :   iloc_sentinel ils (input_location);
    2649        25461 :   input_location = BUILTINS_LOCATION;
    2650        25461 :   builtin_contract_violation_type = make_class_type (RECORD_TYPE);
    2651        25461 :   finish_builtin_struct (builtin_contract_violation_type,
    2652              :                          "__builtin_contract_violation_type", fields, NULL_TREE);
    2653        50922 :   CLASSTYPE_AS_BASE (builtin_contract_violation_type)
    2654        25461 :     = builtin_contract_violation_type;
    2655        25461 :   DECL_CONTEXT (TYPE_NAME (builtin_contract_violation_type))
    2656        25461 :     = FROB_CONTEXT (global_namespace);
    2657        25461 :   CLASSTYPE_LITERAL_P (builtin_contract_violation_type) = true;
    2658        25461 :   CLASSTYPE_LAZY_COPY_CTOR (builtin_contract_violation_type) = true;
    2659        25461 :   xref_basetypes (builtin_contract_violation_type, /*bases=*/NULL_TREE);
    2660        25461 :   DECL_CONTEXT (TYPE_NAME (builtin_contract_violation_type))
    2661        25461 :     = FROB_CONTEXT (global_namespace);
    2662        25461 :   DECL_ARTIFICIAL (TYPE_NAME (builtin_contract_violation_type)) = true;
    2663        25461 :   TYPE_ARTIFICIAL (builtin_contract_violation_type) = true;
    2664        25461 :   builtin_contract_violation_type
    2665        25461 :     = cp_build_qualified_type (builtin_contract_violation_type,
    2666              :                                TYPE_QUAL_CONST);
    2667        25461 :   return builtin_contract_violation_type;
    2668        25461 : }
    2669              : 
    2670              : /* Early initialisation of types and functions we will use.  */
    2671              : void
    2672        25461 : init_contracts ()
    2673              : {
    2674        25461 :   init_terminate_fn ();
    2675        25461 :   init_builtin_contract_violation_type ();
    2676        25461 : }
    2677              : 
    2678              : static GTY(()) tree contracts_source_location_impl_type;
    2679              : 
    2680              : /* Build a layout-compatible internal version of source location __impl
    2681              :    type.  */
    2682              : 
    2683              : static tree
    2684          190 : get_contracts_source_location_impl_type (tree context = NULL_TREE)
    2685              : {
    2686          190 :   if (contracts_source_location_impl_type)
    2687              :      return contracts_source_location_impl_type;
    2688              : 
    2689              :   /* First see if we have a declaration that we can use.  */
    2690          190 :   tree contracts_source_location_type
    2691          190 :     = lookup_std_type (get_identifier ("source_location"));
    2692              : 
    2693          190 :   if (contracts_source_location_type
    2694          190 :       && contracts_source_location_type != error_mark_node
    2695          380 :       && TYPE_FIELDS (contracts_source_location_type))
    2696              :     {
    2697           49 :       contracts_source_location_impl_type = get_source_location_impl_type ();
    2698           49 :       return contracts_source_location_impl_type;
    2699              :     }
    2700              : 
    2701              :   /* We do not, so build the __impl layout equivalent type, which must
    2702              :      match <source_location>:
    2703              :      struct __impl
    2704              :       {
    2705              :           const char* _M_file_name;
    2706              :           const char* _M_function_name;
    2707              :           unsigned _M_line;
    2708              :           unsigned _M_column;
    2709              :       }; */
    2710          141 :   const tree types[] = { const_string_type_node,
    2711              :                         const_string_type_node,
    2712          141 :                         uint_least32_type_node,
    2713          141 :                         uint_least32_type_node };
    2714              : 
    2715          141 :  const char *names[] = { "_M_file_name",
    2716              :                          "_M_function_name",
    2717              :                          "_M_line",
    2718              :                          "_M_column",
    2719              :                         };
    2720          141 :   tree fields = NULL_TREE;
    2721          141 :   unsigned n = 0;
    2722          705 :   for (tree type : types)
    2723              :   {
    2724              :     /* finish_builtin_struct wants fields chained in reverse.  */
    2725          564 :     tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
    2726          564 :                             get_identifier (names[n++]), type);
    2727          564 :     DECL_CHAIN (next) = fields;
    2728          564 :     fields = next;
    2729              :   }
    2730              : 
    2731          141 :   iloc_sentinel ils (input_location);
    2732          141 :   input_location = BUILTINS_LOCATION;
    2733          141 :   contracts_source_location_impl_type = cxx_make_type (RECORD_TYPE);
    2734          141 :   finish_builtin_struct (contracts_source_location_impl_type,
    2735              :                          "__impl", fields, NULL_TREE);
    2736          141 :   DECL_CONTEXT (TYPE_NAME (contracts_source_location_impl_type)) = context;
    2737          141 :   DECL_ARTIFICIAL (TYPE_NAME (contracts_source_location_impl_type)) = true;
    2738          141 :   TYPE_ARTIFICIAL (contracts_source_location_impl_type) = true;
    2739          141 :   contracts_source_location_impl_type
    2740          141 :     = cp_build_qualified_type (contracts_source_location_impl_type,
    2741              :                                TYPE_QUAL_CONST);
    2742              : 
    2743          141 :   return contracts_source_location_impl_type;
    2744          141 : }
    2745              : 
    2746              : static tree
    2747         1036 : get_src_loc_impl_ptr (location_t loc)
    2748              : {
    2749         1036 :   if (!contracts_source_location_impl_type)
    2750          190 :     get_contracts_source_location_impl_type ();
    2751              : 
    2752         1036 :   tree fndecl = current_function_decl;
    2753              :   /* We might be an outlined function.  */
    2754         1036 :   if (DECL_IS_PRE_FN_P (fndecl) || DECL_IS_POST_FN_P (fndecl))
    2755           32 :     fndecl = get_orig_for_outlined (fndecl);
    2756              :   /* We might be a wrapper.  */
    2757         1036 :   if (DECL_IS_WRAPPER_FN_P (fndecl))
    2758           40 :     fndecl = get_orig_func_for_wrapper (fndecl);
    2759              : 
    2760         1036 :   gcc_checking_assert (fndecl);
    2761         1036 :   tree impl__
    2762         1036 :     = build_source_location_impl (loc, fndecl,
    2763              :                                   contracts_source_location_impl_type);
    2764         1036 :   tree p = build_pointer_type (contracts_source_location_impl_type);
    2765         1036 :   return build_fold_addr_expr_with_type_loc (loc, impl__, p);
    2766              : }
    2767              : 
    2768              : /* Build a contract_violation layout compatible object. */
    2769              : 
    2770              : /* Constructor.  At present, this should always be constant. */
    2771              : 
    2772              : static tree
    2773         1036 : build_contract_violation_ctor (tree contract)
    2774              : {
    2775         1036 :   bool can_be_const = true;
    2776         1036 :   uint16_t version = 1;
    2777              :   /* Default CDM_PREDICATE_FALSE. */
    2778         1036 :   uint16_t detection_mode = CDM_PREDICATE_FALSE;
    2779              : 
    2780         1036 :   tree assertion_kind = CONTRACT_ASSERTION_KIND (contract);
    2781         1036 :   if (!assertion_kind || really_constant_p (assertion_kind))
    2782              :     {
    2783         1036 :       contract_assertion_kind kind = get_contract_assertion_kind (contract);
    2784         1036 :       assertion_kind = build_int_cst (uint16_type_node, kind);
    2785              :     }
    2786              :   else
    2787              :     can_be_const = false;
    2788              : 
    2789         1036 :   tree eval_semantic = CONTRACT_EVALUATION_SEMANTIC (contract);
    2790         1036 :   gcc_checking_assert (eval_semantic);
    2791         1036 :   if (!really_constant_p (eval_semantic))
    2792            0 :     can_be_const = false;
    2793              : 
    2794         1036 :   tree comment = CONTRACT_COMMENT (contract);
    2795         1036 :   if (comment && !really_constant_p (comment))
    2796              :     can_be_const = false;
    2797              : 
    2798         1036 :   tree std_src_loc_impl_ptr = CONTRACT_STD_SOURCE_LOC (contract);
    2799         1036 :   if (std_src_loc_impl_ptr)
    2800              :     {
    2801            0 :       std_src_loc_impl_ptr = convert_from_reference (std_src_loc_impl_ptr);
    2802            0 :       if (!really_constant_p (std_src_loc_impl_ptr))
    2803            0 :         can_be_const = false;
    2804              :     }
    2805              :   else
    2806         1036 :     std_src_loc_impl_ptr = get_src_loc_impl_ptr (EXPR_LOCATION (contract));
    2807              : 
    2808              :   /* Must match the type layout in builtin_contract_violation_type.  */
    2809         1036 :   tree f0 = next_aggregate_field (TYPE_FIELDS (builtin_contract_violation_type));
    2810         1036 :   tree f1 = next_aggregate_field (DECL_CHAIN (f0));
    2811         1036 :   tree f2 = next_aggregate_field (DECL_CHAIN (f1));
    2812         1036 :   tree f3 = next_aggregate_field (DECL_CHAIN (f2));
    2813         1036 :   tree f4 = next_aggregate_field (DECL_CHAIN (f3));
    2814         1036 :   tree f5 = next_aggregate_field (DECL_CHAIN (f4));
    2815         1036 :   tree f6 = next_aggregate_field (DECL_CHAIN (f5));
    2816         1036 :   tree ctor = build_constructor_va
    2817         1036 :     (builtin_contract_violation_type, 7,
    2818         1036 :      f0, build_int_cst (uint16_type_node, version),
    2819              :      f1, assertion_kind,
    2820              :      f2, eval_semantic,
    2821         1036 :      f3, build_int_cst (uint16_type_node, detection_mode),
    2822              :      f4, comment,
    2823              :      f5, std_src_loc_impl_ptr,
    2824              :      f6, build_zero_cst (nullptr_type_node)); // __vendor_ext
    2825              : 
    2826         1036 :   TREE_READONLY (ctor) = true;
    2827         1036 :   if (can_be_const)
    2828         1036 :     TREE_CONSTANT (ctor) = true;
    2829              : 
    2830         1036 :   return ctor;
    2831              : }
    2832              : 
    2833              : /* Build a named TU-local constant of TYPE.  */
    2834              : 
    2835              : static tree
    2836         1036 : contracts_tu_local_named_var (location_t loc, const char *name, tree type)
    2837              : {
    2838         1036 :   tree var_ = build_decl (loc, VAR_DECL, NULL, type);
    2839         1036 :   DECL_NAME (var_) = generate_internal_label (name);
    2840         1036 :   TREE_PUBLIC (var_) = false;
    2841         1036 :   DECL_EXTERNAL (var_) = false;
    2842         1036 :   TREE_STATIC (var_) = true;
    2843              :   /* Compiler-generated.  */
    2844         1036 :   DECL_ARTIFICIAL (var_) = true;
    2845         1036 :   TREE_CONSTANT (var_) = true;
    2846         1036 :   layout_decl (var_, 0);
    2847         1036 :   return var_;
    2848              : }
    2849              : 
    2850              : /* Create a read-only violation object.  */
    2851              : 
    2852              : static tree
    2853         1036 : build_contract_violation_constant (tree ctor, tree contract)
    2854              : {
    2855         1036 :   tree viol_ = contracts_tu_local_named_var
    2856         1036 :     (EXPR_LOCATION (contract), "Lcontract_violation",
    2857              :      builtin_contract_violation_type);
    2858              : 
    2859         1036 :   TREE_CONSTANT (viol_) = true;
    2860         1036 :   DECL_INITIAL (viol_) = ctor;
    2861         1036 :   varpool_node::finalize_decl (viol_);
    2862              : 
    2863         1036 :   return viol_;
    2864              : }
    2865              : 
    2866              : /* Helper to replace references to dummy this parameters with references to
    2867              :    the first argument of the FUNCTION_DECL DATA.  */
    2868              : 
    2869              : static tree
    2870         5112 : remap_dummy_this_1 (tree *tp, int *, void *data)
    2871              : {
    2872         5112 :   if (!is_this_parameter (*tp))
    2873              :     return NULL_TREE;
    2874           49 :   tree fn = (tree)data;
    2875           49 :   *tp = DECL_ARGUMENTS (fn);
    2876           49 :   return NULL_TREE;
    2877              : }
    2878              : 
    2879              : /* Replace all references to dummy this parameters in EXPR with references to
    2880              :    the first argument of the FUNCTION_DECL FNDECL.  */
    2881              : 
    2882              : static void
    2883         1038 : remap_dummy_this (tree fndecl, tree *expr)
    2884              : {
    2885            0 :   walk_tree (expr, remap_dummy_this_1, fndecl, NULL);
    2886            0 : }
    2887              : 
    2888              : /* Replace uses of user's placeholder var with the actual return value.  */
    2889              : 
    2890              : struct replace_tree
    2891              : {
    2892              :   tree from, to;
    2893              : };
    2894              : 
    2895              : static tree
    2896         1793 : remap_retval_1 (tree *here, int *do_subtree, void *d)
    2897              : {
    2898         1793 :   replace_tree *data = (replace_tree *) d;
    2899              : 
    2900         1793 :   if (*here == data->from)
    2901              :     {
    2902           84 :       *here = data->to;
    2903           84 :       *do_subtree = 0;
    2904              :     }
    2905              :   else
    2906         1709 :     *do_subtree = 1;
    2907         1793 :   return NULL_TREE;
    2908              : }
    2909              : 
    2910              : static void
    2911          355 : remap_retval (tree fndecl, tree contract)
    2912              : {
    2913          355 :   struct replace_tree data;
    2914          355 :   data.from = POSTCONDITION_IDENTIFIER (contract);
    2915          355 :   gcc_checking_assert (DECL_RESULT (fndecl));
    2916          355 :   data.to = DECL_RESULT (fndecl);
    2917          355 :   walk_tree (&CONTRACT_CONDITION (contract), remap_retval_1, &data, NULL);
    2918          355 : }
    2919              : 
    2920              : 
    2921              : /* Genericize a CONTRACT tree, but do not attach it to the current context,
    2922              :    the caller is responsible for that.
    2923              :    This is called during genericization.  */
    2924              : 
    2925              : tree
    2926         1040 : build_contract_check (tree contract)
    2927              : {
    2928         1040 :   contract_evaluation_semantic semantic = get_evaluation_semantic (contract);
    2929         1040 :   bool quick = false;
    2930         1040 :   bool calls_handler = false;
    2931         1040 :   switch (semantic)
    2932              :     {
    2933            2 :     case CES_IGNORE:
    2934            2 :       return void_node;
    2935              :     case CES_ENFORCE:
    2936              :     case CES_OBSERVE:
    2937              :       calls_handler = true;
    2938              :       break;
    2939            2 :     case CES_QUICK:
    2940            2 :       quick = true;
    2941            2 :       break;
    2942            0 :     default:
    2943            0 :       gcc_unreachable ();
    2944              :     }
    2945              : 
    2946         1038 :   location_t loc = EXPR_LOCATION (contract);
    2947              : 
    2948         1038 :   remap_dummy_this (current_function_decl, &CONTRACT_CONDITION (contract));
    2949         1038 :   tree condition = CONTRACT_CONDITION (contract);
    2950         1038 :   if (condition == error_mark_node)
    2951              :     return NULL_TREE;
    2952              : 
    2953         1038 :   if (!flag_contract_checks_outlined && POSTCONDITION_P (contract))
    2954              :     {
    2955          355 :       remap_retval (current_function_decl, contract);
    2956          355 :       condition = CONTRACT_CONDITION (contract);
    2957          355 :       if (condition == error_mark_node)
    2958              :         return NULL_TREE;
    2959              :     }
    2960              : 
    2961         1038 :   tree terminate_wrapper = terminate_fn;
    2962         1038 :   if (flag_contracts_conservative_ipa)
    2963         1038 :     terminate_wrapper = declare_terminate_wrapper ();
    2964         1038 :   if (calls_handler)
    2965         1036 :     declare_violation_handler_wrappers ();
    2966              : 
    2967         1038 :   bool check_might_throw = (flag_exceptions
    2968         1038 :                             && !expr_noexcept_p (condition, tf_none));
    2969              : 
    2970              :   /* Build a statement expression to hold a contract check, with the check
    2971              :      potentially wrapped in a try-catch expr.  */
    2972         1038 :   tree cc_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
    2973         1038 :   BIND_EXPR_BODY (cc_bind) = push_stmt_list ();
    2974              : 
    2975         1038 :   if (TREE_CODE (contract) == ASSERTION_STMT)
    2976          154 :     emit_builtin_observable_checkpoint ();
    2977         1038 :   tree cond = build_x_unary_op (loc, TRUTH_NOT_EXPR, condition, NULL_TREE,
    2978              :                                 tf_warning_or_error);
    2979         1038 :   tree violation;
    2980         1038 :   bool viol_is_var = false;
    2981         1038 :   if (quick)
    2982              :     /* We will not be calling a handler.  */
    2983            2 :     violation = build_zero_cst (nullptr_type_node);
    2984              :   else
    2985              :     {
    2986              :       /* Build a violation object, with the contract settings.  */
    2987         1036 :       tree ctor = build_contract_violation_ctor (contract);
    2988         1036 :       gcc_checking_assert (TREE_CONSTANT (ctor));
    2989         1036 :       violation = build_contract_violation_constant (ctor, contract);
    2990         1036 :       violation = build_address (violation);
    2991              :     }
    2992              : 
    2993         1038 :   tree s_const = build_int_cst (uint16_type_node, semantic);
    2994              :   /* So now do we need a try-catch?  */
    2995         1038 :   if (check_might_throw)
    2996              :     {
    2997              :       /* This will hold the computed condition.  */
    2998          193 :       tree check_failed = build_decl (loc, VAR_DECL, NULL, boolean_type_node);
    2999          193 :       DECL_ARTIFICIAL (check_failed) = true;
    3000          193 :       DECL_IGNORED_P (check_failed) = true;
    3001          193 :       DECL_CONTEXT (check_failed) = current_function_decl;
    3002          193 :       layout_decl (check_failed, 0);
    3003          193 :       add_decl_expr (check_failed);
    3004          193 :       DECL_CHAIN (check_failed) = BIND_EXPR_VARS (cc_bind);
    3005          193 :       BIND_EXPR_VARS (cc_bind) = check_failed;
    3006          193 :       tree check_try = begin_try_block ();
    3007          193 :       finish_expr_stmt (cp_build_init_expr (check_failed, cond));
    3008          193 :       finish_try_block (check_try);
    3009              : 
    3010          193 :       tree handler = begin_handler ();
    3011          193 :       finish_handler_parms (NULL_TREE, handler); /* catch (...) */
    3012          193 :       if (quick)
    3013            0 :         finish_expr_stmt (build_call_a (terminate_wrapper, 0, nullptr));
    3014              :       else
    3015              :         {
    3016          193 :           if (viol_is_var)
    3017              :             {
    3018              :               /* We can update the detection mode here.  */
    3019              :               tree memb
    3020              :                 = lookup_member (builtin_contract_violation_type,
    3021              :                                  get_identifier ("_M_detection_mode"),
    3022              :                                  1, 0, tf_warning_or_error);
    3023              :               tree r = cp_build_indirect_ref (loc, violation, RO_UNARY_STAR,
    3024              :                                               tf_warning_or_error);
    3025              :               r = build_class_member_access_expr (r, memb, NULL_TREE, false,
    3026              :                                                   tf_warning_or_error);
    3027              :               r = cp_build_modify_expr
    3028              :                 (loc, r, NOP_EXPR,
    3029              :                  build_int_cst (uint16_type_node, (uint16_t)CDM_EVAL_EXCEPTION),
    3030              :                  tf_warning_or_error);
    3031              :               finish_expr_stmt (r);
    3032              :               finish_expr_stmt (build_call_n (tu_has_violation, 2,
    3033              :                                               violation, s_const));
    3034              :             }
    3035              :           else
    3036              :             /* We need to make a copy of the violation object to update.  */
    3037          193 :             finish_expr_stmt (build_call_n (tu_has_violation_exception, 2,
    3038              :                                             violation, s_const));
    3039              :           /* If we reach here, we have handled the exception thrown and do not
    3040              :              need further action.  */
    3041          193 :           tree e = cp_build_modify_expr (loc, check_failed, NOP_EXPR,
    3042              :                                          boolean_false_node,
    3043              :                                          tf_warning_or_error);
    3044          193 :           finish_expr_stmt (e);
    3045              :         }
    3046          193 :       finish_handler (handler);
    3047          193 :       finish_handler_sequence (check_try);
    3048          193 :       cond = check_failed;
    3049          193 :       BIND_EXPR_VARS (cc_bind) = nreverse (BIND_EXPR_VARS (cc_bind));
    3050              :     }
    3051              : 
    3052         1038 :   tree do_check = begin_if_stmt ();
    3053         1038 :   finish_if_stmt_cond (cond, do_check);
    3054         1038 :   if (quick)
    3055            2 :     finish_expr_stmt (build_call_a (terminate_wrapper, 0, nullptr));
    3056              :   else
    3057         1036 :     finish_expr_stmt (build_call_n (tu_has_violation, 2, violation, s_const));
    3058         1038 :   finish_then_clause (do_check);
    3059         1038 :   finish_if_stmt (do_check);
    3060              : 
    3061         1038 :   TREE_SIDE_EFFECTS (cc_bind) = true;
    3062         1038 :   BIND_EXPR_BODY (cc_bind) = pop_stmt_list (BIND_EXPR_BODY (cc_bind));
    3063         1038 :   return cc_bind;
    3064              : }
    3065              : 
    3066              : #include "gt-cp-contracts.h"
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.