LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-cfg-strip.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.9 % 1157 832
Test Date: 2026-03-28 14:25:54 Functions: 95.1 % 122 116
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-cfg-strip.h"
      20              : #include "rust-ast-full.h"
      21              : #include "rust-ast-visitor.h"
      22              : #include "rust-path.h"
      23              : #include "rust-session-manager.h"
      24              : #include "rust-attribute-values.h"
      25              : #include "rust-macro-expand.h"
      26              : 
      27              : namespace Rust {
      28              : 
      29              : /**
      30              :  * Determines whether any cfg predicate is false and hence item with attributes
      31              :  * should be stripped. Will expand attributes as well.
      32              :  */
      33              : bool
      34      1825945 : CfgStrip::fails_cfg_with_expand (AST::AttrVec &attrs) const
      35              : {
      36      1825945 :   auto &session = Session::get_instance ();
      37              : 
      38              :   // TODO: maybe have something that strips cfg attributes that evaluate true?
      39      1926166 :   for (auto &attr : attrs)
      40              :     {
      41       100334 :       if (attr.get_path () == Values::Attributes::CFG)
      42              :         {
      43         2116 :           if (!attr.is_parsed_to_meta_item ())
      44          479 :             attr.parse_attr_to_meta_item ();
      45              : 
      46              :           // DEBUG
      47         2116 :           if (!attr.is_parsed_to_meta_item ())
      48            1 :             rust_debug ("failed to parse attr to meta item, right before "
      49              :                         "cfg predicate check");
      50              :           else
      51         2115 :             rust_debug ("attr has been successfully parsed to meta item, "
      52              :                         "right before cfg predicate check");
      53              : 
      54         2116 :           if (!attr.check_cfg_predicate (session))
      55              :             {
      56              :               // DEBUG
      57          112 :               rust_debug (
      58              :                 "cfg predicate failed for attribute: \033[0;31m'%s'\033[0m",
      59              :                 attr.as_string ().c_str ());
      60              : 
      61          112 :               return true;
      62              :             }
      63              :           else
      64              :             {
      65              :               // DEBUG
      66         2004 :               rust_debug ("cfg predicate succeeded for attribute: "
      67              :                           "\033[0;31m'%s'\033[0m",
      68              :                           attr.as_string ().c_str ());
      69              :             }
      70              :         }
      71        98218 :       else if (!expansion_cfg.should_test
      72       196436 :                && attr.get_path () == Values::Attributes::TEST)
      73              :         return true;
      74              :     }
      75              :   return false;
      76              : }
      77              : 
      78              : /**
      79              :  * Expands cfg_attr attributes.
      80              :  */
      81              : void
      82      1830467 : expand_cfg_attrs (AST::AttrVec &attrs)
      83              : {
      84      1830467 :   auto &session = Session::get_instance ();
      85              : 
      86      1942073 :   for (std::size_t i = 0; i < attrs.size (); i++)
      87              :     {
      88       111606 :       auto &attr = attrs[i];
      89       111606 :       if (attr.get_path () == Values::Attributes::CFG_ATTR)
      90              :         {
      91           16 :           if (!attr.is_parsed_to_meta_item ())
      92            5 :             attr.parse_attr_to_meta_item ();
      93              : 
      94           16 :           if (attr.check_cfg_predicate (session))
      95              :             {
      96              :               // Key has been found we need to remove the conditional part of
      97              :               // the attribute and insert the content back
      98              : 
      99              :               // split off cfg_attr
     100            8 :               AST::AttrVec new_attrs = attr.separate_cfg_attrs ();
     101              : 
     102              :               // remove attr from vector
     103            8 :               attrs.erase (attrs.begin () + i);
     104              : 
     105              :               // add new attrs to vector
     106            8 :               attrs.insert (attrs.begin () + i,
     107              :                             std::make_move_iterator (new_attrs.begin ()),
     108              :                             std::make_move_iterator (new_attrs.end ()));
     109              : 
     110              :               /* Decrement i so that the for loop's i++ will bring us back to
     111              :                * position i, allowing us to reprocess the newly inserted
     112              :                * attribute (in case it's also a cfg_attr that needs expansion)
     113              :                */
     114            8 :               i--;
     115            8 :             }
     116              :           else
     117              :             {
     118              :               // Key has not been found, remove the whole attribute
     119            8 :               attrs.erase (attrs.begin () + i);
     120            8 :               i--;
     121              :             }
     122              : 
     123              :           /* do something - if feature (first token in tree) is in fact enabled,
     124              :            * make tokens listed afterwards into attributes. i.e.: for
     125              :            * [cfg_attr(feature = "wow", wow1, wow2)], if "wow" is true, then add
     126              :            * attributes [wow1] and [wow2] to attribute list. This can also be
     127              :            * recursive, so check for expanded attributes being recursive and
     128              :            * possibly recursively call the expand_attrs? */
     129              :         }
     130              :     }
     131      1830467 :   attrs.shrink_to_fit ();
     132      1830467 : }
     133              : 
     134              : void
     135        10431 : CfgStrip::go (AST::Crate &crate)
     136              : {
     137        10431 :   visit (crate);
     138        10431 : }
     139              : 
     140              : void
     141        10431 : CfgStrip::visit (AST::Crate &crate)
     142              : {
     143              :   // expand crate cfg_attr attributes
     144        10431 :   expand_cfg_attrs (crate.inner_attrs);
     145              : 
     146        10431 :   if (fails_cfg_with_expand (crate.inner_attrs))
     147              :     {
     148              :       // basically, delete whole crate
     149            1 :       crate.strip_crate ();
     150              :       // TODO: maybe create warning here? probably not desired behaviour
     151              :     }
     152              : 
     153        10431 :   auto &items = crate.items;
     154              : 
     155        10431 :   AST::DefaultASTVisitor::visit (crate);
     156        55656 :   for (auto it = items.begin (); it != items.end ();)
     157              :     {
     158        45225 :       auto &item = *it;
     159        45225 :       if (item->is_marked_for_strip ())
     160           19 :         it = items.erase (it);
     161              :       else
     162        45206 :         it++;
     163              :     }
     164              :   // expand module attributes?
     165        10431 : }
     166              : 
     167              : // Visitor used to expand attributes.
     168              : void
     169         4749 : CfgStrip::maybe_strip_struct_fields (std::vector<AST::StructField> &fields)
     170              : {
     171        10551 :   for (auto it = fields.begin (); it != fields.end ();)
     172              :     {
     173         5802 :       auto &field = *it;
     174              : 
     175         5802 :       auto &field_attrs = field.get_outer_attrs ();
     176         5802 :       expand_cfg_attrs (field_attrs);
     177         5802 :       if (fails_cfg_with_expand (field_attrs))
     178              :         {
     179            1 :           it = fields.erase (it);
     180            1 :           continue;
     181              :         }
     182              : 
     183              :       // expand sub-types of type, but can't strip type itself
     184         5801 :       auto &type = field.get_field_type ();
     185         5801 :       type.accept_vis (*this);
     186              : 
     187         5801 :       if (type.is_marked_for_strip ())
     188            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
     189              : 
     190              :       // if nothing else happens, increment
     191         5801 :       ++it;
     192              :     }
     193         4749 : }
     194              : 
     195              : void
     196         5764 : CfgStrip::maybe_strip_struct_expr_fields (
     197              :   std::vector<std::unique_ptr<AST::StructExprField>> &fields)
     198              : {
     199        16057 :   for (auto it = fields.begin (); it != fields.end ();)
     200              :     {
     201        10293 :       auto &field = *it;
     202              : 
     203        10293 :       auto &field_attrs = field->get_outer_attrs ();
     204        10293 :       expand_cfg_attrs (field_attrs);
     205        10293 :       if (fails_cfg_with_expand (field_attrs))
     206              :         {
     207            1 :           it = fields.erase (it);
     208            1 :           continue;
     209              :         }
     210              : 
     211        10292 :       ++it;
     212              :     }
     213         5764 : }
     214              : 
     215              : void
     216         4704 : CfgStrip::maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields)
     217              : {
     218        12197 :   for (auto it = fields.begin (); it != fields.end ();)
     219              :     {
     220         7493 :       auto &field = *it;
     221              : 
     222         7493 :       auto &field_attrs = field.get_outer_attrs ();
     223         7493 :       expand_cfg_attrs (field_attrs);
     224         7493 :       if (fails_cfg_with_expand (field_attrs))
     225              :         {
     226            0 :           it = fields.erase (it);
     227            0 :           continue;
     228              :         }
     229              : 
     230              :       // expand sub-types of type, but can't strip type itself
     231         7493 :       auto &type = field.get_field_type ();
     232         7493 :       type.accept_vis (*this);
     233         7493 :       if (type.is_marked_for_strip ())
     234            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
     235              : 
     236              :       // if nothing else happens, increment
     237         7493 :       ++it;
     238              :     }
     239         4704 : }
     240              : 
     241              : void
     242        67581 : CfgStrip::maybe_strip_function_params (
     243              :   std::vector<std::unique_ptr<AST::Param>> &params)
     244              : {
     245       152012 :   for (auto it = params.begin (); it != params.end ();)
     246              :     {
     247        84431 :       if (!(*it)->is_self () && !(*it)->is_variadic ())
     248              :         {
     249        43020 :           auto param = static_cast<AST::FunctionParam *> (it->get ());
     250              : 
     251        43020 :           auto &param_attrs = param->get_outer_attrs ();
     252        43020 :           expand_cfg_attrs (param_attrs);
     253        43020 :           if (fails_cfg_with_expand (param_attrs))
     254              :             {
     255            0 :               it = params.erase (it);
     256            0 :               continue;
     257              :             }
     258              : 
     259              :           // TODO: should an unwanted strip lead to break out of loop?
     260        43020 :           auto &pattern = param->get_pattern ();
     261        43020 :           pattern.accept_vis (*this);
     262        43020 :           if (pattern.is_marked_for_strip ())
     263            0 :             rust_error_at (pattern.get_locus (),
     264              :                            "cannot strip pattern in this position");
     265              : 
     266        43020 :           auto &type = param->get_type ();
     267        43020 :           type.accept_vis (*this);
     268              : 
     269        43020 :           if (type.is_marked_for_strip ())
     270            0 :             rust_error_at (type.get_locus (),
     271              :                            "cannot strip type in this position");
     272              :         }
     273              :       // increment
     274        84431 :       ++it;
     275              :     }
     276        67581 : }
     277              : 
     278              : void
     279        20635 : CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args)
     280              : {
     281              :   // lifetime args can't be expanded
     282              :   // FIXME: Can we have macro invocations for lifetimes?
     283              : 
     284              :   // expand type args - strip sub-types only
     285        42008 :   for (auto &arg : args.get_generic_args ())
     286              :     {
     287        21373 :       switch (arg.get_kind ())
     288              :         {
     289         9435 :         case AST::GenericArg::Kind::Type:
     290         9435 :           {
     291         9435 :             auto &type = arg.get_type ();
     292         9435 :             type.accept_vis (*this);
     293              : 
     294         9435 :             if (type.is_marked_for_strip ())
     295            0 :               rust_error_at (type.get_locus (),
     296              :                              "cannot strip type in this position");
     297              :             break;
     298              :           }
     299          392 :         case AST::GenericArg::Kind::Const:
     300          392 :           {
     301          392 :             auto &expr = arg.get_expression ();
     302          392 :             expr.accept_vis (*this);
     303              : 
     304          392 :             if (expr.is_marked_for_strip ())
     305            0 :               rust_error_at (expr.get_locus (),
     306              :                              "cannot strip expression in this position");
     307              :             break;
     308              :           }
     309              :         default:
     310              :           break;
     311              :           // FIXME: Figure out what to do here if there is ambiguity. Since the
     312              :           // resolver comes after the expansion, we need to figure out a way to
     313              :           // strip ambiguous values here
     314              :           // TODO: Arthur: Probably add a `mark_as_strip` method to `GenericArg`
     315              :           // or something. This would clean up this whole thing
     316              :         }
     317              :     }
     318              : 
     319              :   // FIXME: Can we have macro invocations in generic type bindings?
     320              :   // expand binding args - strip sub-types only
     321        20967 :   for (auto &binding : args.get_binding_args ())
     322              :     {
     323          332 :       auto &type = binding.get_type ();
     324          332 :       type.accept_vis (*this);
     325              : 
     326          332 :       if (type.is_marked_for_strip ())
     327            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
     328              :     }
     329        20635 : }
     330              : 
     331              : void
     332         1779 : CfgStrip::maybe_strip_qualified_path_type (AST::QualifiedPathType &path_type)
     333              : {
     334         1779 :   auto &type = path_type.get_type ();
     335         1779 :   type.accept_vis (*this);
     336              : 
     337         1779 :   if (type.is_marked_for_strip ())
     338            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
     339              : 
     340         1779 :   if (path_type.has_as_clause ())
     341              :     {
     342         1589 :       auto &type_path = path_type.get_as_type_path ();
     343         1589 :       visit (type_path);
     344         1589 :       if (type_path.is_marked_for_strip ())
     345            0 :         rust_error_at (type_path.get_locus (),
     346              :                        "cannot strip type path in this position");
     347              :     }
     348         1779 : }
     349              : 
     350              : void
     351          250 : CfgStrip::CfgStrip::maybe_strip_closure_params (
     352              :   std::vector<AST::ClosureParam> &params)
     353              : {
     354          500 :   for (auto it = params.begin (); it != params.end ();)
     355              :     {
     356          250 :       auto &param = *it;
     357              : 
     358          250 :       auto &param_attrs = param.get_outer_attrs ();
     359          250 :       expand_cfg_attrs (param_attrs);
     360          250 :       if (fails_cfg_with_expand (param_attrs))
     361              :         {
     362            0 :           it = params.erase (it);
     363            0 :           continue;
     364              :         }
     365              : 
     366          250 :       auto &pattern = param.get_pattern ();
     367          250 :       pattern.accept_vis (*this);
     368          250 :       if (pattern.is_marked_for_strip ())
     369            0 :         rust_error_at (pattern.get_locus (),
     370              :                        "cannot strip pattern in this position");
     371              : 
     372          250 :       if (param.has_type_given ())
     373              :         {
     374          232 :           auto &type = param.get_type ();
     375          232 :           type.accept_vis (*this);
     376              : 
     377          232 :           if (type.is_marked_for_strip ())
     378            0 :             rust_error_at (type.get_locus (),
     379              :                            "cannot strip type in this position");
     380              :         }
     381              : 
     382              :       // increment if found nothing else so far
     383          250 :       ++it;
     384              :     }
     385          250 : }
     386              : 
     387              : void
     388            0 : CfgStrip::maybe_strip_where_clause (AST::WhereClause &where_clause)
     389              : {
     390              :   // items cannot be stripped conceptually, so just accept visitor
     391            0 :   for (auto &item : where_clause.get_items ())
     392            0 :     item->accept_vis (*this);
     393            0 : }
     394              : 
     395              : void
     396       208278 : CfgStrip::visit (AST::IdentifierExpr &ident_expr)
     397              : {
     398              :   // strip test based on outer attrs
     399       208278 :   AST::DefaultASTVisitor::visit (ident_expr);
     400       208278 :   expand_cfg_attrs (ident_expr.get_outer_attrs ());
     401       208278 :   if (fails_cfg_with_expand (ident_expr.get_outer_attrs ()))
     402              :     {
     403            0 :       ident_expr.mark_for_strip ();
     404            0 :       return;
     405              :     }
     406              : }
     407              : 
     408              : void
     409         4597 : CfgStrip::visit (AST::MacroInvocation &macro_invoc)
     410              : {
     411              :   // initial strip test based on outer attrs
     412         4597 :   expand_cfg_attrs (macro_invoc.get_outer_attrs ());
     413         4597 :   if (fails_cfg_with_expand (macro_invoc.get_outer_attrs ()))
     414              :     {
     415            0 :       macro_invoc.mark_for_strip ();
     416            0 :       return;
     417              :     }
     418              : 
     419              :   // can't strip simple path
     420              : 
     421              :   // I don't think any macro token trees can be stripped in any way
     422              : 
     423              :   // TODO: maybe have cfg! macro stripping behaviour here?
     424              : }
     425              : 
     426              : void
     427       160969 : CfgStrip::visit (AST::PathInExpression &path)
     428              : {
     429              :   // initial strip test based on outer attrs
     430       160969 :   expand_cfg_attrs (path.get_outer_attrs ());
     431       160969 :   if (fails_cfg_with_expand (path.get_outer_attrs ()))
     432              :     {
     433            0 :       path.mark_for_strip ();
     434            0 :       return;
     435              :     }
     436              : 
     437       160969 :   if (!path.is_lang_item ())
     438              :     {
     439       383644 :       for (auto &segment : path.get_segments ())
     440              :         {
     441       446346 :           if (segment.has_generic_args ())
     442         7105 :             maybe_strip_generic_args (segment.get_generic_args ());
     443              :         }
     444              :     }
     445              : }
     446              : 
     447              : void
     448        13446 : CfgStrip::visit (AST::TypePathSegmentGeneric &segment)
     449              : {
     450              :   // TODO: strip inside generic args
     451              : 
     452        13446 :   if (!segment.has_generic_args ())
     453              :     return;
     454              : 
     455        13442 :   maybe_strip_generic_args (segment.get_generic_args ());
     456              : }
     457              : void
     458           78 : CfgStrip::visit (AST::TypePathSegmentFunction &segment)
     459              : {
     460           78 :   AST::DefaultASTVisitor::visit (segment);
     461           78 :   auto &type_path_function = segment.get_type_path_function ();
     462              : 
     463          160 :   for (auto &type : type_path_function.get_params ())
     464              :     {
     465           82 :       if (type->is_marked_for_strip ())
     466            0 :         rust_error_at (type->get_locus (),
     467              :                        "cannot strip type in this position");
     468              :     }
     469              : 
     470           78 :   if (type_path_function.has_return_type ())
     471              :     {
     472           74 :       auto &return_type = type_path_function.get_return_type ();
     473              : 
     474           74 :       if (return_type.is_marked_for_strip ())
     475            0 :         rust_error_at (return_type.get_locus (),
     476              :                        "cannot strip type in this position");
     477              :     }
     478           78 : }
     479              : 
     480              : void
     481          526 : CfgStrip::visit (AST::QualifiedPathInExpression &path)
     482              : {
     483              :   // initial strip test based on outer attrs
     484          526 :   AST::DefaultASTVisitor::visit (path);
     485              : 
     486          526 :   expand_cfg_attrs (path.get_outer_attrs ());
     487          526 :   if (fails_cfg_with_expand (path.get_outer_attrs ()))
     488              :     {
     489            0 :       path.mark_for_strip ();
     490            0 :       return;
     491              :     }
     492              : 
     493          526 :   maybe_strip_qualified_path_type (path.get_qualified_path_type ());
     494              : 
     495         1052 :   for (auto &segment : path.get_segments ())
     496              :     {
     497         1052 :       if (segment.has_generic_args ())
     498            0 :         maybe_strip_generic_args (segment.get_generic_args ());
     499              :     }
     500              : }
     501              : 
     502              : void
     503         1253 : CfgStrip::visit (AST::QualifiedPathInType &path)
     504              : {
     505         1253 :   maybe_strip_qualified_path_type (path.get_qualified_path_type ());
     506              : 
     507              :   // this shouldn't strip any segments, but can strip inside them
     508         1253 :   AST::DefaultASTVisitor::visit (path);
     509         1253 : }
     510              : 
     511              : void
     512       689246 : CfgStrip::visit (AST::LiteralExpr &expr)
     513              : {
     514              :   // initial strip test based on outer attrs
     515       689246 :   expand_cfg_attrs (expr.get_outer_attrs ());
     516       689246 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     517              :     {
     518            0 :       expr.mark_for_strip ();
     519            0 :       return;
     520              :     }
     521              : }
     522              : 
     523              : void
     524        17510 : CfgStrip::visit (AST::BorrowExpr &expr)
     525              : {
     526        17510 :   AST::DefaultASTVisitor::visit (expr);
     527              :   // initial strip test based on outer attrs
     528        17510 :   expand_cfg_attrs (expr.get_outer_attrs ());
     529        17510 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     530              :     {
     531            0 :       expr.mark_for_strip ();
     532            0 :       return;
     533              :     }
     534              : 
     535              :   /* strip any internal sub-expressions - expression itself isn't
     536              :    * allowed to have external attributes in this position so can't be
     537              :    * stripped. */
     538        17510 :   auto &borrowed_expr = expr.get_borrowed_expr ();
     539        17510 :   if (borrowed_expr.is_marked_for_strip ())
     540            0 :     rust_error_at (borrowed_expr.get_locus (),
     541              :                    "cannot strip expression in this position - outer "
     542              :                    "attributes not allowed");
     543              : }
     544              : void
     545        21384 : CfgStrip::visit (AST::DereferenceExpr &expr)
     546              : {
     547              :   // initial strip test based on outer attrs
     548        21384 :   expand_cfg_attrs (expr.get_outer_attrs ());
     549        21384 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     550              :     {
     551            0 :       expr.mark_for_strip ();
     552            0 :       return;
     553              :     }
     554              : 
     555              :   /* strip any internal sub-expressions - expression itself isn't
     556              :    * allowed to have external attributes in this position so can't be
     557              :    * stripped. */
     558        21384 :   auto &dereferenced_expr = expr.get_dereferenced_expr ();
     559        21384 :   dereferenced_expr.accept_vis (*this);
     560        21384 :   if (dereferenced_expr.is_marked_for_strip ())
     561            0 :     rust_error_at (dereferenced_expr.get_locus (),
     562              :                    "cannot strip expression in this position - outer "
     563              :                    "attributes not allowed");
     564              : }
     565              : void
     566            4 : CfgStrip::visit (AST::ErrorPropagationExpr &expr)
     567              : {
     568            4 :   AST::DefaultASTVisitor::visit (expr);
     569              : 
     570              :   // initial strip test based on outer attrs
     571            4 :   expand_cfg_attrs (expr.get_outer_attrs ());
     572            4 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     573              :     {
     574            0 :       expr.mark_for_strip ();
     575            0 :       return;
     576              :     }
     577              : 
     578              :   /* strip any internal sub-expressions - expression itself isn't
     579              :    * allowed to have external attributes in this position so can't be
     580              :    * stripped. */
     581            4 :   auto &propagating_expr = expr.get_propagating_expr ();
     582            4 :   if (propagating_expr.is_marked_for_strip ())
     583            0 :     rust_error_at (propagating_expr.get_locus (),
     584              :                    "cannot strip expression in this position - outer "
     585              :                    "attributes not allowed");
     586              : }
     587              : void
     588         2418 : CfgStrip::visit (AST::NegationExpr &expr)
     589              : {
     590         2418 :   AST::DefaultASTVisitor::visit (expr);
     591              :   // initial strip test based on outer attrs
     592         2418 :   expand_cfg_attrs (expr.get_outer_attrs ());
     593         2418 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     594              :     {
     595            0 :       expr.mark_for_strip ();
     596            0 :       return;
     597              :     }
     598              : 
     599              :   /* strip any internal sub-expressions - expression itself isn't
     600              :    * allowed to have external attributes in this position so can't be
     601              :    * stripped. */
     602         2418 :   auto &negated_expr = expr.get_negated_expr ();
     603         2418 :   if (negated_expr.is_marked_for_strip ())
     604            0 :     rust_error_at (negated_expr.get_locus (),
     605              :                    "cannot strip expression in this position - outer "
     606              :                    "attributes not allowed");
     607              : }
     608              : void
     609       540417 : CfgStrip::visit (AST::ArithmeticOrLogicalExpr &expr)
     610              : {
     611       540417 :   AST::DefaultASTVisitor::visit (expr);
     612              :   /* outer attributes never allowed before these. while cannot strip
     613              :    * two direct descendant expressions, can strip ones below that */
     614              : 
     615              :   // ensure that they are not marked for strip
     616       540417 :   if (expr.get_left_expr ().is_marked_for_strip ())
     617            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     618              :                    "cannot strip expression in this position - outer "
     619              :                    "attributes are never allowed "
     620              :                    "before binary op exprs");
     621       540417 :   if (expr.get_right_expr ().is_marked_for_strip ())
     622            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     623              :                    "cannot strip expression in this position - outer "
     624              :                    "attributes not allowed");
     625       540417 : }
     626              : 
     627              : void
     628        13389 : CfgStrip::visit (AST::ComparisonExpr &expr)
     629              : {
     630              :   /* outer attributes never allowed before these. while cannot strip
     631              :    * two direct descendant expressions, can strip ones below that */
     632        13389 :   AST::DefaultASTVisitor::visit (expr);
     633              : 
     634              :   // ensure that they are not marked for strip
     635        13389 :   if (expr.get_left_expr ().is_marked_for_strip ())
     636            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     637              :                    "cannot strip expression in this position - outer "
     638              :                    "attributes are never allowed "
     639              :                    "before binary op exprs");
     640        13389 :   if (expr.get_right_expr ().is_marked_for_strip ())
     641            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     642              :                    "cannot strip expression in this position - outer "
     643              :                    "attributes not allowed");
     644        13389 : }
     645              : 
     646              : void
     647         1580 : CfgStrip::visit (AST::LazyBooleanExpr &expr)
     648              : {
     649              :   /* outer attributes never allowed before these. while cannot strip
     650              :    * two direct descendant expressions, can strip ones below that */
     651         1580 :   AST::DefaultASTVisitor::visit (expr);
     652              : 
     653              :   // ensure that they are not marked for strip
     654         1580 :   if (expr.get_left_expr ().is_marked_for_strip ())
     655            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     656              :                    "cannot strip expression in this position - outer "
     657              :                    "attributes are never allowed "
     658              :                    "before binary op exprs");
     659         1580 :   if (expr.get_right_expr ().is_marked_for_strip ())
     660            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     661              :                    "cannot strip expression in this position - outer "
     662              :                    "attributes not allowed");
     663         1580 : }
     664              : 
     665              : void
     666        52274 : CfgStrip::visit (AST::TypeCastExpr &expr)
     667              : {
     668              :   /* outer attributes never allowed before these. while cannot strip
     669              :    * direct descendant expression, can strip ones below that */
     670        52274 :   AST::DefaultASTVisitor::visit (expr);
     671              : 
     672        52274 :   auto &casted_expr = expr.get_casted_expr ();
     673              :   // ensure that they are not marked for strip
     674        52274 :   if (casted_expr.is_marked_for_strip ())
     675            0 :     rust_error_at (casted_expr.get_locus (),
     676              :                    "cannot strip expression in this position - outer "
     677              :                    "attributes are never allowed before cast exprs");
     678              : 
     679              :   // TODO: strip sub-types of type
     680        52274 :   auto &type = expr.get_type_to_cast_to ();
     681        52274 :   if (type.is_marked_for_strip ())
     682            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
     683        52274 : }
     684              : void
     685        15868 : CfgStrip::visit (AST::AssignmentExpr &expr)
     686              : {
     687        15868 :   expand_cfg_attrs (expr.get_outer_attrs ());
     688        15868 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     689              :     {
     690           14 :       expr.mark_for_strip ();
     691           14 :       return;
     692              :     }
     693        15854 :   AST::DefaultASTVisitor::visit (expr);
     694              : 
     695              :   // ensure that they are not marked for strip
     696        15854 :   if (expr.get_left_expr ().is_marked_for_strip ())
     697            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     698              :                    "cannot strip expression in this position - outer "
     699              :                    "attributes are never allowed "
     700              :                    "before binary op exprs");
     701        15854 :   if (expr.get_right_expr ().is_marked_for_strip ())
     702            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     703              :                    "cannot strip expression in this position - outer "
     704              :                    "attributes not allowed");
     705              : }
     706              : void
     707         6322 : CfgStrip::visit (AST::CompoundAssignmentExpr &expr)
     708              : {
     709              :   /* outer attributes never allowed before these. while cannot strip
     710              :    * two direct descendant expressions, can strip ones below that */
     711         6322 :   AST::DefaultASTVisitor::visit (expr);
     712              : 
     713              :   // ensure that they are not marked for strip
     714         6322 :   if (expr.get_left_expr ().is_marked_for_strip ())
     715            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     716              :                    "cannot strip expression in this position - outer "
     717              :                    "attributes are never allowed "
     718              :                    "before binary op exprs");
     719         6322 :   if (expr.get_right_expr ().is_marked_for_strip ())
     720            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     721              :                    "cannot strip expression in this position - outer "
     722              :                    "attributes not allowed");
     723         6322 : }
     724              : void
     725         2135 : CfgStrip::visit (AST::GroupedExpr &expr)
     726              : {
     727              :   // initial strip test based on outer attrs
     728         2135 :   expand_cfg_attrs (expr.get_outer_attrs ());
     729         2135 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     730              :     {
     731            0 :       expr.mark_for_strip ();
     732            0 :       return;
     733              :     }
     734              : 
     735              :   /* strip test based on inner attrs - spec says these are inner
     736              :    * attributes, not outer attributes of inner expr */
     737         2135 :   expand_cfg_attrs (expr.get_inner_attrs ());
     738         2135 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     739              :     {
     740            0 :       expr.mark_for_strip ();
     741            0 :       return;
     742              :     }
     743              : 
     744              :   /* strip any internal sub-expressions - expression itself isn't
     745              :    * allowed to have external attributes in this position so can't be
     746              :    * stripped. */
     747         2135 :   AST::DefaultASTVisitor::visit (expr);
     748              : 
     749         2135 :   auto &inner_expr = expr.get_expr_in_parens ();
     750         2135 :   if (inner_expr.is_marked_for_strip ())
     751            0 :     rust_error_at (inner_expr.get_locus (),
     752              :                    "cannot strip expression in this position - outer "
     753              :                    "attributes not allowed");
     754              : }
     755              : void
     756         1164 : CfgStrip::visit (AST::ArrayElemsValues &elems)
     757              : {
     758              :   /* apparently outer attributes are allowed in "elements of array
     759              :    * expressions" according to spec */
     760         1164 :   maybe_strip_pointer_allow_strip (elems.get_values ());
     761         1164 : }
     762              : void
     763          466 : CfgStrip::visit (AST::ArrayElemsCopied &elems)
     764              : {
     765              :   /* apparently outer attributes are allowed in "elements of array
     766              :    * expressions" according to spec. on the other hand, it would not
     767              :    * make conceptual sense to be able to remove either expression. As
     768              :    * such, not implementing. TODO clear up the ambiguity here */
     769          466 :   AST::DefaultASTVisitor::visit (elems);
     770              : 
     771              :   // only intend stripping for internal sub-expressions
     772          466 :   auto &copied_expr = elems.get_elem_to_copy ();
     773          466 :   if (copied_expr.is_marked_for_strip ())
     774            0 :     rust_error_at (copied_expr.get_locus (),
     775              :                    "cannot strip expression in this position - outer "
     776              :                    "attributes not allowed");
     777              : 
     778          466 :   auto &copy_count = elems.get_num_copies ();
     779          466 :   copy_count.accept_vis (*this);
     780          466 :   if (copy_count.is_marked_for_strip ())
     781            0 :     rust_error_at (copy_count.get_locus (),
     782              :                    "cannot strip expression in this position - outer "
     783              :                    "attributes not allowed");
     784          466 : }
     785              : void
     786         1630 : CfgStrip::visit (AST::ArrayExpr &expr)
     787              : {
     788              :   // initial strip test based on outer attrs
     789         1630 :   expand_cfg_attrs (expr.get_outer_attrs ());
     790         1630 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     791              :     {
     792            0 :       expr.mark_for_strip ();
     793            0 :       return;
     794              :     }
     795              : 
     796              :   /* strip test based on inner attrs - spec says there are separate
     797              :    * inner attributes, not just outer attributes of inner exprs */
     798         1630 :   expand_cfg_attrs (expr.get_inner_attrs ());
     799         1630 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     800              :     {
     801            0 :       expr.mark_for_strip ();
     802            0 :       return;
     803              :     }
     804              : 
     805              :   /* assuming you can't strip away the ArrayElems type, but can strip
     806              :    * internal expressions and whatever */
     807         1630 :   AST::DefaultASTVisitor::visit (expr);
     808              : }
     809              : 
     810              : void
     811         1404 : CfgStrip::visit (AST::ArrayIndexExpr &expr)
     812              : {
     813              :   /* it is unclear whether outer attributes are supposed to be
     814              :    * allowed, but conceptually it wouldn't make much sense, but
     815              :    * having expansion code anyway. TODO */
     816              :   // initial strip test based on outer attrs
     817         1404 :   expand_cfg_attrs (expr.get_outer_attrs ());
     818         1404 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     819              :     {
     820            0 :       expr.mark_for_strip ();
     821            0 :       return;
     822              :     }
     823              : 
     824              :   /* strip any internal sub-expressions - expression itself isn't
     825              :    * allowed to have external attributes in this position so can't be
     826              :    * stripped. */
     827         1404 :   AST::DefaultASTVisitor::visit (expr);
     828              : 
     829         1404 :   const auto &array_expr = expr.get_array_expr ();
     830         1404 :   if (array_expr.is_marked_for_strip ())
     831            0 :     rust_error_at (array_expr.get_locus (),
     832              :                    "cannot strip expression in this position - outer "
     833              :                    "attributes not allowed");
     834              : 
     835         1404 :   const auto &index_expr = expr.get_index_expr ();
     836         1404 :   if (index_expr.is_marked_for_strip ())
     837            0 :     rust_error_at (index_expr.get_locus (),
     838              :                    "cannot strip expression in this position - outer "
     839              :                    "attributes not allowed");
     840              : }
     841              : void
     842         2617 : CfgStrip::visit (AST::TupleExpr &expr)
     843              : {
     844              :   /* according to spec, outer attributes are allowed on "elements of
     845              :    * tuple expressions" */
     846              : 
     847              :   // initial strip test based on outer attrs
     848         2617 :   expand_cfg_attrs (expr.get_outer_attrs ());
     849         2617 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     850              :     {
     851            0 :       expr.mark_for_strip ();
     852            0 :       return;
     853              :     }
     854              : 
     855              :   /* strip test based on inner attrs - spec says these are inner
     856              :    * attributes, not outer attributes of inner expr */
     857         2617 :   expand_cfg_attrs (expr.get_inner_attrs ());
     858         2617 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     859              :     {
     860            0 :       expr.mark_for_strip ();
     861            0 :       return;
     862              :     }
     863              : 
     864              :   /* apparently outer attributes are allowed in "elements of tuple
     865              :    * expressions" according to spec */
     866         2617 :   maybe_strip_pointer_allow_strip (expr.get_tuple_elems ());
     867              : }
     868              : void
     869         5616 : CfgStrip::visit (AST::TupleIndexExpr &expr)
     870              : {
     871              :   // initial strip test based on outer attrs
     872         5616 :   expand_cfg_attrs (expr.get_outer_attrs ());
     873         5616 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     874              :     {
     875            0 :       expr.mark_for_strip ();
     876            0 :       return;
     877              :     }
     878              : 
     879         5616 :   AST::DefaultASTVisitor::visit (expr);
     880              :   /* wouldn't strip this directly (as outer attrs should be
     881              :    * associated with this level), but any sub-expressions would be
     882              :    * stripped. Thus, no need to erase when strip check called. */
     883         5616 :   auto &tuple_expr = expr.get_tuple_expr ();
     884         5616 :   if (tuple_expr.is_marked_for_strip ())
     885            0 :     rust_error_at (tuple_expr.get_locus (),
     886              :                    "cannot strip expression in this position - outer "
     887              :                    "attributes not allowed");
     888              : }
     889              : 
     890              : void
     891          328 : CfgStrip::visit (AST::StructExprStruct &expr)
     892              : {
     893              :   // initial strip test based on outer attrs
     894          328 :   expand_cfg_attrs (expr.get_outer_attrs ());
     895          328 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     896              :     {
     897            0 :       expr.mark_for_strip ();
     898            0 :       return;
     899              :     }
     900              : 
     901              :   /* strip test based on inner attrs - spec says these are inner
     902              :    * attributes, not outer attributes of inner expr */
     903          328 :   expand_cfg_attrs (expr.get_inner_attrs ());
     904          328 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     905              :     {
     906            0 :       expr.mark_for_strip ();
     907            0 :       return;
     908              :     }
     909              : 
     910              :   // strip sub-exprs of path
     911          328 :   auto &struct_name = expr.get_struct_name ();
     912          328 :   visit (struct_name);
     913          328 :   if (struct_name.is_marked_for_strip ())
     914            0 :     rust_error_at (struct_name.get_locus (),
     915              :                    "cannot strip path in this position");
     916              : }
     917              : 
     918              : void
     919         9451 : CfgStrip::visit (AST::StructExprFieldIdentifierValue &field)
     920              : {
     921              :   /* as no attrs possible (at moment, at least), only sub-expression
     922              :    * stripping is possible */
     923         9451 :   AST::DefaultASTVisitor::visit (field);
     924              : 
     925         9451 :   auto &value = field.get_value ();
     926         9451 :   if (value.is_marked_for_strip ())
     927            0 :     rust_error_at (value.get_locus (),
     928              :                    "cannot strip expression in this position - outer "
     929              :                    "attributes not allowed");
     930         9451 : }
     931              : void
     932          176 : CfgStrip::visit (AST::StructExprFieldIndexValue &field)
     933              : {
     934              :   /* as no attrs possible (at moment, at least), only sub-expression
     935              :    * stripping is possible */
     936          176 :   AST::DefaultASTVisitor::visit (field);
     937              : 
     938          176 :   auto &value = field.get_value ();
     939          176 :   if (value.is_marked_for_strip ())
     940            0 :     rust_error_at (value.get_locus (),
     941              :                    "cannot strip expression in this position - outer "
     942              :                    "attributes not allowed");
     943          176 : }
     944              : void
     945         5764 : CfgStrip::visit (AST::StructExprStructFields &expr)
     946              : {
     947              :   // initial strip test based on outer attrs
     948         5764 :   expand_cfg_attrs (expr.get_outer_attrs ());
     949         5764 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     950              :     {
     951            0 :       expr.mark_for_strip ();
     952            0 :       return;
     953              :     }
     954              : 
     955              :   /* strip test based on inner attrs - spec says these are inner
     956              :    * attributes, not outer attributes of inner expr */
     957         5764 :   expand_cfg_attrs (expr.get_inner_attrs ());
     958         5764 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     959              :     {
     960            0 :       expr.mark_for_strip ();
     961            0 :       return;
     962              :     }
     963              : 
     964              :   // strip sub-exprs of path
     965         5764 :   auto &struct_name = expr.get_struct_name ();
     966         5764 :   visit (struct_name);
     967         5764 :   if (struct_name.is_marked_for_strip ())
     968            0 :     rust_error_at (struct_name.get_locus (),
     969              :                    "cannot strip path in this position");
     970              : 
     971              :   /* spec does not specify whether expressions are allowed to be
     972              :    * stripped at top level of struct fields, but I wouldn't think
     973              :    * that they would be, so operating under the assumption that only
     974              :    * sub-expressions can be stripped. */
     975         5764 :   AST::DefaultASTVisitor::visit (expr);
     976              : 
     977              :   /* struct base presumably can't be stripped, as the '..' is before
     978              :    * the expression. as such, can only strip sub-expressions. */
     979         5764 :   if (expr.has_struct_base ())
     980              :     {
     981          252 :       auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
     982          252 :       base_struct_expr.accept_vis (*this);
     983          252 :       if (base_struct_expr.is_marked_for_strip ())
     984            0 :         rust_error_at (base_struct_expr.get_locus (),
     985              :                        "cannot strip expression in this position - outer "
     986              :                        "attributes not allowed");
     987              :     }
     988              : 
     989         5764 :   maybe_strip_struct_expr_fields (expr.get_fields ());
     990              : }
     991              : 
     992              : void
     993            0 : CfgStrip::visit (AST::StructExprStructBase &expr)
     994              : {
     995              :   // initial strip test based on outer attrs
     996            0 :   expand_cfg_attrs (expr.get_outer_attrs ());
     997            0 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     998              :     {
     999            0 :       expr.mark_for_strip ();
    1000            0 :       return;
    1001              :     }
    1002              : 
    1003              :   /* strip test based on inner attrs - spec says these are inner
    1004              :    * attributes, not outer attributes of inner expr */
    1005            0 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1006            0 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1007              :     {
    1008            0 :       expr.mark_for_strip ();
    1009            0 :       return;
    1010              :     }
    1011              : 
    1012              :   // strip sub-exprs of path
    1013            0 :   auto &struct_name = expr.get_struct_name ();
    1014            0 :   visit (struct_name);
    1015            0 :   if (struct_name.is_marked_for_strip ())
    1016            0 :     rust_error_at (struct_name.get_locus (),
    1017              :                    "cannot strip path in this position");
    1018              : 
    1019              :   /* struct base presumably can't be stripped, as the '..' is before
    1020              :    * the expression. as such, can only strip sub-expressions. */
    1021            0 :   rust_assert (!expr.get_struct_base ().is_invalid ());
    1022            0 :   auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
    1023            0 :   base_struct_expr.accept_vis (*this);
    1024            0 :   if (base_struct_expr.is_marked_for_strip ())
    1025            0 :     rust_error_at (base_struct_expr.get_locus (),
    1026              :                    "cannot strip expression in this position - outer "
    1027              :                    "attributes not allowed");
    1028              : }
    1029              : void
    1030        68533 : CfgStrip::visit (AST::CallExpr &expr)
    1031              : {
    1032              :   // initial strip test based on outer attrs
    1033        68533 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1034        68533 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1035              :     {
    1036            0 :       expr.mark_for_strip ();
    1037            0 :       return;
    1038              :     }
    1039              : 
    1040              :   /* should not be outer attrs on "function" expression - outer attrs
    1041              :    * should be associated with call expr as a whole. only sub-expr
    1042              :    * expansion is possible. */
    1043        68533 :   AST::DefaultASTVisitor::visit (expr);
    1044              : 
    1045        68533 :   auto &function = expr.get_function_expr ();
    1046        68533 :   if (function.is_marked_for_strip ())
    1047            0 :     rust_error_at (function.get_locus (),
    1048              :                    "cannot strip expression in this position - outer "
    1049              :                    "attributes not allowed");
    1050              : 
    1051              :   /* spec says outer attributes are specifically allowed for elements
    1052              :    * of call expressions, so full stripping possible */
    1053              :   // FIXME: Arthur: Figure out how to refactor this - This is similar to
    1054              :   // expanding items in the crate or stmts in blocks
    1055        68533 :   maybe_strip_pointer_allow_strip (expr.get_params ());
    1056              : }
    1057              : void
    1058        20153 : CfgStrip::visit (AST::MethodCallExpr &expr)
    1059              : {
    1060              :   // initial strip test based on outer attrs
    1061        20153 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1062        20153 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1063              :     {
    1064            0 :       expr.mark_for_strip ();
    1065            0 :       return;
    1066              :     }
    1067              : 
    1068              :   /* should not be outer attrs on "receiver" expression - outer attrs
    1069              :    * should be associated with call expr as a whole. only sub-expr
    1070              :    * expansion is possible. */
    1071        20153 :   AST::DefaultASTVisitor::visit (expr);
    1072              : 
    1073        20153 :   auto &receiver = expr.get_receiver_expr ();
    1074        20153 :   if (receiver.is_marked_for_strip ())
    1075            0 :     rust_error_at (receiver.get_locus (),
    1076              :                    "cannot strip expression in this position - outer "
    1077              :                    "attributes not allowed");
    1078              : 
    1079        20153 :   auto &method_name = expr.get_method_name ();
    1080        20153 :   if (method_name.has_generic_args ())
    1081           88 :     maybe_strip_generic_args (method_name.get_generic_args ());
    1082              : 
    1083              :   /* spec says outer attributes are specifically allowed for elements
    1084              :    * of method call expressions, so full stripping possible */
    1085        20153 :   maybe_strip_pointer_allow_strip (expr.get_params ());
    1086              : }
    1087              : void
    1088        39961 : CfgStrip::visit (AST::FieldAccessExpr &expr)
    1089              : {
    1090              :   // initial strip test based on outer attrs
    1091        39961 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1092        39961 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1093              :     {
    1094            0 :       expr.mark_for_strip ();
    1095            0 :       return;
    1096              :     }
    1097              : 
    1098              :   /* should not be outer attrs on "receiver" expression - outer attrs
    1099              :    * should be associated with field expr as a whole. only sub-expr
    1100              :    * expansion is possible. */
    1101        39961 :   AST::DefaultASTVisitor::visit (expr);
    1102              : 
    1103        39961 :   auto &receiver = expr.get_receiver_expr ();
    1104        39961 :   if (receiver.is_marked_for_strip ())
    1105            0 :     rust_error_at (receiver.get_locus (),
    1106              :                    "cannot strip expression in this position - outer "
    1107              :                    "attributes not allowed");
    1108              : }
    1109              : void
    1110          130 : CfgStrip::visit (AST::ClosureExprInner &expr)
    1111              : {
    1112              :   // initial strip test based on outer attrs
    1113          130 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1114          130 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1115              :     {
    1116            0 :       expr.mark_for_strip ();
    1117            0 :       return;
    1118              :     }
    1119              : 
    1120              :   /* strip closure parameters if required - this is specifically
    1121              :    * allowed by spec */
    1122          130 :   maybe_strip_closure_params (expr.get_params ());
    1123              : 
    1124          130 :   AST::DefaultASTVisitor::visit (expr);
    1125              : 
    1126              :   // can't strip expression itself, but can strip sub-expressions
    1127          130 :   auto &definition_expr = expr.get_definition_expr ();
    1128          130 :   if (definition_expr.is_marked_for_strip ())
    1129            0 :     rust_error_at (definition_expr.get_locus (),
    1130              :                    "cannot strip expression in this position - outer "
    1131              :                    "attributes not allowed");
    1132              : }
    1133              : 
    1134              : void
    1135        90409 : CfgStrip::visit (AST::BlockExpr &expr)
    1136              : {
    1137              :   // initial strip test based on outer attrs
    1138        90409 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1139        90409 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1140              :     {
    1141           54 :       expr.mark_for_strip ();
    1142           54 :       return;
    1143              :     }
    1144              : 
    1145              :   /* strip test based on inner attrs - spec says there are inner
    1146              :    * attributes, not just outer attributes of inner stmts */
    1147        90355 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1148        90355 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1149              :     {
    1150            0 :       expr.mark_for_strip ();
    1151            0 :       return;
    1152              :     }
    1153              : 
    1154        90355 :   maybe_strip_pointer_allow_strip (expr.get_statements ());
    1155              : 
    1156        90355 :   AST::DefaultASTVisitor::visit (expr);
    1157              : 
    1158              :   // strip tail expression if exists - can actually fully remove it
    1159        90355 :   if (expr.has_tail_expr ())
    1160              :     {
    1161        70808 :       auto &tail_expr = expr.get_tail_expr ();
    1162              : 
    1163        70808 :       if (tail_expr.is_marked_for_strip ())
    1164           57 :         expr.strip_tail_expr ();
    1165              :     }
    1166              : }
    1167              : 
    1168              : void
    1169          120 : CfgStrip::visit (AST::ClosureExprInnerTyped &expr)
    1170              : {
    1171              :   // initial strip test based on outer attrs
    1172          120 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1173          120 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1174              :     {
    1175            0 :       expr.mark_for_strip ();
    1176            0 :       return;
    1177              :     }
    1178              : 
    1179              :   /* strip closure parameters if required - this is specifically
    1180              :    * allowed by spec */
    1181          120 :   maybe_strip_closure_params (expr.get_params ());
    1182              : 
    1183          120 :   AST::DefaultASTVisitor::visit (expr);
    1184              : 
    1185              :   // can't strip return type, but can strip sub-types
    1186          120 :   auto &type = expr.get_return_type ();
    1187              : 
    1188          120 :   if (type.is_marked_for_strip ())
    1189            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1190              : 
    1191              :   // can't strip expression itself, but can strip sub-expressions
    1192          120 :   auto &definition_block = expr.get_definition_expr ();
    1193          120 :   definition_block.accept_vis (*this);
    1194          120 :   if (definition_block.is_marked_for_strip ())
    1195            0 :     rust_error_at (definition_block.get_locus (),
    1196              :                    "cannot strip block expression in this position - outer "
    1197              :                    "attributes not allowed");
    1198              : }
    1199              : void
    1200          154 : CfgStrip::visit (AST::ContinueExpr &expr)
    1201              : {
    1202              :   // initial strip test based on outer attrs
    1203          154 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1204          154 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1205              :     {
    1206            0 :       expr.mark_for_strip ();
    1207            0 :       return;
    1208              :     }
    1209              : }
    1210              : void
    1211          628 : CfgStrip::visit (AST::BreakExpr &expr)
    1212              : {
    1213              :   // initial strip test based on outer attrs
    1214          628 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1215          628 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1216              :     {
    1217            0 :       expr.mark_for_strip ();
    1218            0 :       return;
    1219              :     }
    1220          628 :   AST::DefaultASTVisitor::visit (expr);
    1221              : 
    1222              :   /* spec does not say that you can have outer attributes on
    1223              :    * expression, so assuming you can't. stripping for sub-expressions
    1224              :    * is the only thing that can be done */
    1225          628 :   if (expr.has_break_expr ())
    1226              :     {
    1227          248 :       auto &break_expr = expr.get_break_expr_unchecked ();
    1228              : 
    1229          248 :       if (break_expr.is_marked_for_strip ())
    1230            0 :         rust_error_at (break_expr.get_locus (),
    1231              :                        "cannot strip expression in this position - outer "
    1232              :                        "attributes not allowed");
    1233              :     }
    1234              : }
    1235              : void
    1236          356 : CfgStrip::visit (AST::RangeFromToExpr &expr)
    1237              : {
    1238              :   /* outer attributes never allowed before these. while cannot strip
    1239              :    * two direct descendant expressions, can strip ones below that */
    1240          356 :   AST::DefaultASTVisitor::visit (expr);
    1241              : 
    1242              :   // ensure that they are not marked for strip
    1243          356 :   if (expr.get_from_expr ().is_marked_for_strip ())
    1244            0 :     rust_error_at (expr.get_from_expr ().get_locus (),
    1245              :                    "cannot strip expression in this position - outer "
    1246              :                    "attributes are never allowed "
    1247              :                    "before range exprs");
    1248          356 :   if (expr.get_to_expr ().is_marked_for_strip ())
    1249            0 :     rust_error_at (expr.get_to_expr ().get_locus (),
    1250              :                    "cannot strip expression in this position - outer "
    1251              :                    "attributes not allowed");
    1252          356 : }
    1253              : void
    1254           28 : CfgStrip::visit (AST::RangeFromExpr &expr)
    1255              : {
    1256              :   /* outer attributes never allowed before these. while cannot strip
    1257              :    * direct descendant expression, can strip ones below that */
    1258              : 
    1259           28 :   AST::DefaultASTVisitor::visit (expr);
    1260              :   /* should have no possibility for outer attrs as would be parsed
    1261              :    * with outer expr */
    1262           28 :   auto &from_expr = expr.get_from_expr ();
    1263           28 :   if (from_expr.is_marked_for_strip ())
    1264            0 :     rust_error_at (from_expr.get_locus (),
    1265              :                    "cannot strip expression in this position - outer "
    1266              :                    "attributes are never allowed before range exprs");
    1267           28 : }
    1268              : void
    1269           28 : CfgStrip::visit (AST::RangeToExpr &expr)
    1270              : {
    1271              :   /* outer attributes never allowed before these. while cannot strip
    1272              :    * direct descendant expression, can strip ones below that */
    1273              : 
    1274           28 :   AST::DefaultASTVisitor::visit (expr);
    1275              :   /* should syntactically not have outer attributes, though this may
    1276              :    * not have worked in practice */
    1277           28 :   auto &to_expr = expr.get_to_expr ();
    1278           28 :   if (to_expr.is_marked_for_strip ())
    1279            0 :     rust_error_at (to_expr.get_locus (),
    1280              :                    "cannot strip expression in this position - outer "
    1281              :                    "attributes not allowed");
    1282           28 : }
    1283              : 
    1284              : void
    1285           28 : CfgStrip::visit (AST::RangeFromToInclExpr &expr)
    1286              : {
    1287              :   /* outer attributes never allowed before these. while cannot strip
    1288              :    * two direct descendant expressions, can strip ones below that */
    1289              : 
    1290           28 :   AST::DefaultASTVisitor::visit (expr);
    1291              : 
    1292              :   // ensure that they are not marked for strip
    1293           28 :   if (expr.get_from_expr ().is_marked_for_strip ())
    1294            0 :     rust_error_at (expr.get_from_expr ().get_locus (),
    1295              :                    "cannot strip expression in this position - outer "
    1296              :                    "attributes are never allowed "
    1297              :                    "before range exprs");
    1298           28 :   if (expr.get_to_expr ().is_marked_for_strip ())
    1299            0 :     rust_error_at (expr.get_to_expr ().get_locus (),
    1300              :                    "cannot strip expression in this position - outer "
    1301              :                    "attributes not allowed");
    1302           28 : }
    1303              : void
    1304            0 : CfgStrip::visit (AST::RangeToInclExpr &expr)
    1305              : {
    1306              :   /* outer attributes never allowed before these. while cannot strip
    1307              :    * direct descendant expression, can strip ones below that */
    1308              : 
    1309            0 :   AST::DefaultASTVisitor::visit (expr);
    1310              :   /* should syntactically not have outer attributes, though this may
    1311              :    * not have worked in practice */
    1312            0 :   auto &to_expr = expr.get_to_expr ();
    1313            0 :   if (to_expr.is_marked_for_strip ())
    1314            0 :     rust_error_at (to_expr.get_locus (),
    1315              :                    "cannot strip expression in this position - outer "
    1316              :                    "attributes not allowed");
    1317            0 : }
    1318              : void
    1319         3108 : CfgStrip::visit (AST::ReturnExpr &expr)
    1320              : {
    1321              :   // initial strip test based on outer attrs
    1322         3108 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1323         3108 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1324              :     {
    1325            0 :       expr.mark_for_strip ();
    1326            0 :       return;
    1327              :     }
    1328              : 
    1329         3108 :   AST::DefaultASTVisitor::visit (expr);
    1330              : 
    1331              :   /* spec does not say that you can have outer attributes on
    1332              :    * expression, so assuming you can't. stripping for sub-expressions
    1333              :    * is the only thing that can be done */
    1334         3108 :   if (expr.has_returned_expr ())
    1335              :     {
    1336         2750 :       auto &returned_expr = expr.get_returned_expr ();
    1337         2750 :       if (returned_expr.is_marked_for_strip ())
    1338            0 :         rust_error_at (returned_expr.get_locus (),
    1339              :                        "cannot strip expression in this position - outer "
    1340              :                        "attributes not allowed");
    1341              :     }
    1342              :   /* TODO: conceptually, you would maybe be able to remove a returned
    1343              :    * expr - e.g. if you had conditional compilation returning void or
    1344              :    * returning a type. On the other hand, I think that function
    1345              :    * return type cannot be conditionally compiled, so I assumed you
    1346              :    * can't do this either. */
    1347              : }
    1348              : void
    1349        16492 : CfgStrip::visit (AST::UnsafeBlockExpr &expr)
    1350              : {
    1351              :   // initial strip test based on outer attrs
    1352        16492 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1353        16492 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1354              :     {
    1355            7 :       expr.mark_for_strip ();
    1356            7 :       return;
    1357              :     }
    1358              : 
    1359        16485 :   AST::DefaultASTVisitor::visit (expr);
    1360              : 
    1361              :   // can't strip block itself, but can strip sub-expressions
    1362        16485 :   auto &block_expr = expr.get_block_expr ();
    1363        16485 :   if (block_expr.is_marked_for_strip ())
    1364            0 :     rust_error_at (block_expr.get_locus (),
    1365              :                    "cannot strip block expression in this position - outer "
    1366              :                    "attributes not allowed");
    1367              : }
    1368              : void
    1369          330 : CfgStrip::visit (AST::LoopExpr &expr)
    1370              : {
    1371              :   // initial strip test based on outer attrs
    1372          330 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1373          330 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1374              :     {
    1375            0 :       expr.mark_for_strip ();
    1376            0 :       return;
    1377              :     }
    1378              : 
    1379          330 :   AST::DefaultASTVisitor::visit (expr);
    1380              : 
    1381              :   // can't strip block itself, but can strip sub-expressions
    1382          330 :   auto &loop_block = expr.get_loop_block ();
    1383          330 :   if (loop_block.is_marked_for_strip ())
    1384            0 :     rust_error_at (loop_block.get_locus (),
    1385              :                    "cannot strip block expression in this position - outer "
    1386              :                    "attributes not allowed");
    1387              : }
    1388              : void
    1389          470 : CfgStrip::visit (AST::WhileLoopExpr &expr)
    1390              : {
    1391              :   // initial strip test based on outer attrs
    1392          470 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1393          470 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1394              :     {
    1395            0 :       expr.mark_for_strip ();
    1396            0 :       return;
    1397              :     }
    1398              : 
    1399          470 :   AST::DefaultASTVisitor::visit (expr);
    1400              :   // can't strip predicate expr itself, but can strip sub-expressions
    1401          470 :   auto &predicate_expr = expr.get_predicate_expr ();
    1402          470 :   if (predicate_expr.is_marked_for_strip ())
    1403            0 :     rust_error_at (predicate_expr.get_locus (),
    1404              :                    "cannot strip expression in this position - outer "
    1405              :                    "attributes not allowed");
    1406              : 
    1407              :   // can't strip block itself, but can strip sub-expressions
    1408          470 :   auto &loop_block = expr.get_loop_block ();
    1409          470 :   if (loop_block.is_marked_for_strip ())
    1410            0 :     rust_error_at (loop_block.get_locus (),
    1411              :                    "cannot strip block expression in this position - outer "
    1412              :                    "attributes not allowed");
    1413              : }
    1414              : void
    1415            4 : CfgStrip::visit (AST::WhileLetLoopExpr &expr)
    1416              : {
    1417              :   // initial strip test based on outer attrs
    1418            4 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1419            4 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1420              :     {
    1421            0 :       expr.mark_for_strip ();
    1422            0 :       return;
    1423              :     }
    1424              : 
    1425            4 :   AST::DefaultASTVisitor::visit (expr);
    1426              : 
    1427            4 :   if (expr.get_pattern ()->is_marked_for_strip ())
    1428            0 :     rust_error_at (expr.get_pattern ()->get_locus (),
    1429              :                    "cannot strip pattern in this position");
    1430              : 
    1431              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1432            4 :   auto &scrutinee_expr = expr.get_scrutinee_expr ();
    1433            4 :   if (scrutinee_expr.is_marked_for_strip ())
    1434            0 :     rust_error_at (scrutinee_expr.get_locus (),
    1435              :                    "cannot strip expression in this position - outer "
    1436              :                    "attributes not allowed");
    1437              : 
    1438              :   // can't strip block itself, but can strip sub-expressions
    1439            4 :   auto &loop_block = expr.get_loop_block ();
    1440            4 :   if (loop_block.is_marked_for_strip ())
    1441            0 :     rust_error_at (loop_block.get_locus (),
    1442              :                    "cannot strip block expression in this position - outer "
    1443              :                    "attributes not allowed");
    1444              : }
    1445              : void
    1446          120 : CfgStrip::visit (AST::ForLoopExpr &expr)
    1447              : {
    1448              :   // initial strip test based on outer attrs
    1449          120 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1450          120 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1451              :     {
    1452            0 :       expr.mark_for_strip ();
    1453            0 :       return;
    1454              :     }
    1455              : 
    1456          120 :   AST::DefaultASTVisitor::visit (expr);
    1457              :   // strip sub-patterns of pattern
    1458          120 :   auto &pattern = expr.get_pattern ();
    1459          120 :   if (pattern.is_marked_for_strip ())
    1460            0 :     rust_error_at (pattern.get_locus (),
    1461              :                    "cannot strip pattern in this position");
    1462              : 
    1463              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1464          120 :   auto &iterator_expr = expr.get_iterator_expr ();
    1465          120 :   if (iterator_expr.is_marked_for_strip ())
    1466            0 :     rust_error_at (iterator_expr.get_locus (),
    1467              :                    "cannot strip expression in this position - outer "
    1468              :                    "attributes not allowed");
    1469              : 
    1470              :   // can't strip block itself, but can strip sub-expressions
    1471          120 :   auto &loop_block = expr.get_loop_block ();
    1472          120 :   if (loop_block.is_marked_for_strip ())
    1473            0 :     rust_error_at (loop_block.get_locus (),
    1474              :                    "cannot strip block expression in this position - outer "
    1475              :                    "attributes not allowed");
    1476              : }
    1477              : void
    1478         8301 : CfgStrip::visit (AST::IfExpr &expr)
    1479              : {
    1480              :   // rust playground test shows that IfExpr does support outer attrs, at least
    1481              :   // when used as statement
    1482              : 
    1483              :   // initial strip test based on outer attrs
    1484         8301 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1485         8301 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1486              :     {
    1487            0 :       expr.mark_for_strip ();
    1488            0 :       return;
    1489              :     }
    1490              : 
    1491         8301 :   AST::DefaultASTVisitor::visit (expr);
    1492              : 
    1493              :   // can't strip condition expr itself, but can strip sub-expressions
    1494         8301 :   auto &condition_expr = expr.get_condition_expr ();
    1495         8301 :   if (condition_expr.is_marked_for_strip ())
    1496            0 :     rust_error_at (condition_expr.get_locus (),
    1497              :                    "cannot strip expression in this position - outer "
    1498              :                    "attributes not allowed");
    1499              : 
    1500              :   // can't strip if block itself, but can strip sub-expressions
    1501         8301 :   auto &if_block = expr.get_if_block ();
    1502         8301 :   if (if_block.is_marked_for_strip ())
    1503            0 :     rust_error_at (if_block.get_locus (),
    1504              :                    "cannot strip block expression in this position - outer "
    1505              :                    "attributes not allowed");
    1506              : }
    1507              : 
    1508              : void
    1509         5924 : CfgStrip::visit (AST::IfExprConseqElse &expr)
    1510              : {
    1511              :   // initial strip test based on outer attrs
    1512         5924 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1513         5924 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1514              :     {
    1515            0 :       expr.mark_for_strip ();
    1516            0 :       return;
    1517              :     }
    1518              : 
    1519         5924 :   AST::DefaultASTVisitor::visit (expr);
    1520              : 
    1521              :   // can't strip condition expr itself, but can strip sub-expressions
    1522         5924 :   auto &condition_expr = expr.get_condition_expr ();
    1523         5924 :   if (condition_expr.is_marked_for_strip ())
    1524            0 :     rust_error_at (condition_expr.get_locus (),
    1525              :                    "cannot strip expression in this position - outer "
    1526              :                    "attributes not allowed");
    1527              : 
    1528              :   // can't strip if block itself, but can strip sub-expressions
    1529         5924 :   auto &if_block = expr.get_if_block ();
    1530         5924 :   if (if_block.is_marked_for_strip ())
    1531            0 :     rust_error_at (if_block.get_locus (),
    1532              :                    "cannot strip block expression in this position - outer "
    1533              :                    "attributes not allowed");
    1534              : 
    1535              :   // can't strip else block itself, but can strip sub-expressions
    1536         5924 :   auto &else_block = expr.get_else_block ();
    1537         5924 :   if (else_block.is_marked_for_strip ())
    1538            0 :     rust_error_at (else_block.get_locus (),
    1539              :                    "cannot strip block expression in this position - outer "
    1540              :                    "attributes not allowed");
    1541              : }
    1542              : 
    1543              : void
    1544          102 : CfgStrip::visit (AST::IfLetExpr &expr)
    1545              : {
    1546              :   // initial strip test based on outer attrs
    1547          102 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1548          102 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1549              :     {
    1550            0 :       expr.mark_for_strip ();
    1551            0 :       return;
    1552              :     }
    1553              : 
    1554          102 :   AST::DefaultASTVisitor::visit (expr);
    1555              : 
    1556          102 :   if (expr.get_pattern ()->is_marked_for_strip ())
    1557            0 :     rust_error_at (expr.get_pattern ()->get_locus (),
    1558              :                    "cannot strip pattern in this position");
    1559              : 
    1560              :   // can't strip value expr itself, but can strip sub-expressions
    1561          102 :   auto &value_expr = expr.get_value_expr ();
    1562          102 :   if (value_expr.is_marked_for_strip ())
    1563            0 :     rust_error_at (value_expr.get_locus (),
    1564              :                    "cannot strip expression in this position - outer "
    1565              :                    "attributes not allowed");
    1566              : 
    1567              :   // can't strip if block itself, but can strip sub-expressions
    1568          102 :   auto &if_block = expr.get_if_block ();
    1569          102 :   if (if_block.is_marked_for_strip ())
    1570            0 :     rust_error_at (if_block.get_locus (),
    1571              :                    "cannot strip block expression in this position - outer "
    1572              :                    "attributes not allowed");
    1573              : }
    1574              : void
    1575           30 : CfgStrip::visit (AST::IfLetExprConseqElse &expr)
    1576              : {
    1577              :   // initial strip test based on outer attrs
    1578           30 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1579           30 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1580              :     {
    1581            0 :       expr.mark_for_strip ();
    1582            0 :       return;
    1583              :     }
    1584              : 
    1585           30 :   AST::DefaultASTVisitor::visit (expr);
    1586              : 
    1587           30 :   if (expr.get_pattern ()->is_marked_for_strip ())
    1588            0 :     rust_error_at (expr.get_pattern ()->get_locus (),
    1589              :                    "cannot strip pattern in this position");
    1590              : 
    1591              :   // can't strip value expr itself, but can strip sub-expressions
    1592           30 :   auto &value_expr = expr.get_value_expr ();
    1593           30 :   if (value_expr.is_marked_for_strip ())
    1594            0 :     rust_error_at (value_expr.get_locus (),
    1595              :                    "cannot strip expression in this position - outer "
    1596              :                    "attributes not allowed");
    1597              : 
    1598              :   // can't strip if block itself, but can strip sub-expressions
    1599           30 :   auto &if_block = expr.get_if_block ();
    1600           30 :   if (if_block.is_marked_for_strip ())
    1601            0 :     rust_error_at (if_block.get_locus (),
    1602              :                    "cannot strip block expression in this position - outer "
    1603              :                    "attributes not allowed");
    1604              : 
    1605              :   // can't strip else block itself, but can strip sub-expressions
    1606           30 :   auto &else_block = expr.get_else_block ();
    1607           30 :   if (else_block.is_marked_for_strip ())
    1608            0 :     rust_error_at (else_block.get_locus (),
    1609              :                    "cannot strip block expression in this position - outer "
    1610              :                    "attributes not allowed");
    1611              : }
    1612              : void
    1613         4423 : CfgStrip::visit (AST::MatchExpr &expr)
    1614              : {
    1615              :   // initial strip test based on outer attrs
    1616         4423 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1617         4423 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1618              :     {
    1619            0 :       expr.mark_for_strip ();
    1620            0 :       return;
    1621              :     }
    1622              : 
    1623              :   // inner attr strip test
    1624         4423 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1625         4423 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1626              :     {
    1627            0 :       expr.mark_for_strip ();
    1628            0 :       return;
    1629              :     }
    1630              : 
    1631         4423 :   AST::DefaultASTVisitor::visit (expr);
    1632              : 
    1633              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1634         4423 :   auto &scrutinee_expr = expr.get_scrutinee_expr ();
    1635         4423 :   if (scrutinee_expr.is_marked_for_strip ())
    1636            0 :     rust_error_at (scrutinee_expr.get_locus (),
    1637              :                    "cannot strip expression in this position - outer "
    1638              :                    "attributes not allowed");
    1639              : 
    1640              :   // strip match cases
    1641         4423 :   auto &match_cases = expr.get_match_cases ();
    1642        14609 :   for (auto it = match_cases.begin (); it != match_cases.end ();)
    1643              :     {
    1644        10186 :       auto &match_case = *it;
    1645              : 
    1646              :       // strip match case based on outer attributes in match arm
    1647        10186 :       auto &match_arm = match_case.get_arm ();
    1648        10186 :       expand_cfg_attrs (match_arm.get_outer_attrs ());
    1649        10186 :       if (fails_cfg_with_expand (match_arm.get_outer_attrs ()))
    1650              :         {
    1651              :           // strip match case
    1652            0 :           it = match_cases.erase (it);
    1653            0 :           continue;
    1654              :         }
    1655              : 
    1656        10186 :       if (match_arm.get_pattern ()->is_marked_for_strip ())
    1657            0 :         rust_error_at (match_arm.get_pattern ()->get_locus (),
    1658              :                        "cannot strip pattern in this position");
    1659              : 
    1660              :       /* assuming that guard expression cannot be stripped as
    1661              :        * strictly speaking you would have to strip the whole guard to
    1662              :        * make syntactical sense, which you can't do. as such, only
    1663              :        * strip sub-expressions */
    1664        10186 :       if (match_arm.has_match_arm_guard ())
    1665              :         {
    1666            2 :           auto &guard_expr = match_arm.get_guard_expr ();
    1667            2 :           if (guard_expr.is_marked_for_strip ())
    1668            0 :             rust_error_at (guard_expr.get_locus (),
    1669              :                            "cannot strip expression in this position - outer "
    1670              :                            "attributes not allowed");
    1671              :         }
    1672              : 
    1673              :       // strip sub-expressions from match cases
    1674        10186 :       auto &case_expr = match_case.get_expr ();
    1675        10186 :       if (case_expr.is_marked_for_strip ())
    1676            0 :         rust_error_at (case_expr.get_locus (),
    1677              :                        "cannot strip expression in this position - outer "
    1678              :                        "attributes not allowed");
    1679              : 
    1680              :       // increment to next case if haven't continued
    1681        10186 :       ++it;
    1682              :     }
    1683              : }
    1684              : 
    1685              : void
    1686            0 : CfgStrip::visit (AST::AwaitExpr &expr)
    1687              : {
    1688              :   // initial strip test based on outer attrs
    1689            0 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1690            0 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1691              :     {
    1692            0 :       expr.mark_for_strip ();
    1693            0 :       return;
    1694              :     }
    1695              : 
    1696              :   /* can't strip awaited expr itself, but can strip sub-expressions
    1697              :    * - this is because you can't have no expr to await */
    1698            0 :   auto &awaited_expr = expr.get_awaited_expr ();
    1699            0 :   awaited_expr->accept_vis (*this);
    1700            0 :   if (awaited_expr->is_marked_for_strip ())
    1701            0 :     rust_error_at (awaited_expr->get_locus (),
    1702              :                    "cannot strip expression in this position - outer "
    1703              :                    "attributes not allowed");
    1704              : }
    1705              : 
    1706              : void
    1707            0 : CfgStrip::visit (AST::AsyncBlockExpr &expr)
    1708              : {
    1709              :   // initial strip test based on outer attrs
    1710            0 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1711            0 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1712              :     {
    1713            0 :       expr.mark_for_strip ();
    1714            0 :       return;
    1715              :     }
    1716              : 
    1717            0 :   AST::DefaultASTVisitor::visit (expr);
    1718              : 
    1719              :   // can't strip block itself, but can strip sub-expressions
    1720            0 :   auto &block_expr = expr.get_block_expr ();
    1721            0 :   if (block_expr->is_marked_for_strip ())
    1722            0 :     rust_error_at (block_expr->get_locus (),
    1723              :                    "cannot strip block expression in this position - outer "
    1724              :                    "attributes not allowed");
    1725              : }
    1726              : 
    1727              : void
    1728        20023 : CfgStrip::visit (AST::TypeParam &param)
    1729              : {
    1730              :   // outer attributes don't actually do anything, so ignore them
    1731              : 
    1732        20023 :   AST::DefaultASTVisitor::visit (param);
    1733              : 
    1734        20023 :   if (param.has_type () && param.get_type ().is_marked_for_strip ())
    1735            0 :     rust_error_at (param.get_type ().get_locus (),
    1736              :                    "cannot strip type in this position");
    1737        20023 : }
    1738              : 
    1739              : void
    1740         1259 : CfgStrip::visit (AST::TypeBoundWhereClauseItem &item)
    1741              : {
    1742              :   // for lifetimes shouldn't require
    1743         1259 :   AST::DefaultASTVisitor::visit (item);
    1744              : 
    1745         1259 :   auto &type = item.get_type ();
    1746         1259 :   if (type.is_marked_for_strip ())
    1747            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1748         1259 : }
    1749              : 
    1750              : void
    1751         3264 : CfgStrip::visit (AST::Module &module)
    1752              : {
    1753              :   // strip test based on outer attrs
    1754         3264 :   expand_cfg_attrs (module.get_outer_attrs ());
    1755         3264 :   if (fails_cfg_with_expand (module.get_outer_attrs ()))
    1756              :     {
    1757            0 :       module.mark_for_strip ();
    1758            0 :       return;
    1759              :     }
    1760              : 
    1761         3264 :   if (module.get_kind () == AST::Module::UNLOADED)
    1762              :     {
    1763           82 :       module.load_items ();
    1764              :     }
    1765              : 
    1766              :   // strip test based on inner attrs
    1767         3264 :   expand_cfg_attrs (module.get_inner_attrs ());
    1768         3264 :   if (fails_cfg_with_expand (module.get_inner_attrs ()))
    1769              :     {
    1770            0 :       module.mark_for_strip ();
    1771            0 :       return;
    1772              :     }
    1773              : 
    1774              :   // strip items if required
    1775         3264 :   maybe_strip_pointer_allow_strip (module.get_items ());
    1776              : }
    1777              : 
    1778              : void
    1779           51 : CfgStrip::visit (AST::ExternCrate &extern_crate)
    1780              : {
    1781              :   // strip test based on outer attrs
    1782           51 :   expand_cfg_attrs (extern_crate.get_outer_attrs ());
    1783           51 :   if (fails_cfg_with_expand (extern_crate.get_outer_attrs ()))
    1784              :     {
    1785            0 :       extern_crate.mark_for_strip ();
    1786            0 :       return;
    1787              :     }
    1788              : 
    1789           51 :   if (!extern_crate.references_self ())
    1790              :     {
    1791           51 :       Session &session = Session::get_instance ();
    1792           51 :       session.load_extern_crate (extern_crate.get_referenced_crate (),
    1793              :                                  extern_crate.get_locus ());
    1794              :     }
    1795              : }
    1796              : 
    1797              : void
    1798         1851 : CfgStrip::visit (AST::UseDeclaration &use_decl)
    1799              : {
    1800              :   // strip test based on outer attrs
    1801         1851 :   expand_cfg_attrs (use_decl.get_outer_attrs ());
    1802         1851 :   if (fails_cfg_with_expand (use_decl.get_outer_attrs ()))
    1803              :     {
    1804            0 :       use_decl.mark_for_strip ();
    1805            0 :       return;
    1806              :     }
    1807              : }
    1808              : 
    1809              : void
    1810        67612 : CfgStrip::visit (AST::Function &function)
    1811              : {
    1812              :   // initial test based on outer attrs
    1813        67612 :   expand_cfg_attrs (function.get_outer_attrs ());
    1814        67612 :   if (fails_cfg_with_expand (function.get_outer_attrs ()))
    1815              :     {
    1816           31 :       function.mark_for_strip ();
    1817           31 :       return;
    1818              :     }
    1819              : 
    1820        67581 :   AST::DefaultASTVisitor::visit (function);
    1821              : 
    1822              :   /* strip function parameters if required - this is specifically
    1823              :    * allowed by spec */
    1824        67581 :   maybe_strip_function_params (function.get_function_params ());
    1825              : 
    1826        67581 :   if (function.has_return_type ())
    1827              :     {
    1828        53611 :       auto &return_type = function.get_return_type ();
    1829        53611 :       if (return_type.is_marked_for_strip ())
    1830            0 :         rust_error_at (return_type.get_locus (),
    1831              :                        "cannot strip type in this position");
    1832              :     }
    1833              : 
    1834              :   /* body should always exist - if error state, should have returned
    1835              :    * before now */
    1836              :   // can't strip block itself, but can strip sub-expressions
    1837        67581 :   if (function.has_body ())
    1838              :     {
    1839        53500 :       auto &block_expr = function.get_definition ();
    1840        53500 :       if (block_expr.value ()->is_marked_for_strip ())
    1841            0 :         rust_error_at (block_expr.value ()->get_locus (),
    1842              :                        "cannot strip block expression in this position - outer "
    1843              :                        "attributes not allowed");
    1844              :     }
    1845              : }
    1846              : 
    1847              : void
    1848         6244 : CfgStrip::visit (AST::TypeAlias &type_alias)
    1849              : {
    1850              :   // initial test based on outer attrs
    1851         6244 :   expand_cfg_attrs (type_alias.get_outer_attrs ());
    1852         6244 :   if (fails_cfg_with_expand (type_alias.get_outer_attrs ()))
    1853              :     {
    1854            0 :       type_alias.mark_for_strip ();
    1855            0 :       return;
    1856              :     }
    1857              : 
    1858         6244 :   AST::DefaultASTVisitor::visit (type_alias);
    1859              : 
    1860         6244 :   auto &type = type_alias.get_type_aliased ();
    1861         6244 :   if (type.is_marked_for_strip ())
    1862            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1863              : }
    1864              : 
    1865              : void
    1866         4081 : CfgStrip::visit (AST::StructStruct &struct_item)
    1867              : {
    1868              :   // initial test based on outer attrs
    1869         4081 :   expand_cfg_attrs (struct_item.get_outer_attrs ());
    1870         4081 :   if (fails_cfg_with_expand (struct_item.get_outer_attrs ()))
    1871              :     {
    1872            2 :       struct_item.mark_for_strip ();
    1873            2 :       return;
    1874              :     }
    1875              : 
    1876         4079 :   AST::DefaultASTVisitor::visit (struct_item);
    1877              : 
    1878              :   /* strip struct fields if required - this is presumably
    1879              :    * allowed by spec */
    1880         4079 :   maybe_strip_struct_fields (struct_item.get_fields ());
    1881              : }
    1882              : void
    1883         2454 : CfgStrip::visit (AST::TupleStruct &tuple_struct)
    1884              : {
    1885              :   // initial test based on outer attrs
    1886         2454 :   expand_cfg_attrs (tuple_struct.get_outer_attrs ());
    1887         2454 :   if (fails_cfg_with_expand (tuple_struct.get_outer_attrs ()))
    1888              :     {
    1889            0 :       tuple_struct.mark_for_strip ();
    1890            0 :       return;
    1891              :     }
    1892              : 
    1893         2454 :   AST::DefaultASTVisitor::visit (tuple_struct);
    1894              : 
    1895              :   /* strip struct fields if required - this is presumably
    1896              :    * allowed by spec */
    1897         2454 :   maybe_strip_tuple_fields (tuple_struct.get_fields ());
    1898              : }
    1899              : void
    1900         2112 : CfgStrip::visit (AST::EnumItem &item)
    1901              : {
    1902              :   // initial test based on outer attrs
    1903         2112 :   expand_cfg_attrs (item.get_outer_attrs ());
    1904         2112 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1905              :     {
    1906            0 :       item.mark_for_strip ();
    1907            0 :       return;
    1908              :     }
    1909              : }
    1910              : 
    1911              : void
    1912         2250 : CfgStrip::visit (AST::EnumItemTuple &item)
    1913              : {
    1914              :   // initial test based on outer attrs
    1915         2250 :   expand_cfg_attrs (item.get_outer_attrs ());
    1916         2250 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1917              :     {
    1918            0 :       item.mark_for_strip ();
    1919            0 :       return;
    1920              :     }
    1921              : 
    1922              :   /* strip item fields if required - this is presumably
    1923              :    * allowed by spec */
    1924         2250 :   maybe_strip_tuple_fields (item.get_tuple_fields ());
    1925              : }
    1926              : 
    1927              : void
    1928          440 : CfgStrip::visit (AST::EnumItemStruct &item)
    1929              : {
    1930              :   // initial test based on outer attrs
    1931          440 :   expand_cfg_attrs (item.get_outer_attrs ());
    1932          440 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1933              :     {
    1934            0 :       item.mark_for_strip ();
    1935            0 :       return;
    1936              :     }
    1937              : 
    1938              :   /* strip item fields if required - this is presumably
    1939              :    * allowed by spec */
    1940          440 :   maybe_strip_struct_fields (item.get_struct_fields ());
    1941              : }
    1942              : 
    1943              : void
    1944         1378 : CfgStrip::visit (AST::EnumItemDiscriminant &item)
    1945              : {
    1946              :   // initial test based on outer attrs
    1947         1378 :   expand_cfg_attrs (item.get_outer_attrs ());
    1948         1378 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1949              :     {
    1950            0 :       item.mark_for_strip ();
    1951            0 :       return;
    1952              :     }
    1953              : 
    1954         1378 :   AST::DefaultASTVisitor::visit (item);
    1955              :   /* strip any internal sub-expressions - expression itself isn't
    1956              :    * allowed to have external attributes in this position so can't be
    1957              :    * stripped. */
    1958         1378 :   auto &expr = item.get_expr ();
    1959         1378 :   if (expr.is_marked_for_strip ())
    1960            0 :     rust_error_at (expr.get_locus (),
    1961              :                    "cannot strip expression in this position - outer "
    1962              :                    "attributes not allowed");
    1963              : }
    1964              : void
    1965         1328 : CfgStrip::visit (AST::Enum &enum_item)
    1966              : {
    1967              :   // initial test based on outer attrs
    1968         1328 :   expand_cfg_attrs (enum_item.get_outer_attrs ());
    1969         1328 :   if (fails_cfg_with_expand (enum_item.get_outer_attrs ()))
    1970              :     {
    1971            0 :       enum_item.mark_for_strip ();
    1972            0 :       return;
    1973              :     }
    1974              : 
    1975         1328 :   AST::DefaultASTVisitor::visit (enum_item);
    1976              : 
    1977              :   /* strip enum fields if required - this is presumably
    1978              :    * allowed by spec */
    1979         1328 :   maybe_strip_pointer_allow_strip (enum_item.get_variants ());
    1980              : }
    1981              : void
    1982          230 : CfgStrip::visit (AST::Union &union_item)
    1983              : {
    1984              :   // initial test based on outer attrs
    1985          230 :   expand_cfg_attrs (union_item.get_outer_attrs ());
    1986          230 :   if (fails_cfg_with_expand (union_item.get_outer_attrs ()))
    1987              :     {
    1988            0 :       union_item.mark_for_strip ();
    1989            0 :       return;
    1990              :     }
    1991              : 
    1992          230 :   AST::DefaultASTVisitor::visit (union_item);
    1993              : 
    1994              :   /* strip union fields if required - this is presumably
    1995              :    * allowed by spec */
    1996          230 :   maybe_strip_struct_fields (union_item.get_variants ());
    1997              : }
    1998              : void
    1999         1507 : CfgStrip::visit (AST::ConstantItem &const_item)
    2000              : {
    2001              :   // initial test based on outer attrs
    2002         1507 :   expand_cfg_attrs (const_item.get_outer_attrs ());
    2003         1507 :   if (fails_cfg_with_expand (const_item.get_outer_attrs ()))
    2004              :     {
    2005            0 :       const_item.mark_for_strip ();
    2006            0 :       return;
    2007              :     }
    2008              : 
    2009         1507 :   AST::DefaultASTVisitor::visit (const_item);
    2010              : 
    2011              :   // strip any sub-types
    2012         1507 :   auto &type = const_item.get_type ();
    2013         1507 :   if (type.is_marked_for_strip ())
    2014            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2015              : 
    2016              :   /* strip any internal sub-expressions - expression itself isn't
    2017              :    * allowed to have external attributes in this position so can't be
    2018              :    * stripped. */
    2019         1507 :   if (const_item.has_expr ())
    2020              :     {
    2021         1365 :       auto &expr = const_item.get_expr ();
    2022         1365 :       if (expr.is_marked_for_strip ())
    2023            0 :         rust_error_at (expr.get_locus (),
    2024              :                        "cannot strip expression in this position - outer "
    2025              :                        "attributes not allowed");
    2026              :     }
    2027              : }
    2028              : void
    2029          121 : CfgStrip::visit (AST::StaticItem &static_item)
    2030              : {
    2031              :   // initial test based on outer attrs
    2032          121 :   expand_cfg_attrs (static_item.get_outer_attrs ());
    2033          121 :   if (fails_cfg_with_expand (static_item.get_outer_attrs ()))
    2034              :     {
    2035            0 :       static_item.mark_for_strip ();
    2036            0 :       return;
    2037              :     }
    2038              : 
    2039          121 :   AST::DefaultASTVisitor::visit (static_item);
    2040              : 
    2041              :   // strip any sub-types
    2042          121 :   auto &type = static_item.get_type ();
    2043              : 
    2044          121 :   if (type.is_marked_for_strip ())
    2045            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2046              : 
    2047              :   /* strip any internal sub-expressions - expression itself isn't
    2048              :    * allowed to have external attributes in this position so can't be
    2049              :    * stripped. */
    2050          121 :   auto &expr = static_item.get_expr ();
    2051          121 :   if (expr.is_marked_for_strip ())
    2052            0 :     rust_error_at (expr.get_locus (),
    2053              :                    "cannot strip expression in this position - outer "
    2054              :                    "attributes not allowed");
    2055              : }
    2056              : 
    2057              : void
    2058         3686 : CfgStrip::visit (AST::TraitItemType &item)
    2059              : {
    2060              :   // initial test based on outer attrs
    2061         3686 :   expand_cfg_attrs (item.get_outer_attrs ());
    2062         3686 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2063              :     {
    2064            0 :       item.mark_for_strip ();
    2065            0 :       return;
    2066              :     }
    2067              : 
    2068         3686 :   AST::DefaultASTVisitor::visit (item);
    2069              : }
    2070              : 
    2071              : void
    2072         8686 : CfgStrip::visit (AST::Trait &trait)
    2073              : {
    2074              :   // initial strip test based on outer attrs
    2075         8686 :   expand_cfg_attrs (trait.get_outer_attrs ());
    2076         8686 :   if (fails_cfg_with_expand (trait.get_outer_attrs ()))
    2077              :     {
    2078            1 :       trait.mark_for_strip ();
    2079            1 :       return;
    2080              :     }
    2081              : 
    2082              :   // strip test based on inner attrs
    2083         8685 :   expand_cfg_attrs (trait.get_inner_attrs ());
    2084         8685 :   if (fails_cfg_with_expand (trait.get_inner_attrs ()))
    2085              :     {
    2086            0 :       trait.mark_for_strip ();
    2087            0 :       return;
    2088              :     }
    2089              : 
    2090         8685 :   AST::DefaultASTVisitor::visit (trait);
    2091              : 
    2092         8685 :   maybe_strip_pointer_allow_strip (trait.get_trait_items ());
    2093              : }
    2094              : 
    2095              : void
    2096         2201 : CfgStrip::visit (AST::InherentImpl &impl)
    2097              : {
    2098              :   // initial strip test based on outer attrs
    2099         2201 :   expand_cfg_attrs (impl.get_outer_attrs ());
    2100         2201 :   if (fails_cfg_with_expand (impl.get_outer_attrs ()))
    2101              :     {
    2102            1 :       impl.mark_for_strip ();
    2103            1 :       return;
    2104              :     }
    2105              : 
    2106              :   // strip test based on inner attrs
    2107         2200 :   expand_cfg_attrs (impl.get_inner_attrs ());
    2108         2200 :   if (fails_cfg_with_expand (impl.get_inner_attrs ()))
    2109              :     {
    2110            0 :       impl.mark_for_strip ();
    2111            0 :       return;
    2112              :     }
    2113              : 
    2114         2200 :   AST::DefaultASTVisitor::visit (impl);
    2115              : 
    2116         2200 :   auto &type = impl.get_type ();
    2117              : 
    2118         2200 :   if (type.is_marked_for_strip ())
    2119            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2120              : 
    2121         2200 :   maybe_strip_pointer_allow_strip (impl.get_impl_items ());
    2122              : }
    2123              : 
    2124              : void
    2125        11160 : CfgStrip::visit (AST::TraitImpl &impl)
    2126              : {
    2127              :   // initial strip test based on outer attrs
    2128        11160 :   expand_cfg_attrs (impl.get_outer_attrs ());
    2129        11160 :   if (fails_cfg_with_expand (impl.get_outer_attrs ()))
    2130              :     {
    2131            0 :       impl.mark_for_strip ();
    2132            0 :       return;
    2133              :     }
    2134              : 
    2135              :   // strip test based on inner attrs
    2136        11160 :   expand_cfg_attrs (impl.get_inner_attrs ());
    2137        11160 :   if (fails_cfg_with_expand (impl.get_inner_attrs ()))
    2138              :     {
    2139            0 :       impl.mark_for_strip ();
    2140            0 :       return;
    2141              :     }
    2142              : 
    2143        11160 :   AST::DefaultASTVisitor::visit (impl);
    2144              : 
    2145        11160 :   auto &type = impl.get_type ();
    2146        11160 :   if (type.is_marked_for_strip ())
    2147            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2148              : 
    2149        11160 :   auto &trait_path = impl.get_trait_path ();
    2150        11160 :   visit (trait_path);
    2151        11160 :   if (trait_path.is_marked_for_strip ())
    2152            0 :     rust_error_at (trait_path.get_locus (),
    2153              :                    "cannot strip typepath in this position");
    2154              : 
    2155        11160 :   maybe_strip_pointer_allow_strip (impl.get_impl_items ());
    2156              : }
    2157              : 
    2158              : void
    2159            2 : CfgStrip::visit (AST::ExternalTypeItem &item)
    2160              : {
    2161            2 :   expand_cfg_attrs (item.get_outer_attrs ());
    2162              : 
    2163            2 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2164            0 :     item.mark_for_strip ();
    2165              : 
    2166              :   // TODO: Can we do anything like expand a macro here?
    2167              :   // extern "C" { type ffi_ty!(); }
    2168              :   // ?
    2169            2 : }
    2170              : 
    2171              : void
    2172            2 : CfgStrip::visit (AST::ExternalStaticItem &item)
    2173              : {
    2174              :   // strip test based on outer attrs
    2175            2 :   expand_cfg_attrs (item.get_outer_attrs ());
    2176            2 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2177              :     {
    2178            0 :       item.mark_for_strip ();
    2179            0 :       return;
    2180              :     }
    2181              : 
    2182            2 :   AST::DefaultASTVisitor::visit (item);
    2183              : 
    2184            2 :   auto &type = item.get_type ();
    2185            2 :   if (type.is_marked_for_strip ())
    2186            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2187              : }
    2188              : 
    2189              : void
    2190         3355 : CfgStrip::visit (AST::ExternBlock &block)
    2191              : {
    2192              :   // initial strip test based on outer attrs
    2193         3355 :   expand_cfg_attrs (block.get_outer_attrs ());
    2194         3355 :   if (fails_cfg_with_expand (block.get_outer_attrs ()))
    2195              :     {
    2196            0 :       block.mark_for_strip ();
    2197            0 :       return;
    2198              :     }
    2199              : 
    2200              :   // strip test based on inner attrs
    2201         3355 :   expand_cfg_attrs (block.get_inner_attrs ());
    2202         3355 :   if (fails_cfg_with_expand (block.get_inner_attrs ()))
    2203              :     {
    2204            0 :       block.mark_for_strip ();
    2205            0 :       return;
    2206              :     }
    2207              : 
    2208         3355 :   maybe_strip_pointer_allow_strip (block.get_extern_items ());
    2209              : }
    2210              : 
    2211              : void
    2212         3825 : CfgStrip::visit (AST::MacroRulesDefinition &rules_def)
    2213              : {
    2214              :   // initial strip test based on outer attrs
    2215         3825 :   expand_cfg_attrs (rules_def.get_outer_attrs ());
    2216         3825 :   if (fails_cfg_with_expand (rules_def.get_outer_attrs ()))
    2217              :     {
    2218            0 :       rules_def.mark_for_strip ();
    2219            0 :       return;
    2220              :     }
    2221              : }
    2222              : 
    2223              : void
    2224       164106 : CfgStrip::visit (AST::IdentifierPattern &pattern)
    2225              : {
    2226              :   // can only strip sub-patterns of the inner pattern to bind
    2227       164106 :   if (!pattern.has_subpattern ())
    2228              :     return;
    2229              : 
    2230           70 :   AST::DefaultASTVisitor::visit (pattern);
    2231              : 
    2232           70 :   auto &sub_pattern = pattern.get_subpattern ();
    2233           70 :   if (sub_pattern.is_marked_for_strip ())
    2234            0 :     rust_error_at (sub_pattern.get_locus (),
    2235              :                    "cannot strip pattern in this position");
    2236              : }
    2237              : 
    2238              : void
    2239           42 : CfgStrip::visit (AST::RangePatternBoundPath &bound)
    2240              : {
    2241              :   // can expand path, but not strip it directly
    2242           42 :   auto &path = bound.get_path ();
    2243           42 :   visit (path);
    2244           42 :   if (path.is_marked_for_strip ())
    2245            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2246           42 : }
    2247              : 
    2248              : void
    2249            0 : CfgStrip::visit (AST::RangePatternBoundQualPath &bound)
    2250              : {
    2251              :   // can expand path, but not strip it directly
    2252            0 :   auto &path = bound.get_qualified_path ();
    2253            0 :   visit (path);
    2254            0 :   if (path.is_marked_for_strip ())
    2255            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2256            0 : }
    2257              : 
    2258              : void
    2259          820 : CfgStrip::visit (AST::ReferencePattern &pattern)
    2260              : {
    2261          820 :   AST::DefaultASTVisitor::visit (pattern);
    2262              : 
    2263          820 :   auto &sub_pattern = pattern.get_referenced_pattern ();
    2264          820 :   if (sub_pattern.is_marked_for_strip ())
    2265            0 :     rust_error_at (sub_pattern.get_locus (),
    2266              :                    "cannot strip pattern in this position");
    2267          820 : }
    2268              : void
    2269           78 : CfgStrip::visit (AST::StructPatternFieldTuplePat &field)
    2270              : {
    2271              :   // initial strip test based on outer attrs
    2272           78 :   expand_cfg_attrs (field.get_outer_attrs ());
    2273           78 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2274              :     {
    2275            0 :       field.mark_for_strip ();
    2276            0 :       return;
    2277              :     }
    2278              : 
    2279           78 :   AST::DefaultASTVisitor::visit (field);
    2280              : 
    2281              :   // strip sub-patterns (can't strip top-level pattern)
    2282           78 :   auto &sub_pattern = field.get_index_pattern ();
    2283           78 :   if (sub_pattern.is_marked_for_strip ())
    2284            0 :     rust_error_at (sub_pattern.get_locus (),
    2285              :                    "cannot strip pattern in this position");
    2286              : }
    2287              : 
    2288              : void
    2289          516 : CfgStrip::visit (AST::StructPatternFieldIdentPat &field)
    2290              : {
    2291              :   // initial strip test based on outer attrs
    2292          516 :   expand_cfg_attrs (field.get_outer_attrs ());
    2293          516 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2294              :     {
    2295            0 :       field.mark_for_strip ();
    2296            0 :       return;
    2297              :     }
    2298              : 
    2299          516 :   AST::DefaultASTVisitor::visit (field);
    2300              :   // strip sub-patterns (can't strip top-level pattern)
    2301          516 :   auto &sub_pattern = field.get_ident_pattern ();
    2302          516 :   if (sub_pattern.is_marked_for_strip ())
    2303            0 :     rust_error_at (sub_pattern.get_locus (),
    2304              :                    "cannot strip pattern in this position");
    2305              : }
    2306              : void
    2307          252 : CfgStrip::visit (AST::StructPatternFieldIdent &field)
    2308              : {
    2309              :   // initial strip test based on outer attrs
    2310          252 :   expand_cfg_attrs (field.get_outer_attrs ());
    2311          252 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2312              :     {
    2313            0 :       field.mark_for_strip ();
    2314            0 :       return;
    2315              :     }
    2316              : }
    2317              : 
    2318              : void
    2319          502 : CfgStrip::visit (AST::StructPattern &pattern)
    2320              : {
    2321              :   // expand (but don't strip) path
    2322          502 :   auto &path = pattern.get_path ();
    2323          502 :   visit (path);
    2324          502 :   if (path.is_marked_for_strip ())
    2325            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2326              : 
    2327              :   /* TODO: apparently struct pattern fields can have outer attrs. so can they
    2328              :    * be stripped? */
    2329          502 :   if (!pattern.has_struct_pattern_elems ())
    2330              :     return;
    2331              : 
    2332          500 :   auto &elems = pattern.get_struct_pattern_elems ();
    2333              : 
    2334              :   // assuming you can strip struct pattern fields
    2335          500 :   maybe_strip_pointer_allow_strip (elems.get_struct_pattern_fields ());
    2336              : 
    2337              :   // assuming you can strip the ".." part
    2338          500 :   if (elems.has_rest ())
    2339              :     {
    2340           10 :       expand_cfg_attrs (elems.get_etc_outer_attrs ());
    2341           10 :       if (fails_cfg_with_expand (elems.get_etc_outer_attrs ()))
    2342            0 :         elems.strip_etc ();
    2343              :     }
    2344              : }
    2345              : 
    2346              : void
    2347         4788 : CfgStrip::visit (AST::TupleStructItemsNoRest &tuple_items)
    2348              : {
    2349         4788 :   AST::DefaultASTVisitor::visit (tuple_items);
    2350              :   // can't strip individual patterns, only sub-patterns
    2351        10114 :   for (auto &pattern : tuple_items.get_patterns ())
    2352              :     {
    2353         5326 :       if (pattern->is_marked_for_strip ())
    2354            0 :         rust_error_at (pattern->get_locus (),
    2355              :                        "cannot strip pattern in this position");
    2356              :       // TODO: quit stripping now? or keep going?
    2357              :     }
    2358         4788 : }
    2359              : void
    2360          148 : CfgStrip::visit (AST::TupleStructItemsHasRest &tuple_items)
    2361              : {
    2362          148 :   AST::DefaultASTVisitor::visit (tuple_items);
    2363              :   // can't strip individual patterns, only sub-patterns
    2364          266 :   for (auto &lower_pattern : tuple_items.get_lower_patterns ())
    2365              :     {
    2366          118 :       if (lower_pattern->is_marked_for_strip ())
    2367            0 :         rust_error_at (lower_pattern->get_locus (),
    2368              :                        "cannot strip pattern in this position");
    2369              :       // TODO: quit stripping now? or keep going?
    2370              :     }
    2371          214 :   for (auto &upper_pattern : tuple_items.get_upper_patterns ())
    2372              :     {
    2373           66 :       if (upper_pattern->is_marked_for_strip ())
    2374            0 :         rust_error_at (upper_pattern->get_locus (),
    2375              :                        "cannot strip pattern in this position");
    2376              :       // TODO: quit stripping now? or keep going?
    2377              :     }
    2378          148 : }
    2379              : 
    2380              : void
    2381         4936 : CfgStrip::visit (AST::TupleStructPattern &pattern)
    2382              : {
    2383              :   // expand (but don't strip) path
    2384         4936 :   auto &path = pattern.get_path ();
    2385         4936 :   visit (path);
    2386         4936 :   if (path.is_marked_for_strip ())
    2387            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2388              : 
    2389         4936 :   AST::DefaultASTVisitor::visit (pattern);
    2390         4936 : }
    2391              : 
    2392              : void
    2393         3934 : CfgStrip::visit (AST::TuplePatternItemsNoRest &tuple_items)
    2394              : {
    2395         3934 :   AST::DefaultASTVisitor::visit (tuple_items);
    2396              : 
    2397              :   // can't strip individual patterns, only sub-patterns
    2398        11814 :   for (auto &pattern : tuple_items.get_patterns ())
    2399              :     {
    2400         7880 :       if (pattern->is_marked_for_strip ())
    2401            0 :         rust_error_at (pattern->get_locus (),
    2402              :                        "cannot strip pattern in this position");
    2403              :       // TODO: quit stripping now? or keep going?
    2404              :     }
    2405         3934 : }
    2406              : 
    2407              : void
    2408          102 : CfgStrip::visit (AST::TuplePatternItemsHasRest &tuple_items)
    2409              : {
    2410          102 :   AST::DefaultASTVisitor::visit (tuple_items);
    2411              : 
    2412              :   // can't strip individual patterns, only sub-patterns
    2413          206 :   for (auto &lower_pattern : tuple_items.get_lower_patterns ())
    2414              :     {
    2415          104 :       if (lower_pattern->is_marked_for_strip ())
    2416            0 :         rust_error_at (lower_pattern->get_locus (),
    2417              :                        "cannot strip pattern in this position");
    2418              :       // TODO: quit stripping now? or keep going?
    2419              :     }
    2420          214 :   for (auto &upper_pattern : tuple_items.get_upper_patterns ())
    2421              :     {
    2422          112 :       if (upper_pattern->is_marked_for_strip ())
    2423            0 :         rust_error_at (upper_pattern->get_locus (),
    2424              :                        "cannot strip pattern in this position");
    2425              :       // TODO: quit stripping now? or keep going?
    2426              :     }
    2427          102 : }
    2428              : 
    2429              : void
    2430          176 : CfgStrip::visit (AST::GroupedPattern &pattern)
    2431              : {
    2432          176 :   AST::DefaultASTVisitor::visit (pattern);
    2433              :   // can't strip inner pattern, only sub-patterns
    2434          176 :   auto &pattern_in_parens = pattern.get_pattern_in_parens ();
    2435              : 
    2436          176 :   if (pattern_in_parens.is_marked_for_strip ())
    2437            0 :     rust_error_at (pattern_in_parens.get_locus (),
    2438              :                    "cannot strip pattern in this position");
    2439          176 : }
    2440              : 
    2441              : void
    2442          120 : CfgStrip::visit (AST::SlicePatternItemsNoRest &items)
    2443              : {
    2444          120 :   AST::DefaultASTVisitor::visit (items);
    2445              :   // can't strip individual patterns, only sub-patterns
    2446          360 :   for (auto &pattern : items.get_patterns ())
    2447              :     {
    2448          240 :       if (pattern->is_marked_for_strip ())
    2449            0 :         rust_error_at (pattern->get_locus (),
    2450              :                        "cannot strip pattern in this position");
    2451              :     }
    2452          120 : }
    2453              : 
    2454              : void
    2455          172 : CfgStrip::visit (AST::SlicePatternItemsHasRest &items)
    2456              : {
    2457          172 :   AST::DefaultASTVisitor::visit (items);
    2458              :   // can't strip individual patterns, only sub-patterns
    2459          342 :   for (auto &pattern : items.get_lower_patterns ())
    2460              :     {
    2461          170 :       if (pattern->is_marked_for_strip ())
    2462            0 :         rust_error_at (pattern->get_locus (),
    2463              :                        "cannot strip pattern in this position");
    2464              :     }
    2465          342 :   for (auto &pattern : items.get_upper_patterns ())
    2466              :     {
    2467          170 :       if (pattern->is_marked_for_strip ())
    2468            0 :         rust_error_at (pattern->get_locus (),
    2469              :                        "cannot strip pattern in this position");
    2470              :     }
    2471          172 : }
    2472              : 
    2473              : void
    2474          292 : CfgStrip::visit (AST::SlicePattern &pattern)
    2475              : {
    2476          292 :   AST::DefaultASTVisitor::visit (pattern);
    2477          292 : }
    2478              : 
    2479              : void
    2480          970 : CfgStrip::visit (AST::AltPattern &pattern)
    2481              : {
    2482          970 :   AST::DefaultASTVisitor::visit (pattern);
    2483              :   // can't strip individual patterns, only sub-patterns
    2484         3040 :   for (auto &alt : pattern.get_alts ())
    2485              :     {
    2486         2070 :       if (alt->is_marked_for_strip ())
    2487            0 :         rust_error_at (alt->get_locus (),
    2488              :                        "cannot strip pattern in this position");
    2489              :       // TODO: quit stripping now? or keep going?
    2490              :     }
    2491          970 : }
    2492              : 
    2493              : void
    2494        73952 : CfgStrip::visit (AST::LetStmt &stmt)
    2495              : {
    2496              :   // initial strip test based on outer attrs
    2497        73952 :   expand_cfg_attrs (stmt.get_outer_attrs ());
    2498        73952 :   if (fails_cfg_with_expand (stmt.get_outer_attrs ()))
    2499              :     {
    2500            0 :       stmt.mark_for_strip ();
    2501            0 :       return;
    2502              :     }
    2503              : 
    2504        73952 :   AST::DefaultASTVisitor::visit (stmt);
    2505              :   // can't strip pattern, but call for sub-patterns
    2506        73952 :   auto &pattern = stmt.get_pattern ();
    2507        73952 :   if (pattern.is_marked_for_strip ())
    2508            0 :     rust_error_at (pattern.get_locus (),
    2509              :                    "cannot strip pattern in this position");
    2510              : 
    2511              :   // similar for type
    2512        73952 :   if (stmt.has_type ())
    2513              :     {
    2514        10018 :       auto &type = stmt.get_type ();
    2515              : 
    2516        10018 :       if (type.is_marked_for_strip ())
    2517            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2518              :     }
    2519              : 
    2520              :   /* strip any internal sub-expressions - expression itself isn't
    2521              :    * allowed to have external attributes in this position so can't be
    2522              :    * stripped */
    2523        73952 :   if (stmt.has_init_expr ())
    2524              :     {
    2525        68828 :       auto &init_expr = stmt.get_init_expr ();
    2526              : 
    2527        68828 :       if (init_expr.is_marked_for_strip ())
    2528            0 :         rust_error_at (init_expr.get_locus (),
    2529              :                        "cannot strip expression in this position - outer "
    2530              :                        "attributes not allowed");
    2531              :     }
    2532              : }
    2533              : 
    2534              : void
    2535        62516 : CfgStrip::visit (AST::ExprStmt &stmt)
    2536              : {
    2537              :   // outer attributes associated with expr, so rely on expr
    2538              : 
    2539              :   // guard - should prevent null pointer expr
    2540        62516 :   if (stmt.is_marked_for_strip ())
    2541              :     return;
    2542              : 
    2543        62516 :   AST::DefaultASTVisitor::visit (stmt);
    2544              :   // strip if expr is to be stripped
    2545        62516 :   auto &expr = stmt.get_expr ();
    2546        62516 :   if (expr.is_marked_for_strip ())
    2547              :     {
    2548           18 :       stmt.mark_for_strip ();
    2549           18 :       return;
    2550              :     }
    2551              : }
    2552              : 
    2553              : void
    2554         6873 : CfgStrip::visit (AST::TraitBound &bound)
    2555              : {
    2556              :   // nothing in for lifetimes to strip
    2557              : 
    2558              :   // expand but don't strip type path
    2559         6873 :   auto &path = bound.get_type_path ();
    2560         6873 :   visit (path);
    2561         6873 :   if (path.is_marked_for_strip ())
    2562            0 :     rust_error_at (path.get_locus (),
    2563              :                    "cannot strip type path in this position");
    2564         6873 : }
    2565              : 
    2566              : void
    2567           22 : CfgStrip::visit (AST::ParenthesisedType &type)
    2568              : {
    2569           22 :   AST::DefaultASTVisitor::visit (type);
    2570              :   // expand but don't strip inner type
    2571           22 :   auto &inner_type = type.get_type_in_parens ();
    2572           22 :   if (inner_type->is_marked_for_strip ())
    2573            0 :     rust_error_at (inner_type->get_locus (),
    2574              :                    "cannot strip type in this position");
    2575           22 : }
    2576              : 
    2577              : void
    2578         1811 : CfgStrip::visit (AST::TupleType &type)
    2579              : {
    2580         1811 :   AST::DefaultASTVisitor::visit (type);
    2581              :   // TODO: assuming that types can't be stripped as types don't have outer
    2582              :   // attributes
    2583         4693 :   for (auto &elem_type : type.get_elems ())
    2584              :     {
    2585         2882 :       if (elem_type->is_marked_for_strip ())
    2586            0 :         rust_error_at (elem_type->get_locus (),
    2587              :                        "cannot strip type in this position");
    2588              :     }
    2589         1811 : }
    2590              : 
    2591              : void
    2592        48521 : CfgStrip::visit (AST::RawPointerType &type)
    2593              : {
    2594        48521 :   AST::DefaultASTVisitor::visit (type);
    2595              :   // expand but don't strip type pointed to
    2596        48521 :   auto &pointed_type = type.get_type_pointed_to ();
    2597        48521 :   if (pointed_type.is_marked_for_strip ())
    2598            0 :     rust_error_at (pointed_type.get_locus (),
    2599              :                    "cannot strip type in this position");
    2600        48521 : }
    2601              : 
    2602              : void
    2603        32958 : CfgStrip::visit (AST::ReferenceType &type)
    2604              : {
    2605        32958 :   AST::DefaultASTVisitor::visit (type);
    2606              :   // expand but don't strip type referenced
    2607        32958 :   auto &referenced_type = type.get_type_referenced ();
    2608        32958 :   if (referenced_type.is_marked_for_strip ())
    2609            0 :     rust_error_at (referenced_type.get_locus (),
    2610              :                    "cannot strip type in this position");
    2611        32958 : }
    2612              : 
    2613              : void
    2614         4892 : CfgStrip::visit (AST::ArrayType &type)
    2615              : {
    2616         4892 :   AST::DefaultASTVisitor::visit (type);
    2617              :   // expand but don't strip type referenced
    2618         4892 :   auto &base_type = type.get_elem_type ();
    2619         4892 :   if (base_type.is_marked_for_strip ())
    2620            0 :     rust_error_at (base_type.get_locus (),
    2621              :                    "cannot strip type in this position");
    2622              : 
    2623              :   // same for expression
    2624         4892 :   auto &size_expr = type.get_size_expr ();
    2625         4892 :   if (size_expr.is_marked_for_strip ())
    2626            0 :     rust_error_at (size_expr.get_locus (),
    2627              :                    "cannot strip expression in this position");
    2628         4892 : }
    2629              : void
    2630         4023 : CfgStrip::visit (AST::SliceType &type)
    2631              : {
    2632         4023 :   AST::DefaultASTVisitor::visit (type);
    2633              :   // expand but don't strip elem type
    2634         4023 :   auto &elem_type = type.get_elem_type ();
    2635         4023 :   if (elem_type.is_marked_for_strip ())
    2636            0 :     rust_error_at (elem_type.get_locus (),
    2637              :                    "cannot strip type in this position");
    2638         4023 : }
    2639              : 
    2640              : void
    2641          254 : CfgStrip::visit (AST::BareFunctionType &type)
    2642              : {
    2643              :   // seem to be no generics
    2644          254 :   AST::DefaultASTVisitor::visit (type);
    2645              : 
    2646              :   // presumably function params can be stripped
    2647          254 :   auto &params = type.get_function_params ();
    2648          474 :   for (auto it = params.begin (); it != params.end ();)
    2649              :     {
    2650          220 :       auto &param = *it;
    2651              : 
    2652          220 :       auto &param_attrs = param.get_outer_attrs ();
    2653          220 :       expand_cfg_attrs (param_attrs);
    2654          220 :       if (fails_cfg_with_expand (param_attrs))
    2655              :         {
    2656            0 :           it = params.erase (it);
    2657            0 :           continue;
    2658              :         }
    2659              : 
    2660          220 :       auto &type = param.get_type ();
    2661          220 :       if (type.is_marked_for_strip ())
    2662            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2663              : 
    2664              :       // increment if nothing else happens
    2665          220 :       ++it;
    2666              :     }
    2667              : 
    2668              :   /* TODO: assuming that variadic nature cannot be stripped. If this
    2669              :    * is not true, then have code here to do so. */
    2670              : 
    2671          254 :   if (type.has_return_type ())
    2672              :     {
    2673              :       // FIXME: Can we have type expansion in this position?
    2674              :       // In that case, we need to handle AST::TypeNoBounds on top of just
    2675              :       // AST::Types
    2676          182 :       auto &return_type = type.get_return_type ();
    2677          182 :       if (return_type.is_marked_for_strip ())
    2678            0 :         rust_error_at (return_type.get_locus (),
    2679              :                        "cannot strip type in this position");
    2680              :     }
    2681              : 
    2682              :   // no where clause, apparently
    2683          254 : }
    2684              : 
    2685              : void
    2686        39642 : CfgStrip::visit (AST::SelfParam &param)
    2687              : {
    2688        39642 :   AST::DefaultASTVisitor::visit (param);
    2689              : 
    2690        39642 :   if (param.has_type ())
    2691              :     {
    2692            4 :       auto &type = param.get_type ();
    2693            4 :       if (type.is_marked_for_strip ())
    2694            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2695              :     }
    2696              :   /* TODO: maybe check for invariants being violated - e.g. both type and
    2697              :    * lifetime? */
    2698        39642 : }
    2699              : 
    2700              : } // namespace Rust
        

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.