LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-cfg-strip.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 73.2 % 1146 839
Test Date: 2026-08-22 16:33:35 Functions: 95.0 % 120 114
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     67065842 : CfgStrip::fails_cfg_with_expand (AST::AttrVec &attrs) const
      35              : {
      36     67065842 :   auto &session = Session::get_instance ();
      37              : 
      38              :   // TODO: maybe have something that strips cfg attributes that evaluate true?
      39     70865233 :   for (auto &attr : attrs)
      40              :     {
      41      3799734 :       if (attr.get_path () == Values::Attributes::CFG)
      42              :         {
      43         7421 :           if (!attr.is_parsed_to_meta_item ())
      44          809 :             attr.parse_attr_to_meta_item ();
      45              : 
      46              :           // DEBUG
      47         7421 :           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         7420 :             rust_debug ("attr has been successfully parsed to meta item, "
      52              :                         "right before cfg predicate check");
      53              : 
      54         7421 :           if (!attr.check_cfg_predicate (session))
      55              :             {
      56              :               // DEBUG
      57          342 :               rust_debug (
      58              :                 "cfg predicate failed for attribute: \033[0;31m'%s'\033[0m",
      59              :                 attr.as_string ().c_str ());
      60              : 
      61          342 :               return true;
      62              :             }
      63              :           else
      64              :             {
      65              :               // DEBUG
      66         7079 :               rust_debug ("cfg predicate succeeded for attribute: "
      67              :                           "\033[0;31m'%s'\033[0m",
      68              :                           attr.as_string ().c_str ());
      69              :             }
      70              :         }
      71      3792313 :       else if (!expansion_cfg.should_test
      72      7584626 :                && 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     67070687 : expand_cfg_attrs (AST::AttrVec &attrs)
      83              : {
      84     67070687 :   auto &session = Session::get_instance ();
      85              : 
      86    137955241 :   for (std::size_t i = 0; i < attrs.size (); i++)
      87              :     {
      88      3813867 :       auto &attr = attrs[i];
      89      3813867 :       if (attr.get_path () == Values::Attributes::CFG_ATTR)
      90              :         {
      91         1694 :           if (!attr.is_parsed_to_meta_item ())
      92         1674 :             attr.parse_attr_to_meta_item ();
      93              : 
      94         1694 :           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           52 :               AST::AttrVec new_attrs = attr.separate_cfg_attrs ();
     101              : 
     102              :               // remove attr from vector
     103           52 :               attrs.erase (attrs.begin () + i);
     104              : 
     105              :               // add new attrs to vector
     106           52 :               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           52 :               i--;
     115           52 :             }
     116              :           else
     117              :             {
     118              :               // Key has not been found, remove the whole attribute
     119         1642 :               attrs.erase (attrs.begin () + i);
     120         1642 :               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     67070687 :   attrs.shrink_to_fit ();
     132     67070687 : }
     133              : 
     134              : void
     135        11176 : CfgStrip::go (AST::Crate &crate)
     136              : {
     137        11176 :   visit (crate);
     138        11176 : }
     139              : 
     140              : void
     141        11176 : CfgStrip::visit (AST::Crate &crate)
     142              : {
     143              :   // expand crate cfg_attr attributes
     144        11176 :   expand_cfg_attrs (crate.inner_attrs);
     145              : 
     146        11176 :   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        11176 :   auto &items = crate.items;
     154              : 
     155        11176 :   AST::DefaultASTVisitor::visit (crate);
     156        61382 :   for (auto it = items.begin (); it != items.end ();)
     157              :     {
     158        50206 :       auto &item = *it;
     159        50206 :       if (item->is_marked_for_strip ())
     160           20 :         it = items.erase (it);
     161              :       else
     162        50186 :         it++;
     163              :     }
     164              :   // expand module attributes?
     165        11176 : }
     166              : 
     167              : // Visitor used to expand attributes.
     168              : void
     169       113041 : CfgStrip::maybe_strip_struct_fields (std::vector<AST::StructField> &fields)
     170              : {
     171       138504 :   for (auto it = fields.begin (); it != fields.end ();)
     172              :     {
     173        25463 :       auto &field = *it;
     174              : 
     175        25463 :       auto &field_attrs = field.get_outer_attrs ();
     176        25463 :       expand_cfg_attrs (field_attrs);
     177        25463 :       if (fails_cfg_with_expand (field_attrs))
     178              :         {
     179            2 :           it = fields.erase (it);
     180            2 :           continue;
     181              :         }
     182              : 
     183              :       // expand sub-types of type, but can't strip type itself
     184        25461 :       auto &type = field.get_field_type ();
     185        25461 :       type.accept_vis (*this);
     186              : 
     187        25461 :       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        25461 :       ++it;
     192              :     }
     193       113041 : }
     194              : 
     195              : void
     196        53905 : CfgStrip::maybe_strip_struct_expr_fields (
     197              :   std::vector<std::unique_ptr<AST::StructExprField>> &fields)
     198              : {
     199       154524 :   for (auto it = fields.begin (); it != fields.end ();)
     200              :     {
     201       100619 :       auto &field = *it;
     202              : 
     203       100619 :       auto &field_attrs = field->get_outer_attrs ();
     204       100619 :       expand_cfg_attrs (field_attrs);
     205       100619 :       if (fails_cfg_with_expand (field_attrs))
     206              :         {
     207            1 :           it = fields.erase (it);
     208            1 :           continue;
     209              :         }
     210              : 
     211       100618 :       ++it;
     212              :     }
     213        53905 : }
     214              : 
     215              : void
     216        10250 : CfgStrip::maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields)
     217              : {
     218        35879 :   for (auto it = fields.begin (); it != fields.end ();)
     219              :     {
     220        25629 :       auto &field = *it;
     221              : 
     222        25629 :       auto &field_attrs = field.get_outer_attrs ();
     223        25629 :       expand_cfg_attrs (field_attrs);
     224        25629 :       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        25629 :       auto &type = field.get_field_type ();
     232        25629 :       type.accept_vis (*this);
     233        25629 :       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        25629 :       ++it;
     238              :     }
     239        10250 : }
     240              : 
     241              : void
     242       802738 : CfgStrip::maybe_strip_function_params (
     243              :   std::vector<std::unique_ptr<AST::Param>> &params)
     244              : {
     245      2208425 :   for (auto it = params.begin (); it != params.end ();)
     246              :     {
     247      1405687 :       if (!(*it)->is_self () && !(*it)->is_variadic ())
     248              :         {
     249       818012 :           auto param = static_cast<AST::FunctionParam *> (it->get ());
     250              : 
     251       818012 :           auto &param_attrs = param->get_outer_attrs ();
     252       818012 :           expand_cfg_attrs (param_attrs);
     253       818012 :           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       818012 :           auto &pattern = param->get_pattern ();
     261       818012 :           pattern.accept_vis (*this);
     262       818012 :           if (pattern.is_marked_for_strip ())
     263            0 :             rust_error_at (pattern.get_locus (),
     264              :                            "cannot strip pattern in this position");
     265              : 
     266       818012 :           auto &type = param->get_type ();
     267       818012 :           type.accept_vis (*this);
     268              : 
     269       818012 :           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      1405687 :       ++it;
     275              :     }
     276       802738 : }
     277              : 
     278              : void
     279      1309482 : 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      2559916 :   for (auto &arg : args.get_generic_args ())
     286              :     {
     287      1250434 :       switch (arg.get_kind ())
     288              :         {
     289       352680 :         case AST::GenericArg::Kind::Type:
     290       352680 :           {
     291       352680 :             auto &type = arg.get_type ();
     292       352680 :             type.accept_vis (*this);
     293              : 
     294       352680 :             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          576 :         case AST::GenericArg::Kind::Const:
     300          576 :           {
     301          576 :             auto &expr = arg.get_expression ();
     302          576 :             expr.accept_vis (*this);
     303              : 
     304          576 :             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      1325823 :   for (auto &binding : args.get_binding_args ())
     322              :     {
     323        16341 :       auto &type = binding.get_type ();
     324        16341 :       type.accept_vis (*this);
     325              : 
     326        16341 :       if (type.is_marked_for_strip ())
     327            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
     328              :     }
     329      1309482 : }
     330              : 
     331              : void
     332       217946 : CfgStrip::maybe_strip_qualified_path_type (AST::QualifiedPathType &path_type)
     333              : {
     334       217946 :   auto &type = path_type.get_type ();
     335       217946 :   type.accept_vis (*this);
     336              : 
     337       217946 :   if (type.is_marked_for_strip ())
     338            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
     339              : 
     340       217946 :   if (path_type.has_as_clause ())
     341              :     {
     342       208222 :       auto &type_path = path_type.get_as_type_path ();
     343       208222 :       visit (type_path);
     344       208222 :       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       217946 : }
     349              : 
     350              : void
     351        45050 : CfgStrip::CfgStrip::maybe_strip_closure_params (
     352              :   std::vector<AST::ClosureParam> &params)
     353              : {
     354        97590 :   for (auto it = params.begin (); it != params.end ();)
     355              :     {
     356        52540 :       auto &param = *it;
     357              : 
     358        52540 :       auto &param_attrs = param.get_outer_attrs ();
     359        52540 :       expand_cfg_attrs (param_attrs);
     360        52540 :       if (fails_cfg_with_expand (param_attrs))
     361              :         {
     362            0 :           it = params.erase (it);
     363            0 :           continue;
     364              :         }
     365              : 
     366        52540 :       auto &pattern = param.get_pattern ();
     367        52540 :       pattern.accept_vis (*this);
     368        52540 :       if (pattern.is_marked_for_strip ())
     369            0 :         rust_error_at (pattern.get_locus (),
     370              :                        "cannot strip pattern in this position");
     371              : 
     372        52540 :       if (param.has_type_given ())
     373              :         {
     374         2612 :           auto &type = param.get_type ();
     375         2612 :           type.accept_vis (*this);
     376              : 
     377         2612 :           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        52540 :       ++it;
     384              :     }
     385        45050 : }
     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     14268024 : CfgStrip::visit (AST::IdentifierExpr &ident_expr)
     397              : {
     398              :   // strip test based on outer attrs
     399     14268024 :   AST::DefaultASTVisitor::visit (ident_expr);
     400     14268024 :   expand_cfg_attrs (ident_expr.get_outer_attrs ());
     401     14268024 :   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       161876 : CfgStrip::visit (AST::MacroInvocation &macro_invoc)
     410              : {
     411              :   // initial strip test based on outer attrs
     412       161876 :   expand_cfg_attrs (macro_invoc.get_outer_attrs ());
     413       161876 :   if (fails_cfg_with_expand (macro_invoc.get_outer_attrs ()))
     414              :     {
     415           18 :       macro_invoc.mark_for_strip ();
     416           18 :       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      6155467 : CfgStrip::visit (AST::PathInExpression &path)
     428              : {
     429              :   // initial strip test based on outer attrs
     430      6155467 :   expand_cfg_attrs (path.get_outer_attrs ());
     431      6155467 :   if (fails_cfg_with_expand (path.get_outer_attrs ()))
     432              :     {
     433            0 :       path.mark_for_strip ();
     434            0 :       return;
     435              :     }
     436              : 
     437      6155467 :   if (!path.is_lang_item ())
     438              :     {
     439     13968751 :       for (auto &segment : path.get_segments ())
     440              :         {
     441     15652784 :           if (segment.has_generic_args ())
     442        40234 :             maybe_strip_generic_args (segment.get_generic_args ());
     443              :         }
     444              :     }
     445              : }
     446              : 
     447              : void
     448      1266612 : CfgStrip::visit (AST::TypePathSegmentGeneric &segment)
     449              : {
     450              :   // TODO: strip inside generic args
     451              : 
     452      1266612 :   if (!segment.has_generic_args ())
     453              :     return;
     454              : 
     455      1266608 :   maybe_strip_generic_args (segment.get_generic_args ());
     456              : }
     457              : void
     458        41643 : CfgStrip::visit (AST::TypePathSegmentFunction &segment)
     459              : {
     460        41643 :   AST::DefaultASTVisitor::visit (segment);
     461        41643 :   auto &type_path_function = segment.get_type_path_function ();
     462              : 
     463       103331 :   for (auto &type : type_path_function.get_params ())
     464              :     {
     465        61688 :       if (type->is_marked_for_strip ())
     466            0 :         rust_error_at (type->get_locus (),
     467              :                        "cannot strip type in this position");
     468              :     }
     469              : 
     470        41643 :   if (type_path_function.has_return_type ())
     471              :     {
     472        40278 :       auto &return_type = type_path_function.get_return_type ();
     473              : 
     474        40278 :       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        41643 : }
     479              : 
     480              : void
     481        11988 : CfgStrip::visit (AST::QualifiedPathInExpression &path)
     482              : {
     483              :   // initial strip test based on outer attrs
     484        11988 :   AST::DefaultASTVisitor::visit (path);
     485              : 
     486        11988 :   expand_cfg_attrs (path.get_outer_attrs ());
     487        11988 :   if (fails_cfg_with_expand (path.get_outer_attrs ()))
     488              :     {
     489            0 :       path.mark_for_strip ();
     490            0 :       return;
     491              :     }
     492              : 
     493        11988 :   maybe_strip_qualified_path_type (path.get_qualified_path_type ());
     494              : 
     495        23976 :   for (auto &segment : path.get_segments ())
     496              :     {
     497        23976 :       if (segment.has_generic_args ())
     498            0 :         maybe_strip_generic_args (segment.get_generic_args ());
     499              :     }
     500              : }
     501              : 
     502              : void
     503       205958 : CfgStrip::visit (AST::QualifiedPathInType &path)
     504              : {
     505       205958 :   maybe_strip_qualified_path_type (path.get_qualified_path_type ());
     506              : 
     507              :   // this shouldn't strip any segments, but can strip inside them
     508       205958 :   AST::DefaultASTVisitor::visit (path);
     509       205958 : }
     510              : 
     511              : void
     512     21682054 : CfgStrip::visit (AST::LiteralExpr &expr)
     513              : {
     514              :   // initial strip test based on outer attrs
     515     21682054 :   expand_cfg_attrs (expr.get_outer_attrs ());
     516     21682054 :   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       871670 : CfgStrip::visit (AST::BorrowExpr &expr)
     525              : {
     526       871670 :   AST::DefaultASTVisitor::visit (expr);
     527              :   // initial strip test based on outer attrs
     528       871670 :   expand_cfg_attrs (expr.get_outer_attrs ());
     529       871670 :   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       871670 :   auto &borrowed_expr = expr.get_borrowed_expr ();
     539       871670 :   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       807812 : CfgStrip::visit (AST::DereferenceExpr &expr)
     546              : {
     547              :   // initial strip test based on outer attrs
     548       807812 :   expand_cfg_attrs (expr.get_outer_attrs ());
     549       807812 :   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       807812 :   auto &dereferenced_expr = expr.get_dereferenced_expr ();
     559       807812 :   dereferenced_expr.accept_vis (*this);
     560       807812 :   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        63562 : CfgStrip::visit (AST::ErrorPropagationExpr &expr)
     567              : {
     568        63562 :   AST::DefaultASTVisitor::visit (expr);
     569              : 
     570              :   // initial strip test based on outer attrs
     571        63562 :   expand_cfg_attrs (expr.get_outer_attrs ());
     572        63562 :   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        63562 :   auto &propagating_expr = expr.get_propagating_expr ();
     582        63562 :   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        85267 : CfgStrip::visit (AST::NegationExpr &expr)
     589              : {
     590        85267 :   AST::DefaultASTVisitor::visit (expr);
     591              :   // initial strip test based on outer attrs
     592        85267 :   expand_cfg_attrs (expr.get_outer_attrs ());
     593        85267 :   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        85267 :   auto &negated_expr = expr.get_negated_expr ();
     603        85267 :   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      2557777 : CfgStrip::visit (AST::ArithmeticOrLogicalExpr &expr)
     610              : {
     611      2557777 :   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      2557777 :   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      2557777 :   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      2557777 : }
     626              : 
     627              : void
     628       257083 : 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       257083 :   AST::DefaultASTVisitor::visit (expr);
     633              : 
     634              :   // ensure that they are not marked for strip
     635       257083 :   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       257083 :   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       257083 : }
     645              : 
     646              : void
     647        61382 : 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        61382 :   AST::DefaultASTVisitor::visit (expr);
     652              : 
     653              :   // ensure that they are not marked for strip
     654        61382 :   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        61382 :   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        61382 : }
     664              : 
     665              : void
     666       517857 : 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       517857 :   AST::DefaultASTVisitor::visit (expr);
     671              : 
     672       517857 :   auto &casted_expr = expr.get_casted_expr ();
     673              :   // ensure that they are not marked for strip
     674       517857 :   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       517857 :   auto &type = expr.get_type_to_cast_to ();
     681       517857 :   if (type.is_marked_for_strip ())
     682            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
     683       517857 : }
     684              : void
     685       252071 : CfgStrip::visit (AST::AssignmentExpr &expr)
     686              : {
     687       252071 :   expand_cfg_attrs (expr.get_outer_attrs ());
     688       252071 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     689              :     {
     690           14 :       expr.mark_for_strip ();
     691           14 :       return;
     692              :     }
     693       252057 :   AST::DefaultASTVisitor::visit (expr);
     694              : 
     695              :   // ensure that they are not marked for strip
     696       252057 :   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       252057 :   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       140806 : 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       140806 :   AST::DefaultASTVisitor::visit (expr);
     712              : 
     713              :   // ensure that they are not marked for strip
     714       140806 :   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       140806 :   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       140806 : }
     724              : void
     725       468760 : CfgStrip::visit (AST::GroupedExpr &expr)
     726              : {
     727              :   // initial strip test based on outer attrs
     728       468760 :   expand_cfg_attrs (expr.get_outer_attrs ());
     729       468760 :   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       468760 :   expand_cfg_attrs (expr.get_inner_attrs ());
     738       468760 :   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       468760 :   AST::DefaultASTVisitor::visit (expr);
     748              : 
     749       468760 :   auto &inner_expr = expr.get_expr_in_parens ();
     750       468760 :   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      1205552 : CfgStrip::visit (AST::ArrayElemsValues &elems)
     757              : {
     758              :   /* apparently outer attributes are allowed in "elements of array
     759              :    * expressions" according to spec */
     760      1205552 :   maybe_strip_pointer_allow_strip (elems.get_values ());
     761      1205552 : }
     762              : void
     763         5472 : 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         5472 :   AST::DefaultASTVisitor::visit (elems);
     770              : 
     771              :   // only intend stripping for internal sub-expressions
     772         5472 :   auto &copied_expr = elems.get_elem_to_copy ();
     773         5472 :   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         5472 :   auto &copy_count = elems.get_num_copies ();
     779         5472 :   copy_count.accept_vis (*this);
     780         5472 :   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         5472 : }
     785              : void
     786      1211024 : CfgStrip::visit (AST::ArrayExpr &expr)
     787              : {
     788              :   // initial strip test based on outer attrs
     789      1211024 :   expand_cfg_attrs (expr.get_outer_attrs ());
     790      1211024 :   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      1211024 :   expand_cfg_attrs (expr.get_inner_attrs ());
     799      1211024 :   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      1211024 :   AST::DefaultASTVisitor::visit (expr);
     808              : }
     809              : 
     810              : void
     811       113191 : 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       113191 :   expand_cfg_attrs (expr.get_outer_attrs ());
     818       113191 :   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       113191 :   AST::DefaultASTVisitor::visit (expr);
     828              : 
     829       113191 :   const auto &array_expr = expr.get_array_expr ();
     830       113191 :   if (array_expr.is_marked_for_strip ())
     831              :     {
     832            1 :       rust_error_at (array_expr.get_locus (),
     833              :                      "cannot strip expression in this position - outer "
     834              :                      "attributes not allowed");
     835            1 :       expr.mark_for_strip ();
     836            1 :       return;
     837              :     }
     838              : 
     839       113190 :   const auto &index_expr = expr.get_index_expr ();
     840       113190 :   if (index_expr.is_marked_for_strip ())
     841            0 :     rust_error_at (index_expr.get_locus (),
     842              :                    "cannot strip expression in this position - outer "
     843              :                    "attributes not allowed");
     844              : }
     845              : void
     846       228205 : CfgStrip::visit (AST::TupleExpr &expr)
     847              : {
     848              :   /* according to spec, outer attributes are allowed on "elements of
     849              :    * tuple expressions" */
     850              : 
     851              :   // initial strip test based on outer attrs
     852       228205 :   expand_cfg_attrs (expr.get_outer_attrs ());
     853       228205 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     854              :     {
     855            0 :       expr.mark_for_strip ();
     856            0 :       return;
     857              :     }
     858              : 
     859              :   /* strip test based on inner attrs - spec says these are inner
     860              :    * attributes, not outer attributes of inner expr */
     861       228205 :   expand_cfg_attrs (expr.get_inner_attrs ());
     862       228205 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     863              :     {
     864            0 :       expr.mark_for_strip ();
     865            0 :       return;
     866              :     }
     867              : 
     868              :   /* apparently outer attributes are allowed in "elements of tuple
     869              :    * expressions" according to spec */
     870       228205 :   maybe_strip_pointer_allow_strip (expr.get_tuple_elems ());
     871              : }
     872              : void
     873       412683 : CfgStrip::visit (AST::TupleIndexExpr &expr)
     874              : {
     875              :   // initial strip test based on outer attrs
     876       412683 :   expand_cfg_attrs (expr.get_outer_attrs ());
     877       412683 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     878              :     {
     879            0 :       expr.mark_for_strip ();
     880            0 :       return;
     881              :     }
     882              : 
     883       412683 :   AST::DefaultASTVisitor::visit (expr);
     884              :   /* wouldn't strip this directly (as outer attrs should be
     885              :    * associated with this level), but any sub-expressions would be
     886              :    * stripped. Thus, no need to erase when strip check called. */
     887       412683 :   auto &tuple_expr = expr.get_tuple_expr ();
     888       412683 :   if (tuple_expr.is_marked_for_strip ())
     889            0 :     rust_error_at (tuple_expr.get_locus (),
     890              :                    "cannot strip expression in this position - outer "
     891              :                    "attributes not allowed");
     892              : }
     893              : 
     894              : void
     895         1942 : CfgStrip::visit (AST::StructExprStruct &expr)
     896              : {
     897              :   // initial strip test based on outer attrs
     898         1942 :   expand_cfg_attrs (expr.get_outer_attrs ());
     899         1942 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     900              :     {
     901            0 :       expr.mark_for_strip ();
     902            0 :       return;
     903              :     }
     904              : 
     905              :   /* strip test based on inner attrs - spec says these are inner
     906              :    * attributes, not outer attributes of inner expr */
     907         1942 :   expand_cfg_attrs (expr.get_inner_attrs ());
     908         1942 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     909              :     {
     910            0 :       expr.mark_for_strip ();
     911            0 :       return;
     912              :     }
     913              : 
     914              :   // strip sub-exprs of path
     915         1942 :   auto &struct_name = expr.get_struct_name ();
     916         1942 :   visit (struct_name);
     917         1942 :   if (struct_name.is_marked_for_strip ())
     918            0 :     rust_error_at (struct_name.get_locus (),
     919              :                    "cannot strip path in this position");
     920              : }
     921              : 
     922              : void
     923        86744 : CfgStrip::visit (AST::StructExprFieldIdentifierValue &field)
     924              : {
     925              :   /* as no attrs possible (at moment, at least), only sub-expression
     926              :    * stripping is possible */
     927        86744 :   AST::DefaultASTVisitor::visit (field);
     928              : 
     929        86744 :   auto &value = field.get_value ();
     930        86744 :   if (value.is_marked_for_strip ())
     931            0 :     rust_error_at (value.get_locus (),
     932              :                    "cannot strip expression in this position - outer "
     933              :                    "attributes not allowed");
     934        86744 : }
     935              : void
     936          176 : CfgStrip::visit (AST::StructExprFieldIndexValue &field)
     937              : {
     938              :   /* as no attrs possible (at moment, at least), only sub-expression
     939              :    * stripping is possible */
     940          176 :   AST::DefaultASTVisitor::visit (field);
     941              : 
     942          176 :   auto &value = field.get_value ();
     943          176 :   if (value.is_marked_for_strip ())
     944            0 :     rust_error_at (value.get_locus (),
     945              :                    "cannot strip expression in this position - outer "
     946              :                    "attributes not allowed");
     947          176 : }
     948              : void
     949        53905 : CfgStrip::visit (AST::StructExprStructFields &expr)
     950              : {
     951              :   // initial strip test based on outer attrs
     952        53905 :   expand_cfg_attrs (expr.get_outer_attrs ());
     953        53905 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     954              :     {
     955            0 :       expr.mark_for_strip ();
     956            0 :       return;
     957              :     }
     958              : 
     959              :   /* strip test based on inner attrs - spec says these are inner
     960              :    * attributes, not outer attributes of inner expr */
     961        53905 :   expand_cfg_attrs (expr.get_inner_attrs ());
     962        53905 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
     963              :     {
     964            0 :       expr.mark_for_strip ();
     965            0 :       return;
     966              :     }
     967              : 
     968              :   // strip sub-exprs of path
     969        53905 :   auto &struct_name = expr.get_struct_name ();
     970        53905 :   visit (struct_name);
     971        53905 :   if (struct_name.is_marked_for_strip ())
     972            0 :     rust_error_at (struct_name.get_locus (),
     973              :                    "cannot strip path in this position");
     974              : 
     975              :   /* spec does not specify whether expressions are allowed to be
     976              :    * stripped at top level of struct fields, but I wouldn't think
     977              :    * that they would be, so operating under the assumption that only
     978              :    * sub-expressions can be stripped. */
     979        53905 :   AST::DefaultASTVisitor::visit (expr);
     980              : 
     981              :   /* struct base presumably can't be stripped, as the '..' is before
     982              :    * the expression. as such, can only strip sub-expressions. */
     983        53905 :   if (expr.has_struct_base ())
     984              :     {
     985          528 :       auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
     986          528 :       base_struct_expr.accept_vis (*this);
     987          528 :       if (base_struct_expr.is_marked_for_strip ())
     988            0 :         rust_error_at (base_struct_expr.get_locus (),
     989              :                        "cannot strip expression in this position - outer "
     990              :                        "attributes not allowed");
     991              :     }
     992              : 
     993        53905 :   maybe_strip_struct_expr_fields (expr.get_fields ());
     994              : }
     995              : 
     996              : void
     997            0 : CfgStrip::visit (AST::StructExprStructBase &expr)
     998              : {
     999              :   // initial strip test based on outer attrs
    1000            0 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1001            0 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1002              :     {
    1003            0 :       expr.mark_for_strip ();
    1004            0 :       return;
    1005              :     }
    1006              : 
    1007              :   /* strip test based on inner attrs - spec says these are inner
    1008              :    * attributes, not outer attributes of inner expr */
    1009            0 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1010            0 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1011              :     {
    1012            0 :       expr.mark_for_strip ();
    1013            0 :       return;
    1014              :     }
    1015              : 
    1016              :   // strip sub-exprs of path
    1017            0 :   auto &struct_name = expr.get_struct_name ();
    1018            0 :   visit (struct_name);
    1019            0 :   if (struct_name.is_marked_for_strip ())
    1020            0 :     rust_error_at (struct_name.get_locus (),
    1021              :                    "cannot strip path in this position");
    1022              : 
    1023              :   /* struct base presumably can't be stripped, as the '..' is before
    1024              :    * the expression. as such, can only strip sub-expressions. */
    1025            0 :   rust_assert (!expr.get_struct_base ().is_invalid ());
    1026            0 :   auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
    1027            0 :   base_struct_expr.accept_vis (*this);
    1028            0 :   if (base_struct_expr.is_marked_for_strip ())
    1029            0 :     rust_error_at (base_struct_expr.get_locus (),
    1030              :                    "cannot strip expression in this position - outer "
    1031              :                    "attributes not allowed");
    1032              : }
    1033              : void
    1034      4141638 : CfgStrip::visit (AST::CallExpr &expr)
    1035              : {
    1036              :   // initial strip test based on outer attrs
    1037      4141638 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1038      4141638 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1039              :     {
    1040            1 :       expr.mark_for_strip ();
    1041            1 :       return;
    1042              :     }
    1043              : 
    1044              :   /* should not be outer attrs on "function" expression - outer attrs
    1045              :    * should be associated with call expr as a whole. only sub-expr
    1046              :    * expansion is possible. */
    1047      4141637 :   AST::DefaultASTVisitor::visit (expr);
    1048              : 
    1049      4141637 :   auto &function = expr.get_function_expr ();
    1050      4141637 :   if (function.is_marked_for_strip ())
    1051              :     {
    1052            1 :       rust_error_at (function.get_locus (),
    1053              :                      "cannot strip expression in this position - outer "
    1054              :                      "attributes not allowed");
    1055            1 :       expr.mark_for_strip ();
    1056            1 :       return;
    1057              :     }
    1058              : 
    1059              :   /* spec says outer attributes are specifically allowed for elements
    1060              :    * of call expressions, so full stripping possible */
    1061              :   // FIXME: Arthur: Figure out how to refactor this - This is similar to
    1062              :   // expanding items in the crate or stmts in blocks
    1063      4141636 :   maybe_strip_pointer_allow_strip (expr.get_params ());
    1064              : }
    1065              : void
    1066      3436763 : CfgStrip::visit (AST::MethodCallExpr &expr)
    1067              : {
    1068              :   // initial strip test based on outer attrs
    1069      3436763 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1070      3436763 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1071              :     {
    1072            0 :       expr.mark_for_strip ();
    1073            0 :       return;
    1074              :     }
    1075              : 
    1076              :   /* should not be outer attrs on "receiver" expression - outer attrs
    1077              :    * should be associated with call expr as a whole. only sub-expr
    1078              :    * expansion is possible. */
    1079      3436763 :   AST::DefaultASTVisitor::visit (expr);
    1080              : 
    1081      3436763 :   auto &receiver = expr.get_receiver_expr ();
    1082      3436763 :   if (receiver.is_marked_for_strip ())
    1083            0 :     rust_error_at (receiver.get_locus (),
    1084              :                    "cannot strip expression in this position - outer "
    1085              :                    "attributes not allowed");
    1086              : 
    1087      3436763 :   auto &method_name = expr.get_method_name ();
    1088      3436763 :   if (method_name.has_generic_args ())
    1089         2640 :     maybe_strip_generic_args (method_name.get_generic_args ());
    1090              : 
    1091              :   /* spec says outer attributes are specifically allowed for elements
    1092              :    * of method call expressions, so full stripping possible */
    1093      3436763 :   maybe_strip_pointer_allow_strip (expr.get_params ());
    1094              : }
    1095              : void
    1096       641358 : CfgStrip::visit (AST::FieldAccessExpr &expr)
    1097              : {
    1098              :   // initial strip test based on outer attrs
    1099       641358 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1100       641358 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1101              :     {
    1102            0 :       expr.mark_for_strip ();
    1103            0 :       return;
    1104              :     }
    1105              : 
    1106              :   /* should not be outer attrs on "receiver" expression - outer attrs
    1107              :    * should be associated with field expr as a whole. only sub-expr
    1108              :    * expansion is possible. */
    1109       641358 :   AST::DefaultASTVisitor::visit (expr);
    1110              : 
    1111       641358 :   auto &receiver = expr.get_receiver_expr ();
    1112       641358 :   if (receiver.is_marked_for_strip ())
    1113            0 :     rust_error_at (receiver.get_locus (),
    1114              :                    "cannot strip expression in this position - outer "
    1115              :                    "attributes not allowed");
    1116              : }
    1117              : void
    1118        44860 : CfgStrip::visit (AST::ClosureExprInner &expr)
    1119              : {
    1120              :   // initial strip test based on outer attrs
    1121        44860 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1122        44860 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1123              :     {
    1124            0 :       expr.mark_for_strip ();
    1125            0 :       return;
    1126              :     }
    1127              : 
    1128              :   /* strip closure parameters if required - this is specifically
    1129              :    * allowed by spec */
    1130        44860 :   maybe_strip_closure_params (expr.get_params ());
    1131              : 
    1132        44860 :   AST::DefaultASTVisitor::visit (expr);
    1133              : 
    1134              :   // can't strip expression itself, but can strip sub-expressions
    1135        44860 :   auto &definition_expr = expr.get_definition_expr ();
    1136        44860 :   if (definition_expr.is_marked_for_strip ())
    1137            0 :     rust_error_at (definition_expr.get_locus (),
    1138              :                    "cannot strip expression in this position - outer "
    1139              :                    "attributes not allowed");
    1140              : }
    1141              : 
    1142              : void
    1143      1346206 : CfgStrip::visit (AST::BlockExpr &expr)
    1144              : {
    1145              :   // initial strip test based on outer attrs
    1146      1346206 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1147      1346206 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1148              :     {
    1149          107 :       expr.mark_for_strip ();
    1150          107 :       return;
    1151              :     }
    1152              : 
    1153              :   /* strip test based on inner attrs - spec says there are inner
    1154              :    * attributes, not just outer attributes of inner stmts */
    1155      1346099 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1156      1346099 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1157              :     {
    1158            0 :       expr.mark_for_strip ();
    1159            0 :       return;
    1160              :     }
    1161              : 
    1162      1346099 :   maybe_strip_pointer_allow_strip (expr.get_statements ());
    1163              : 
    1164      1346099 :   AST::DefaultASTVisitor::visit (expr);
    1165              : 
    1166              :   // strip tail expression if exists - can actually fully remove it
    1167      1346099 :   if (expr.has_tail_expr ())
    1168              :     {
    1169      1114890 :       auto &tail_expr = expr.get_tail_expr ();
    1170              : 
    1171      1114890 :       if (tail_expr.is_marked_for_strip ())
    1172           83 :         expr.strip_tail_expr ();
    1173              :     }
    1174              : }
    1175              : 
    1176              : void
    1177          190 : CfgStrip::visit (AST::ClosureExprInnerTyped &expr)
    1178              : {
    1179              :   // initial strip test based on outer attrs
    1180          190 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1181          190 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1182              :     {
    1183            0 :       expr.mark_for_strip ();
    1184            0 :       return;
    1185              :     }
    1186              : 
    1187              :   /* strip closure parameters if required - this is specifically
    1188              :    * allowed by spec */
    1189          190 :   maybe_strip_closure_params (expr.get_params ());
    1190              : 
    1191          190 :   AST::DefaultASTVisitor::visit (expr);
    1192              : 
    1193              :   // can't strip return type, but can strip sub-types
    1194          190 :   auto &type = expr.get_return_type ();
    1195              : 
    1196          190 :   if (type.is_marked_for_strip ())
    1197            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1198              : 
    1199              :   // can't strip expression itself, but can strip sub-expressions
    1200          190 :   auto &definition_block = expr.get_definition_expr ();
    1201          190 :   definition_block.accept_vis (*this);
    1202          190 :   if (definition_block.is_marked_for_strip ())
    1203            0 :     rust_error_at (definition_block.get_locus (),
    1204              :                    "cannot strip block expression in this position - outer "
    1205              :                    "attributes not allowed");
    1206              : }
    1207              : void
    1208         4714 : CfgStrip::visit (AST::ContinueExpr &expr)
    1209              : {
    1210              :   // initial strip test based on outer attrs
    1211         4714 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1212         4714 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1213              :     {
    1214            0 :       expr.mark_for_strip ();
    1215            0 :       return;
    1216              :     }
    1217              : }
    1218              : void
    1219         9436 : CfgStrip::visit (AST::BreakExpr &expr)
    1220              : {
    1221              :   // initial strip test based on outer attrs
    1222         9436 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1223         9436 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1224              :     {
    1225            0 :       expr.mark_for_strip ();
    1226            0 :       return;
    1227              :     }
    1228         9436 :   AST::DefaultASTVisitor::visit (expr);
    1229              : 
    1230              :   /* spec does not say that you can have outer attributes on
    1231              :    * expression, so assuming you can't. stripping for sub-expressions
    1232              :    * is the only thing that can be done */
    1233         9436 :   if (expr.has_break_expr ())
    1234              :     {
    1235          292 :       auto &break_expr = expr.get_break_expr_unchecked ();
    1236              : 
    1237          292 :       if (break_expr.is_marked_for_strip ())
    1238            0 :         rust_error_at (break_expr.get_locus (),
    1239              :                        "cannot strip expression in this position - outer "
    1240              :                        "attributes not allowed");
    1241              :     }
    1242              : }
    1243              : void
    1244        39259 : CfgStrip::visit (AST::RangeFromToExpr &expr)
    1245              : {
    1246              :   /* outer attributes never allowed before these. while cannot strip
    1247              :    * two direct descendant expressions, can strip ones below that */
    1248        39259 :   AST::DefaultASTVisitor::visit (expr);
    1249              : 
    1250              :   // ensure that they are not marked for strip
    1251        39259 :   if (expr.get_from_expr ().is_marked_for_strip ())
    1252            0 :     rust_error_at (expr.get_from_expr ().get_locus (),
    1253              :                    "cannot strip expression in this position - outer "
    1254              :                    "attributes are never allowed "
    1255              :                    "before range exprs");
    1256        39259 :   if (expr.get_to_expr ().is_marked_for_strip ())
    1257            0 :     rust_error_at (expr.get_to_expr ().get_locus (),
    1258              :                    "cannot strip expression in this position - outer "
    1259              :                    "attributes not allowed");
    1260        39259 : }
    1261              : void
    1262        15710 : CfgStrip::visit (AST::RangeFromExpr &expr)
    1263              : {
    1264              :   /* outer attributes never allowed before these. while cannot strip
    1265              :    * direct descendant expression, can strip ones below that */
    1266              : 
    1267        15710 :   AST::DefaultASTVisitor::visit (expr);
    1268              :   /* should have no possibility for outer attrs as would be parsed
    1269              :    * with outer expr */
    1270        15710 :   auto &from_expr = expr.get_from_expr ();
    1271        15710 :   if (from_expr.is_marked_for_strip ())
    1272            0 :     rust_error_at (from_expr.get_locus (),
    1273              :                    "cannot strip expression in this position - outer "
    1274              :                    "attributes are never allowed before range exprs");
    1275        15710 : }
    1276              : void
    1277        21768 : CfgStrip::visit (AST::RangeToExpr &expr)
    1278              : {
    1279              :   /* outer attributes never allowed before these. while cannot strip
    1280              :    * direct descendant expression, can strip ones below that */
    1281              : 
    1282        21768 :   AST::DefaultASTVisitor::visit (expr);
    1283              :   /* should syntactically not have outer attributes, though this may
    1284              :    * not have worked in practice */
    1285        21768 :   auto &to_expr = expr.get_to_expr ();
    1286        21768 :   if (to_expr.is_marked_for_strip ())
    1287            0 :     rust_error_at (to_expr.get_locus (),
    1288              :                    "cannot strip expression in this position - outer "
    1289              :                    "attributes not allowed");
    1290        21768 : }
    1291              : 
    1292              : void
    1293          448 : CfgStrip::visit (AST::RangeFromToInclExpr &expr)
    1294              : {
    1295              :   /* outer attributes never allowed before these. while cannot strip
    1296              :    * two direct descendant expressions, can strip ones below that */
    1297              : 
    1298          448 :   AST::DefaultASTVisitor::visit (expr);
    1299              : 
    1300              :   // ensure that they are not marked for strip
    1301          448 :   if (expr.get_from_expr ().is_marked_for_strip ())
    1302            0 :     rust_error_at (expr.get_from_expr ().get_locus (),
    1303              :                    "cannot strip expression in this position - outer "
    1304              :                    "attributes are never allowed "
    1305              :                    "before range exprs");
    1306          448 :   if (expr.get_to_expr ().is_marked_for_strip ())
    1307            0 :     rust_error_at (expr.get_to_expr ().get_locus (),
    1308              :                    "cannot strip expression in this position - outer "
    1309              :                    "attributes not allowed");
    1310          448 : }
    1311              : void
    1312            0 : CfgStrip::visit (AST::RangeToInclExpr &expr)
    1313              : {
    1314              :   /* outer attributes never allowed before these. while cannot strip
    1315              :    * direct descendant expression, can strip ones below that */
    1316              : 
    1317            0 :   AST::DefaultASTVisitor::visit (expr);
    1318              :   /* should syntactically not have outer attributes, though this may
    1319              :    * not have worked in practice */
    1320            0 :   auto &to_expr = expr.get_to_expr ();
    1321            0 :   if (to_expr.is_marked_for_strip ())
    1322            0 :     rust_error_at (to_expr.get_locus (),
    1323              :                    "cannot strip expression in this position - outer "
    1324              :                    "attributes not allowed");
    1325            0 : }
    1326              : void
    1327        92788 : CfgStrip::visit (AST::ReturnExpr &expr)
    1328              : {
    1329              :   // initial strip test based on outer attrs
    1330        92788 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1331        92788 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1332              :     {
    1333            0 :       expr.mark_for_strip ();
    1334            0 :       return;
    1335              :     }
    1336              : 
    1337        92788 :   AST::DefaultASTVisitor::visit (expr);
    1338              : 
    1339              :   /* spec does not say that you can have outer attributes on
    1340              :    * expression, so assuming you can't. stripping for sub-expressions
    1341              :    * is the only thing that can be done */
    1342        92788 :   if (expr.has_returned_expr ())
    1343              :     {
    1344        90392 :       auto &returned_expr = expr.get_returned_expr ();
    1345        90392 :       if (returned_expr.is_marked_for_strip ())
    1346            0 :         rust_error_at (returned_expr.get_locus (),
    1347              :                        "cannot strip expression in this position - outer "
    1348              :                        "attributes not allowed");
    1349              :     }
    1350              :   /* TODO: conceptually, you would maybe be able to remove a returned
    1351              :    * expr - e.g. if you had conditional compilation returning void or
    1352              :    * returning a type. On the other hand, I think that function
    1353              :    * return type cannot be conditionally compiled, so I assumed you
    1354              :    * can't do this either. */
    1355              : }
    1356              : void
    1357       123061 : CfgStrip::visit (AST::UnsafeBlockExpr &expr)
    1358              : {
    1359              :   // initial strip test based on outer attrs
    1360       123061 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1361       123061 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1362              :     {
    1363            7 :       expr.mark_for_strip ();
    1364            7 :       return;
    1365              :     }
    1366              : 
    1367       123054 :   AST::DefaultASTVisitor::visit (expr);
    1368              : 
    1369              :   // can't strip block itself, but can strip sub-expressions
    1370       123054 :   auto &block_expr = expr.get_block_expr ();
    1371       123054 :   if (block_expr.is_marked_for_strip ())
    1372            0 :     rust_error_at (block_expr.get_locus (),
    1373              :                    "cannot strip block expression in this position - outer "
    1374              :                    "attributes not allowed");
    1375              : }
    1376              : void
    1377         2971 : CfgStrip::visit (AST::LoopExpr &expr)
    1378              : {
    1379              :   // initial strip test based on outer attrs
    1380         2971 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1381         2971 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1382              :     {
    1383            0 :       expr.mark_for_strip ();
    1384            0 :       return;
    1385              :     }
    1386              : 
    1387         2971 :   AST::DefaultASTVisitor::visit (expr);
    1388              : 
    1389              :   // can't strip block itself, but can strip sub-expressions
    1390         2971 :   auto &loop_block = expr.get_loop_block ();
    1391         2971 :   if (loop_block.is_marked_for_strip ())
    1392            0 :     rust_error_at (loop_block.get_locus (),
    1393              :                    "cannot strip block expression in this position - outer "
    1394              :                    "attributes not allowed");
    1395              : }
    1396              : void
    1397        14260 : CfgStrip::visit (AST::WhileLoopExpr &expr)
    1398              : {
    1399              :   // initial strip test based on outer attrs
    1400        14260 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1401        14260 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1402              :     {
    1403            0 :       expr.mark_for_strip ();
    1404            0 :       return;
    1405              :     }
    1406              : 
    1407        14260 :   AST::DefaultASTVisitor::visit (expr);
    1408              :   // can't strip predicate expr itself, but can strip sub-expressions
    1409        14260 :   auto &predicate_expr = expr.get_predicate_expr ();
    1410        14260 :   if (predicate_expr.is_marked_for_strip ())
    1411            0 :     rust_error_at (predicate_expr.get_locus (),
    1412              :                    "cannot strip expression in this position - outer "
    1413              :                    "attributes not allowed");
    1414              : 
    1415              :   // can't strip block itself, but can strip sub-expressions
    1416        14260 :   auto &loop_block = expr.get_loop_block ();
    1417        14260 :   if (loop_block.is_marked_for_strip ())
    1418            0 :     rust_error_at (loop_block.get_locus (),
    1419              :                    "cannot strip block expression in this position - outer "
    1420              :                    "attributes not allowed");
    1421              : }
    1422              : void
    1423         2964 : CfgStrip::visit (AST::WhileLetLoopExpr &expr)
    1424              : {
    1425              :   // initial strip test based on outer attrs
    1426         2964 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1427         2964 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1428              :     {
    1429            0 :       expr.mark_for_strip ();
    1430            0 :       return;
    1431              :     }
    1432              : 
    1433         2964 :   AST::DefaultASTVisitor::visit (expr);
    1434              : 
    1435         2964 :   if (expr.get_pattern ()->is_marked_for_strip ())
    1436            0 :     rust_error_at (expr.get_pattern ()->get_locus (),
    1437              :                    "cannot strip pattern in this position");
    1438              : 
    1439              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1440         2964 :   auto &scrutinee_expr = expr.get_scrutinee_expr ();
    1441         2964 :   if (scrutinee_expr.is_marked_for_strip ())
    1442            0 :     rust_error_at (scrutinee_expr.get_locus (),
    1443              :                    "cannot strip expression in this position - outer "
    1444              :                    "attributes not allowed");
    1445              : 
    1446              :   // can't strip block itself, but can strip sub-expressions
    1447         2964 :   auto &loop_block = expr.get_loop_block ();
    1448         2964 :   if (loop_block.is_marked_for_strip ())
    1449            0 :     rust_error_at (loop_block.get_locus (),
    1450              :                    "cannot strip block expression in this position - outer "
    1451              :                    "attributes not allowed");
    1452              : }
    1453              : void
    1454        15739 : CfgStrip::visit (AST::ForLoopExpr &expr)
    1455              : {
    1456              :   // initial strip test based on outer attrs
    1457        15739 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1458        15739 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1459              :     {
    1460            0 :       expr.mark_for_strip ();
    1461            0 :       return;
    1462              :     }
    1463              : 
    1464        15739 :   AST::DefaultASTVisitor::visit (expr);
    1465              :   // strip sub-patterns of pattern
    1466        15739 :   auto &pattern = expr.get_pattern ();
    1467        15739 :   if (pattern.is_marked_for_strip ())
    1468            0 :     rust_error_at (pattern.get_locus (),
    1469              :                    "cannot strip pattern in this position");
    1470              : 
    1471              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1472        15739 :   auto &iterator_expr = expr.get_iterator_expr ();
    1473        15739 :   if (iterator_expr.is_marked_for_strip ())
    1474            0 :     rust_error_at (iterator_expr.get_locus (),
    1475              :                    "cannot strip expression in this position - outer "
    1476              :                    "attributes not allowed");
    1477              : 
    1478              :   // can't strip block itself, but can strip sub-expressions
    1479        15739 :   auto &loop_block = expr.get_loop_block ();
    1480        15739 :   if (loop_block.is_marked_for_strip ())
    1481            0 :     rust_error_at (loop_block.get_locus (),
    1482              :                    "cannot strip block expression in this position - outer "
    1483              :                    "attributes not allowed");
    1484              : }
    1485              : void
    1486       204806 : CfgStrip::visit (AST::IfExpr &expr)
    1487              : {
    1488              :   // rust playground test shows that IfExpr does support outer attrs, at least
    1489              :   // when used as statement
    1490              : 
    1491              :   // initial strip test based on outer attrs
    1492       204806 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1493       204806 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1494              :     {
    1495            0 :       expr.mark_for_strip ();
    1496            0 :       return;
    1497              :     }
    1498              : 
    1499       204806 :   AST::DefaultASTVisitor::visit (expr);
    1500              : 
    1501              :   // can't strip condition expr itself, but can strip sub-expressions
    1502       204806 :   auto &condition_expr = expr.get_condition_expr ();
    1503       204806 :   if (condition_expr.is_marked_for_strip ())
    1504            0 :     rust_error_at (condition_expr.get_locus (),
    1505              :                    "cannot strip expression in this position - outer "
    1506              :                    "attributes not allowed");
    1507              : 
    1508              :   // can't strip if block itself, but can strip sub-expressions
    1509       204806 :   auto &if_block = expr.get_if_block ();
    1510       204806 :   if (if_block.is_marked_for_strip ())
    1511            0 :     rust_error_at (if_block.get_locus (),
    1512              :                    "cannot strip block expression in this position - outer "
    1513              :                    "attributes not allowed");
    1514              : }
    1515              : 
    1516              : void
    1517        94726 : CfgStrip::visit (AST::IfExprConseqElse &expr)
    1518              : {
    1519              :   // initial strip test based on outer attrs
    1520        94726 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1521        94726 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1522              :     {
    1523            0 :       expr.mark_for_strip ();
    1524            0 :       return;
    1525              :     }
    1526              : 
    1527        94726 :   AST::DefaultASTVisitor::visit (expr);
    1528              : 
    1529              :   // can't strip condition expr itself, but can strip sub-expressions
    1530        94726 :   auto &condition_expr = expr.get_condition_expr ();
    1531        94726 :   if (condition_expr.is_marked_for_strip ())
    1532            0 :     rust_error_at (condition_expr.get_locus (),
    1533              :                    "cannot strip expression in this position - outer "
    1534              :                    "attributes not allowed");
    1535              : 
    1536              :   // can't strip if block itself, but can strip sub-expressions
    1537        94726 :   auto &if_block = expr.get_if_block ();
    1538        94726 :   if (if_block.is_marked_for_strip ())
    1539            0 :     rust_error_at (if_block.get_locus (),
    1540              :                    "cannot strip block expression in this position - outer "
    1541              :                    "attributes not allowed");
    1542              : 
    1543              :   // can't strip else block itself, but can strip sub-expressions
    1544        94726 :   auto &else_block = expr.get_else_block ();
    1545        94726 :   if (else_block.is_marked_for_strip ())
    1546            0 :     rust_error_at (else_block.get_locus (),
    1547              :                    "cannot strip block expression in this position - outer "
    1548              :                    "attributes not allowed");
    1549              : }
    1550              : 
    1551              : void
    1552        10664 : CfgStrip::visit (AST::IfLetExpr &expr)
    1553              : {
    1554              :   // initial strip test based on outer attrs
    1555        10664 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1556        10664 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1557              :     {
    1558            0 :       expr.mark_for_strip ();
    1559            0 :       return;
    1560              :     }
    1561              : 
    1562        10664 :   AST::DefaultASTVisitor::visit (expr);
    1563              : 
    1564        10664 :   if (expr.get_pattern ()->is_marked_for_strip ())
    1565            0 :     rust_error_at (expr.get_pattern ()->get_locus (),
    1566              :                    "cannot strip pattern in this position");
    1567              : 
    1568              :   // can't strip value expr itself, but can strip sub-expressions
    1569        10664 :   auto &value_expr = expr.get_value_expr ();
    1570        10664 :   if (value_expr.is_marked_for_strip ())
    1571            0 :     rust_error_at (value_expr.get_locus (),
    1572              :                    "cannot strip expression in this position - outer "
    1573              :                    "attributes not allowed");
    1574              : 
    1575              :   // can't strip if block itself, but can strip sub-expressions
    1576        10664 :   auto &if_block = expr.get_if_block ();
    1577        10664 :   if (if_block.is_marked_for_strip ())
    1578            0 :     rust_error_at (if_block.get_locus (),
    1579              :                    "cannot strip block expression in this position - outer "
    1580              :                    "attributes not allowed");
    1581              : }
    1582              : void
    1583         2550 : CfgStrip::visit (AST::IfLetExprConseqElse &expr)
    1584              : {
    1585              :   // initial strip test based on outer attrs
    1586         2550 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1587         2550 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1588              :     {
    1589            0 :       expr.mark_for_strip ();
    1590            0 :       return;
    1591              :     }
    1592              : 
    1593         2550 :   AST::DefaultASTVisitor::visit (expr);
    1594              : 
    1595         2550 :   if (expr.get_pattern ()->is_marked_for_strip ())
    1596            0 :     rust_error_at (expr.get_pattern ()->get_locus (),
    1597              :                    "cannot strip pattern in this position");
    1598              : 
    1599              :   // can't strip value expr itself, but can strip sub-expressions
    1600         2550 :   auto &value_expr = expr.get_value_expr ();
    1601         2550 :   if (value_expr.is_marked_for_strip ())
    1602            0 :     rust_error_at (value_expr.get_locus (),
    1603              :                    "cannot strip expression in this position - outer "
    1604              :                    "attributes not allowed");
    1605              : 
    1606              :   // can't strip if block itself, but can strip sub-expressions
    1607         2550 :   auto &if_block = expr.get_if_block ();
    1608         2550 :   if (if_block.is_marked_for_strip ())
    1609            0 :     rust_error_at (if_block.get_locus (),
    1610              :                    "cannot strip block expression in this position - outer "
    1611              :                    "attributes not allowed");
    1612              : 
    1613              :   // can't strip else block itself, but can strip sub-expressions
    1614         2550 :   auto &else_block = expr.get_else_block ();
    1615         2550 :   if (else_block.is_marked_for_strip ())
    1616            0 :     rust_error_at (else_block.get_locus (),
    1617              :                    "cannot strip block expression in this position - outer "
    1618              :                    "attributes not allowed");
    1619              : }
    1620              : void
    1621       285469 : CfgStrip::visit (AST::MatchExpr &expr)
    1622              : {
    1623              :   // initial strip test based on outer attrs
    1624       285469 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1625       285469 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1626              :     {
    1627            0 :       expr.mark_for_strip ();
    1628            0 :       return;
    1629              :     }
    1630              : 
    1631              :   // inner attr strip test
    1632       285469 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1633       285469 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1634              :     {
    1635            0 :       expr.mark_for_strip ();
    1636            0 :       return;
    1637              :     }
    1638              : 
    1639       285469 :   AST::DefaultASTVisitor::visit (expr);
    1640              : 
    1641              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1642       285469 :   auto &scrutinee_expr = expr.get_scrutinee_expr ();
    1643       285469 :   if (scrutinee_expr.is_marked_for_strip ())
    1644            0 :     rust_error_at (scrutinee_expr.get_locus (),
    1645              :                    "cannot strip expression in this position - outer "
    1646              :                    "attributes not allowed");
    1647              : 
    1648              :   // strip match cases
    1649       285469 :   auto &match_cases = expr.get_match_cases ();
    1650      2988581 :   for (auto it = match_cases.begin (); it != match_cases.end ();)
    1651              :     {
    1652      2703112 :       auto &match_case = *it;
    1653              : 
    1654              :       // strip match case based on outer attributes in match arm
    1655      2703112 :       auto &match_arm = match_case.get_arm ();
    1656      2703112 :       expand_cfg_attrs (match_arm.get_outer_attrs ());
    1657      2703112 :       if (fails_cfg_with_expand (match_arm.get_outer_attrs ()))
    1658              :         {
    1659              :           // strip match case
    1660            0 :           it = match_cases.erase (it);
    1661            0 :           continue;
    1662              :         }
    1663              : 
    1664      2703112 :       if (match_arm.get_pattern ()->is_marked_for_strip ())
    1665            0 :         rust_error_at (match_arm.get_pattern ()->get_locus (),
    1666              :                        "cannot strip pattern in this position");
    1667              : 
    1668              :       /* assuming that guard expression cannot be stripped as
    1669              :        * strictly speaking you would have to strip the whole guard to
    1670              :        * make syntactical sense, which you can't do. as such, only
    1671              :        * strip sub-expressions */
    1672      2703112 :       if (match_arm.has_match_arm_guard ())
    1673              :         {
    1674         2507 :           auto &guard_expr = match_arm.get_guard_expr ();
    1675         2507 :           if (guard_expr.is_marked_for_strip ())
    1676            0 :             rust_error_at (guard_expr.get_locus (),
    1677              :                            "cannot strip expression in this position - outer "
    1678              :                            "attributes not allowed");
    1679              :         }
    1680              : 
    1681              :       // strip sub-expressions from match cases
    1682      2703112 :       auto &case_expr = match_case.get_expr ();
    1683      2703112 :       if (case_expr.is_marked_for_strip ())
    1684            0 :         rust_error_at (case_expr.get_locus (),
    1685              :                        "cannot strip expression in this position - outer "
    1686              :                        "attributes not allowed");
    1687              : 
    1688              :       // increment to next case if haven't continued
    1689      2703112 :       ++it;
    1690              :     }
    1691              : }
    1692              : 
    1693              : void
    1694            0 : CfgStrip::visit (AST::AwaitExpr &expr)
    1695              : {
    1696              :   // initial strip test based on outer attrs
    1697            0 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1698            0 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1699              :     {
    1700            0 :       expr.mark_for_strip ();
    1701            0 :       return;
    1702              :     }
    1703              : 
    1704              :   /* can't strip awaited expr itself, but can strip sub-expressions
    1705              :    * - this is because you can't have no expr to await */
    1706            0 :   auto &awaited_expr = expr.get_awaited_expr ();
    1707            0 :   awaited_expr->accept_vis (*this);
    1708            0 :   if (awaited_expr->is_marked_for_strip ())
    1709            0 :     rust_error_at (awaited_expr->get_locus (),
    1710              :                    "cannot strip expression in this position - outer "
    1711              :                    "attributes not allowed");
    1712              : }
    1713              : 
    1714              : void
    1715            0 : CfgStrip::visit (AST::AsyncBlockExpr &expr)
    1716              : {
    1717              :   // initial strip test based on outer attrs
    1718            0 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1719            0 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1720              :     {
    1721            0 :       expr.mark_for_strip ();
    1722            0 :       return;
    1723              :     }
    1724              : 
    1725            0 :   AST::DefaultASTVisitor::visit (expr);
    1726              : 
    1727              :   // can't strip block itself, but can strip sub-expressions
    1728            0 :   auto &block_expr = expr.get_block_expr ();
    1729            0 :   if (block_expr->is_marked_for_strip ())
    1730            0 :     rust_error_at (block_expr->get_locus (),
    1731              :                    "cannot strip block expression in this position - outer "
    1732              :                    "attributes not allowed");
    1733              : }
    1734              : 
    1735              : void
    1736       322182 : CfgStrip::visit (AST::TypeParam &param)
    1737              : {
    1738              :   // outer attributes don't actually do anything, so ignore them
    1739              : 
    1740       322182 :   AST::DefaultASTVisitor::visit (param);
    1741              : 
    1742       322182 :   if (param.has_type () && param.get_type ().is_marked_for_strip ())
    1743            0 :     rust_error_at (param.get_type ().get_locus (),
    1744              :                    "cannot strip type in this position");
    1745       322182 : }
    1746              : 
    1747              : void
    1748        60087 : CfgStrip::visit (AST::TypeBoundWhereClauseItem &item)
    1749              : {
    1750              :   // for lifetimes shouldn't require
    1751        60087 :   AST::DefaultASTVisitor::visit (item);
    1752              : 
    1753        60087 :   auto &type = item.get_type ();
    1754        60087 :   if (type.is_marked_for_strip ())
    1755            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1756        60087 : }
    1757              : 
    1758              : void
    1759        11556 : CfgStrip::visit (AST::Module &module)
    1760              : {
    1761              :   // strip test based on outer attrs
    1762        11556 :   expand_cfg_attrs (module.get_outer_attrs ());
    1763        11556 :   if (fails_cfg_with_expand (module.get_outer_attrs ()))
    1764              :     {
    1765           67 :       module.mark_for_strip ();
    1766           67 :       return;
    1767              :     }
    1768              : 
    1769        11489 :   if (module.get_kind () == AST::Module::UNLOADED)
    1770              :     {
    1771          283 :       module.load_items ();
    1772              :     }
    1773              : 
    1774              :   // strip test based on inner attrs
    1775        11489 :   expand_cfg_attrs (module.get_inner_attrs ());
    1776        11489 :   if (fails_cfg_with_expand (module.get_inner_attrs ()))
    1777              :     {
    1778            0 :       module.mark_for_strip ();
    1779            0 :       return;
    1780              :     }
    1781              : 
    1782              :   // strip items if required
    1783        11489 :   maybe_strip_pointer_allow_strip (module.get_items ());
    1784              : }
    1785              : 
    1786              : void
    1787           79 : CfgStrip::visit (AST::ExternCrate &extern_crate)
    1788              : {
    1789              :   // strip test based on outer attrs
    1790           79 :   expand_cfg_attrs (extern_crate.get_outer_attrs ());
    1791           79 :   if (fails_cfg_with_expand (extern_crate.get_outer_attrs ()))
    1792              :     {
    1793            0 :       extern_crate.mark_for_strip ();
    1794            0 :       return;
    1795              :     }
    1796              : }
    1797              : 
    1798              : void
    1799        29291 : CfgStrip::visit (AST::UseDeclaration &use_decl)
    1800              : {
    1801              :   // strip test based on outer attrs
    1802        29291 :   expand_cfg_attrs (use_decl.get_outer_attrs ());
    1803        29291 :   if (fails_cfg_with_expand (use_decl.get_outer_attrs ()))
    1804              :     {
    1805           46 :       use_decl.mark_for_strip ();
    1806           46 :       return;
    1807              :     }
    1808              : }
    1809              : 
    1810              : void
    1811       802787 : CfgStrip::visit (AST::Function &function)
    1812              : {
    1813              :   // initial test based on outer attrs
    1814       802787 :   expand_cfg_attrs (function.get_outer_attrs ());
    1815       802787 :   if (fails_cfg_with_expand (function.get_outer_attrs ()))
    1816              :     {
    1817           49 :       function.mark_for_strip ();
    1818           49 :       return;
    1819              :     }
    1820              : 
    1821       802738 :   AST::DefaultASTVisitor::visit (function);
    1822              : 
    1823              :   /* strip function parameters if required - this is specifically
    1824              :    * allowed by spec */
    1825       802738 :   maybe_strip_function_params (function.get_function_params ());
    1826              : 
    1827       802738 :   if (function.has_return_type ())
    1828              :     {
    1829       688872 :       auto &return_type = function.get_return_type ();
    1830       688872 :       if (return_type.is_marked_for_strip ())
    1831            0 :         rust_error_at (return_type.get_locus (),
    1832              :                        "cannot strip type in this position");
    1833              :     }
    1834              : 
    1835              :   /* body should always exist - if error state, should have returned
    1836              :    * before now */
    1837              :   // can't strip block itself, but can strip sub-expressions
    1838       802738 :   if (function.has_body ())
    1839              :     {
    1840       747481 :       auto &block_expr = function.get_definition ();
    1841       747481 :       if (block_expr.value ()->is_marked_for_strip ())
    1842            0 :         rust_error_at (block_expr.value ()->get_locus (),
    1843              :                        "cannot strip block expression in this position - outer "
    1844              :                        "attributes not allowed");
    1845              :     }
    1846              : }
    1847              : 
    1848              : void
    1849       178593 : CfgStrip::visit (AST::TypeAlias &type_alias)
    1850              : {
    1851              :   // initial test based on outer attrs
    1852       178593 :   expand_cfg_attrs (type_alias.get_outer_attrs ());
    1853       178593 :   if (fails_cfg_with_expand (type_alias.get_outer_attrs ()))
    1854              :     {
    1855            0 :       type_alias.mark_for_strip ();
    1856            0 :       return;
    1857              :     }
    1858              : 
    1859       178593 :   AST::DefaultASTVisitor::visit (type_alias);
    1860              : 
    1861       178593 :   auto &type = type_alias.get_type_aliased ();
    1862       178593 :   if (type.is_marked_for_strip ())
    1863            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1864              : }
    1865              : 
    1866              : void
    1867       112306 : CfgStrip::visit (AST::StructStruct &struct_item)
    1868              : {
    1869              :   // initial test based on outer attrs
    1870       112306 :   expand_cfg_attrs (struct_item.get_outer_attrs ());
    1871       112306 :   if (fails_cfg_with_expand (struct_item.get_outer_attrs ()))
    1872              :     {
    1873            7 :       struct_item.mark_for_strip ();
    1874            7 :       return;
    1875              :     }
    1876              : 
    1877       112299 :   AST::DefaultASTVisitor::visit (struct_item);
    1878              : 
    1879              :   /* strip struct fields if required - this is presumably
    1880              :    * allowed by spec */
    1881       112299 :   maybe_strip_struct_fields (struct_item.get_fields ());
    1882              : }
    1883              : void
    1884         6070 : CfgStrip::visit (AST::TupleStruct &tuple_struct)
    1885              : {
    1886              :   // initial test based on outer attrs
    1887         6070 :   expand_cfg_attrs (tuple_struct.get_outer_attrs ());
    1888         6070 :   if (fails_cfg_with_expand (tuple_struct.get_outer_attrs ()))
    1889              :     {
    1890            0 :       tuple_struct.mark_for_strip ();
    1891            0 :       return;
    1892              :     }
    1893              : 
    1894         6070 :   AST::DefaultASTVisitor::visit (tuple_struct);
    1895              : 
    1896              :   /* strip struct fields if required - this is presumably
    1897              :    * allowed by spec */
    1898         6070 :   maybe_strip_tuple_fields (tuple_struct.get_fields ());
    1899              : }
    1900              : void
    1901         6358 : CfgStrip::visit (AST::EnumItem &item)
    1902              : {
    1903              :   // initial test based on outer attrs
    1904         6358 :   expand_cfg_attrs (item.get_outer_attrs ());
    1905         6358 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1906              :     {
    1907            0 :       item.mark_for_strip ();
    1908            0 :       return;
    1909              :     }
    1910              : }
    1911              : 
    1912              : void
    1913         4180 : CfgStrip::visit (AST::EnumItemTuple &item)
    1914              : {
    1915              :   // initial test based on outer attrs
    1916         4180 :   expand_cfg_attrs (item.get_outer_attrs ());
    1917         4180 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1918              :     {
    1919            0 :       item.mark_for_strip ();
    1920            0 :       return;
    1921              :     }
    1922              : 
    1923              :   /* strip item fields if required - this is presumably
    1924              :    * allowed by spec */
    1925         4180 :   maybe_strip_tuple_fields (item.get_tuple_fields ());
    1926              : }
    1927              : 
    1928              : void
    1929          440 : CfgStrip::visit (AST::EnumItemStruct &item)
    1930              : {
    1931              :   // initial test based on outer attrs
    1932          440 :   expand_cfg_attrs (item.get_outer_attrs ());
    1933          440 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1934              :     {
    1935            0 :       item.mark_for_strip ();
    1936            0 :       return;
    1937              :     }
    1938              : 
    1939              :   /* strip item fields if required - this is presumably
    1940              :    * allowed by spec */
    1941          440 :   maybe_strip_struct_fields (item.get_struct_fields ());
    1942              : }
    1943              : 
    1944              : void
    1945         1624 : CfgStrip::visit (AST::EnumItemDiscriminant &item)
    1946              : {
    1947              :   // initial test based on outer attrs
    1948         1624 :   expand_cfg_attrs (item.get_outer_attrs ());
    1949         1624 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1950              :     {
    1951            0 :       item.mark_for_strip ();
    1952            0 :       return;
    1953              :     }
    1954              : 
    1955         1624 :   AST::DefaultASTVisitor::visit (item);
    1956              :   /* strip any internal sub-expressions - expression itself isn't
    1957              :    * allowed to have external attributes in this position so can't be
    1958              :    * stripped. */
    1959         1624 :   auto &expr = item.get_expr ();
    1960         1624 :   if (expr.is_marked_for_strip ())
    1961            0 :     rust_error_at (expr.get_locus (),
    1962              :                    "cannot strip expression in this position - outer "
    1963              :                    "attributes not allowed");
    1964              : }
    1965              : void
    1966         2442 : CfgStrip::visit (AST::Enum &enum_item)
    1967              : {
    1968              :   // initial test based on outer attrs
    1969         2442 :   expand_cfg_attrs (enum_item.get_outer_attrs ());
    1970         2442 :   if (fails_cfg_with_expand (enum_item.get_outer_attrs ()))
    1971              :     {
    1972            0 :       enum_item.mark_for_strip ();
    1973            0 :       return;
    1974              :     }
    1975              : 
    1976         2442 :   AST::DefaultASTVisitor::visit (enum_item);
    1977              : 
    1978              :   /* strip enum fields if required - this is presumably
    1979              :    * allowed by spec */
    1980         2442 :   maybe_strip_pointer_allow_strip (enum_item.get_variants ());
    1981              : }
    1982              : void
    1983          302 : CfgStrip::visit (AST::Union &union_item)
    1984              : {
    1985              :   // initial test based on outer attrs
    1986          302 :   expand_cfg_attrs (union_item.get_outer_attrs ());
    1987          302 :   if (fails_cfg_with_expand (union_item.get_outer_attrs ()))
    1988              :     {
    1989            0 :       union_item.mark_for_strip ();
    1990            0 :       return;
    1991              :     }
    1992              : 
    1993          302 :   AST::DefaultASTVisitor::visit (union_item);
    1994              : 
    1995              :   /* strip union fields if required - this is presumably
    1996              :    * allowed by spec */
    1997          302 :   maybe_strip_struct_fields (union_item.get_variants ());
    1998              : }
    1999              : void
    2000        33636 : CfgStrip::visit (AST::ConstantItem &const_item)
    2001              : {
    2002              :   // initial test based on outer attrs
    2003        33636 :   expand_cfg_attrs (const_item.get_outer_attrs ());
    2004        33636 :   if (fails_cfg_with_expand (const_item.get_outer_attrs ()))
    2005              :     {
    2006            1 :       const_item.mark_for_strip ();
    2007            1 :       return;
    2008              :     }
    2009              : 
    2010        33635 :   AST::DefaultASTVisitor::visit (const_item);
    2011              : 
    2012              :   // strip any sub-types
    2013        33635 :   auto &type = const_item.get_type ();
    2014        33635 :   if (type.is_marked_for_strip ())
    2015            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2016              : 
    2017              :   /* strip any internal sub-expressions - expression itself isn't
    2018              :    * allowed to have external attributes in this position so can't be
    2019              :    * stripped. */
    2020        33635 :   if (const_item.has_expr ())
    2021              :     {
    2022        32159 :       auto &expr = const_item.get_expr ();
    2023        32159 :       if (expr.is_marked_for_strip ())
    2024            0 :         rust_error_at (expr.get_locus (),
    2025              :                        "cannot strip expression in this position - outer "
    2026              :                        "attributes not allowed");
    2027              :     }
    2028              : }
    2029              : void
    2030         1359 : CfgStrip::visit (AST::StaticItem &static_item)
    2031              : {
    2032              :   // initial test based on outer attrs
    2033         1359 :   expand_cfg_attrs (static_item.get_outer_attrs ());
    2034         1359 :   if (fails_cfg_with_expand (static_item.get_outer_attrs ()))
    2035              :     {
    2036            0 :       static_item.mark_for_strip ();
    2037            0 :       return;
    2038              :     }
    2039              : 
    2040         1359 :   AST::DefaultASTVisitor::visit (static_item);
    2041              : 
    2042              :   // strip any sub-types
    2043         1359 :   auto &type = static_item.get_type ();
    2044              : 
    2045         1359 :   if (type.is_marked_for_strip ())
    2046            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2047              : 
    2048              :   /* strip any internal sub-expressions - expression itself isn't
    2049              :    * allowed to have external attributes in this position so can't be
    2050              :    * stripped. */
    2051         1359 :   auto &expr = static_item.get_expr ();
    2052         1359 :   if (expr.is_marked_for_strip ())
    2053            0 :     rust_error_at (expr.get_locus (),
    2054              :                    "cannot strip expression in this position - outer "
    2055              :                    "attributes not allowed");
    2056              : }
    2057              : 
    2058              : void
    2059         6288 : CfgStrip::visit (AST::TraitItemType &item)
    2060              : {
    2061              :   // initial test based on outer attrs
    2062         6288 :   expand_cfg_attrs (item.get_outer_attrs ());
    2063         6288 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2064              :     {
    2065            0 :       item.mark_for_strip ();
    2066            0 :       return;
    2067              :     }
    2068              : 
    2069         6288 :   AST::DefaultASTVisitor::visit (item);
    2070              : }
    2071              : 
    2072              : void
    2073        13858 : CfgStrip::visit (AST::Trait &trait)
    2074              : {
    2075              :   // initial strip test based on outer attrs
    2076        13858 :   expand_cfg_attrs (trait.get_outer_attrs ());
    2077        13858 :   if (fails_cfg_with_expand (trait.get_outer_attrs ()))
    2078              :     {
    2079            1 :       trait.mark_for_strip ();
    2080            1 :       return;
    2081              :     }
    2082              : 
    2083              :   // strip test based on inner attrs
    2084        13857 :   expand_cfg_attrs (trait.get_inner_attrs ());
    2085        13857 :   if (fails_cfg_with_expand (trait.get_inner_attrs ()))
    2086              :     {
    2087            0 :       trait.mark_for_strip ();
    2088            0 :       return;
    2089              :     }
    2090              : 
    2091        13857 :   AST::DefaultASTVisitor::visit (trait);
    2092              : 
    2093        13857 :   maybe_strip_pointer_allow_strip (trait.get_trait_items ());
    2094              : }
    2095              : 
    2096              : void
    2097        12370 : CfgStrip::visit (AST::InherentImpl &impl)
    2098              : {
    2099              :   // initial strip test based on outer attrs
    2100        12370 :   expand_cfg_attrs (impl.get_outer_attrs ());
    2101        12370 :   if (fails_cfg_with_expand (impl.get_outer_attrs ()))
    2102              :     {
    2103            8 :       impl.mark_for_strip ();
    2104            8 :       return;
    2105              :     }
    2106              : 
    2107              :   // strip test based on inner attrs
    2108        12362 :   expand_cfg_attrs (impl.get_inner_attrs ());
    2109        12362 :   if (fails_cfg_with_expand (impl.get_inner_attrs ()))
    2110              :     {
    2111            0 :       impl.mark_for_strip ();
    2112            0 :       return;
    2113              :     }
    2114              : 
    2115        12362 :   AST::DefaultASTVisitor::visit (impl);
    2116              : 
    2117        12362 :   auto &type = impl.get_type ();
    2118              : 
    2119        12362 :   if (type.is_marked_for_strip ())
    2120            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2121              : 
    2122        12362 :   maybe_strip_pointer_allow_strip (impl.get_impl_items ());
    2123              : }
    2124              : 
    2125              : void
    2126       233915 : CfgStrip::visit (AST::TraitImpl &impl)
    2127              : {
    2128              :   // initial strip test based on outer attrs
    2129       233915 :   expand_cfg_attrs (impl.get_outer_attrs ());
    2130       233915 :   if (fails_cfg_with_expand (impl.get_outer_attrs ()))
    2131              :     {
    2132           11 :       impl.mark_for_strip ();
    2133           11 :       return;
    2134              :     }
    2135              : 
    2136              :   // strip test based on inner attrs
    2137       233904 :   expand_cfg_attrs (impl.get_inner_attrs ());
    2138       233904 :   if (fails_cfg_with_expand (impl.get_inner_attrs ()))
    2139              :     {
    2140            0 :       impl.mark_for_strip ();
    2141            0 :       return;
    2142              :     }
    2143              : 
    2144       233904 :   AST::DefaultASTVisitor::visit (impl);
    2145              : 
    2146       233904 :   auto &type = impl.get_type ();
    2147       233904 :   if (type.is_marked_for_strip ())
    2148            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2149              : 
    2150       233904 :   auto &trait_path = impl.get_trait_path ();
    2151       233904 :   visit (trait_path);
    2152       233904 :   if (trait_path.is_marked_for_strip ())
    2153            0 :     rust_error_at (trait_path.get_locus (),
    2154              :                    "cannot strip typepath in this position");
    2155              : 
    2156       233904 :   maybe_strip_pointer_allow_strip (impl.get_impl_items ());
    2157              : }
    2158              : 
    2159              : void
    2160           39 : CfgStrip::visit (AST::ExternalTypeItem &item)
    2161              : {
    2162           39 :   expand_cfg_attrs (item.get_outer_attrs ());
    2163              : 
    2164           39 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2165            0 :     item.mark_for_strip ();
    2166              : 
    2167              :   // TODO: Can we do anything like expand a macro here?
    2168              :   // extern "C" { type ffi_ty!(); }
    2169              :   // ?
    2170           39 : }
    2171              : 
    2172              : void
    2173            2 : CfgStrip::visit (AST::ExternalStaticItem &item)
    2174              : {
    2175              :   // strip test based on outer attrs
    2176            2 :   expand_cfg_attrs (item.get_outer_attrs ());
    2177            2 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2178              :     {
    2179            0 :       item.mark_for_strip ();
    2180            0 :       return;
    2181              :     }
    2182              : 
    2183            2 :   AST::DefaultASTVisitor::visit (item);
    2184              : 
    2185            2 :   auto &type = item.get_type ();
    2186            2 :   if (type.is_marked_for_strip ())
    2187            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2188              : }
    2189              : 
    2190              : void
    2191         5447 : CfgStrip::visit (AST::ExternBlock &block)
    2192              : {
    2193              :   // initial strip test based on outer attrs
    2194         5447 :   expand_cfg_attrs (block.get_outer_attrs ());
    2195         5447 :   if (fails_cfg_with_expand (block.get_outer_attrs ()))
    2196              :     {
    2197            0 :       block.mark_for_strip ();
    2198            0 :       return;
    2199              :     }
    2200              : 
    2201              :   // strip test based on inner attrs
    2202         5447 :   expand_cfg_attrs (block.get_inner_attrs ());
    2203         5447 :   if (fails_cfg_with_expand (block.get_inner_attrs ()))
    2204              :     {
    2205            0 :       block.mark_for_strip ();
    2206            0 :       return;
    2207              :     }
    2208              : 
    2209         5447 :   maybe_strip_pointer_allow_strip (block.get_extern_items ());
    2210              : }
    2211              : 
    2212              : void
    2213        47524 : CfgStrip::visit (AST::MacroRulesDefinition &rules_def)
    2214              : {
    2215              :   // initial strip test based on outer attrs
    2216        47524 :   expand_cfg_attrs (rules_def.get_outer_attrs ());
    2217        47524 :   if (fails_cfg_with_expand (rules_def.get_outer_attrs ()))
    2218              :     {
    2219            2 :       rules_def.mark_for_strip ();
    2220            2 :       return;
    2221              :     }
    2222              : }
    2223              : 
    2224              : void
    2225      2383817 : CfgStrip::visit (AST::IdentifierPattern &pattern)
    2226              : {
    2227              :   // can only strip sub-patterns of the inner pattern to bind
    2228      2383817 :   if (!pattern.has_subpattern ())
    2229              :     return;
    2230              : 
    2231         1272 :   AST::DefaultASTVisitor::visit (pattern);
    2232              : 
    2233         1272 :   auto &sub_pattern = pattern.get_subpattern ();
    2234         1272 :   if (sub_pattern.is_marked_for_strip ())
    2235            0 :     rust_error_at (sub_pattern.get_locus (),
    2236              :                    "cannot strip pattern in this position");
    2237              : }
    2238              : 
    2239              : void
    2240           42 : CfgStrip::visit (AST::RangePatternBoundPath &bound)
    2241              : {
    2242              :   // can expand path, but not strip it directly
    2243           42 :   auto &path = bound.get_path ();
    2244           42 :   visit (path);
    2245           42 :   if (path.is_marked_for_strip ())
    2246            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2247           42 : }
    2248              : 
    2249              : void
    2250            0 : CfgStrip::visit (AST::RangePatternBoundQualPath &bound)
    2251              : {
    2252              :   // can expand path, but not strip it directly
    2253            0 :   auto &path = bound.get_qualified_path ();
    2254            0 :   visit (path);
    2255            0 :   if (path.is_marked_for_strip ())
    2256            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2257            0 : }
    2258              : 
    2259              : void
    2260        21572 : CfgStrip::visit (AST::ReferencePattern &pattern)
    2261              : {
    2262        21572 :   AST::DefaultASTVisitor::visit (pattern);
    2263              : 
    2264        21572 :   auto &sub_pattern = pattern.get_referenced_pattern ();
    2265        21572 :   if (sub_pattern.is_marked_for_strip ())
    2266            0 :     rust_error_at (sub_pattern.get_locus (),
    2267              :                    "cannot strip pattern in this position");
    2268        21572 : }
    2269              : void
    2270           78 : CfgStrip::visit (AST::StructPatternFieldTuplePat &field)
    2271              : {
    2272              :   // initial strip test based on outer attrs
    2273           78 :   expand_cfg_attrs (field.get_outer_attrs ());
    2274           78 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2275              :     {
    2276            0 :       field.mark_for_strip ();
    2277            0 :       return;
    2278              :     }
    2279              : 
    2280           78 :   AST::DefaultASTVisitor::visit (field);
    2281              : 
    2282              :   // strip sub-patterns (can't strip top-level pattern)
    2283           78 :   auto &sub_pattern = field.get_index_pattern ();
    2284           78 :   if (sub_pattern.is_marked_for_strip ())
    2285            0 :     rust_error_at (sub_pattern.get_locus (),
    2286              :                    "cannot strip pattern in this position");
    2287              : }
    2288              : 
    2289              : void
    2290         3456 : CfgStrip::visit (AST::StructPatternFieldIdentPat &field)
    2291              : {
    2292              :   // initial strip test based on outer attrs
    2293         3456 :   expand_cfg_attrs (field.get_outer_attrs ());
    2294         3456 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2295              :     {
    2296            0 :       field.mark_for_strip ();
    2297            0 :       return;
    2298              :     }
    2299              : 
    2300         3456 :   AST::DefaultASTVisitor::visit (field);
    2301              :   // strip sub-patterns (can't strip top-level pattern)
    2302         3456 :   auto &sub_pattern = field.get_ident_pattern ();
    2303         3456 :   if (sub_pattern.is_marked_for_strip ())
    2304            0 :     rust_error_at (sub_pattern.get_locus (),
    2305              :                    "cannot strip pattern in this position");
    2306              : }
    2307              : void
    2308         1676 : CfgStrip::visit (AST::StructPatternFieldIdent &field)
    2309              : {
    2310              :   // initial strip test based on outer attrs
    2311         1676 :   expand_cfg_attrs (field.get_outer_attrs ());
    2312         1676 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2313              :     {
    2314            0 :       field.mark_for_strip ();
    2315            0 :       return;
    2316              :     }
    2317              : }
    2318              : 
    2319              : void
    2320         3704 : CfgStrip::visit (AST::StructPattern &pattern)
    2321              : {
    2322              :   // expand (but don't strip) path
    2323         3704 :   auto &path = pattern.get_path ();
    2324         3704 :   visit (path);
    2325         3704 :   if (path.is_marked_for_strip ())
    2326            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2327              : 
    2328              :   /* TODO: apparently struct pattern fields can have outer attrs. so can they
    2329              :    * be stripped? */
    2330         3704 :   if (!pattern.has_struct_pattern_elems ())
    2331              :     return;
    2332              : 
    2333         3702 :   auto &elems = pattern.get_struct_pattern_elems ();
    2334              : 
    2335              :   // assuming you can strip struct pattern fields
    2336         3702 :   maybe_strip_pointer_allow_strip (elems.get_struct_pattern_fields ());
    2337              : 
    2338              :   // assuming you can strip the ".." part
    2339         3702 :   if (elems.has_rest ())
    2340              :     {
    2341           80 :       expand_cfg_attrs (elems.get_etc_outer_attrs ());
    2342           80 :       if (fails_cfg_with_expand (elems.get_etc_outer_attrs ()))
    2343            0 :         elems.strip_etc ();
    2344              :     }
    2345              : }
    2346              : 
    2347              : void
    2348        80918 : CfgStrip::visit (AST::TupleStructItemsNoRest &tuple_items)
    2349              : {
    2350        80918 :   AST::DefaultASTVisitor::visit (tuple_items);
    2351              :   // can't strip individual patterns, only sub-patterns
    2352       164278 :   for (auto &pattern : tuple_items.get_patterns ())
    2353              :     {
    2354        83360 :       if (pattern->is_marked_for_strip ())
    2355            0 :         rust_error_at (pattern->get_locus (),
    2356              :                        "cannot strip pattern in this position");
    2357              :       // TODO: quit stripping now? or keep going?
    2358              :     }
    2359        80918 : }
    2360              : void
    2361          802 : CfgStrip::visit (AST::TupleStructItemsHasRest &tuple_items)
    2362              : {
    2363          802 :   AST::DefaultASTVisitor::visit (tuple_items);
    2364              :   // can't strip individual patterns, only sub-patterns
    2365          944 :   for (auto &lower_pattern : tuple_items.get_lower_patterns ())
    2366              :     {
    2367          142 :       if (lower_pattern->is_marked_for_strip ())
    2368            0 :         rust_error_at (lower_pattern->get_locus (),
    2369              :                        "cannot strip pattern in this position");
    2370              :       // TODO: quit stripping now? or keep going?
    2371              :     }
    2372          884 :   for (auto &upper_pattern : tuple_items.get_upper_patterns ())
    2373              :     {
    2374           82 :       if (upper_pattern->is_marked_for_strip ())
    2375            0 :         rust_error_at (upper_pattern->get_locus (),
    2376              :                        "cannot strip pattern in this position");
    2377              :       // TODO: quit stripping now? or keep going?
    2378              :     }
    2379          802 : }
    2380              : 
    2381              : void
    2382        81720 : CfgStrip::visit (AST::TupleStructPattern &pattern)
    2383              : {
    2384              :   // expand (but don't strip) path
    2385        81720 :   auto &path = pattern.get_path ();
    2386        81720 :   visit (path);
    2387        81720 :   if (path.is_marked_for_strip ())
    2388            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2389              : 
    2390        81720 :   AST::DefaultASTVisitor::visit (pattern);
    2391        81720 : }
    2392              : 
    2393              : void
    2394       215781 : CfgStrip::visit (AST::TuplePatternItemsNoRest &tuple_items)
    2395              : {
    2396       215781 :   AST::DefaultASTVisitor::visit (tuple_items);
    2397              : 
    2398              :   // can't strip individual patterns, only sub-patterns
    2399       700429 :   for (auto &pattern : tuple_items.get_patterns ())
    2400              :     {
    2401       484648 :       if (pattern->is_marked_for_strip ())
    2402            0 :         rust_error_at (pattern->get_locus (),
    2403              :                        "cannot strip pattern in this position");
    2404              :       // TODO: quit stripping now? or keep going?
    2405              :     }
    2406       215781 : }
    2407              : 
    2408              : void
    2409          144 : CfgStrip::visit (AST::TuplePatternItemsHasRest &tuple_items)
    2410              : {
    2411          144 :   AST::DefaultASTVisitor::visit (tuple_items);
    2412              : 
    2413              :   // can't strip individual patterns, only sub-patterns
    2414          266 :   for (auto &lower_pattern : tuple_items.get_lower_patterns ())
    2415              :     {
    2416          122 :       if (lower_pattern->is_marked_for_strip ())
    2417            0 :         rust_error_at (lower_pattern->get_locus (),
    2418              :                        "cannot strip pattern in this position");
    2419              :       // TODO: quit stripping now? or keep going?
    2420              :     }
    2421          272 :   for (auto &upper_pattern : tuple_items.get_upper_patterns ())
    2422              :     {
    2423          128 :       if (upper_pattern->is_marked_for_strip ())
    2424            0 :         rust_error_at (upper_pattern->get_locus (),
    2425              :                        "cannot strip pattern in this position");
    2426              :       // TODO: quit stripping now? or keep going?
    2427              :     }
    2428          144 : }
    2429              : 
    2430              : void
    2431          192 : CfgStrip::visit (AST::GroupedPattern &pattern)
    2432              : {
    2433          192 :   AST::DefaultASTVisitor::visit (pattern);
    2434              :   // can't strip inner pattern, only sub-patterns
    2435          192 :   auto &pattern_in_parens = pattern.get_pattern_in_parens ();
    2436              : 
    2437          192 :   if (pattern_in_parens.is_marked_for_strip ())
    2438            0 :     rust_error_at (pattern_in_parens.get_locus (),
    2439              :                    "cannot strip pattern in this position");
    2440          192 : }
    2441              : 
    2442              : void
    2443         1442 : CfgStrip::visit (AST::SlicePattern &pattern)
    2444              : {
    2445         1442 :   AST::DefaultASTVisitor::visit (pattern);
    2446              :   // can't strip individual patterns, only sub-patterns
    2447         4442 :   for (auto &sub_pat : pattern.get_patterns ())
    2448              :     {
    2449         3000 :       if (sub_pat->is_marked_for_strip ())
    2450            0 :         rust_error_at (sub_pat->get_locus (),
    2451              :                        "cannot strip pattern in this position");
    2452              :     }
    2453         1442 : }
    2454              : 
    2455              : void
    2456         3964 : CfgStrip::visit (AST::AltPattern &pattern)
    2457              : {
    2458         3964 :   AST::DefaultASTVisitor::visit (pattern);
    2459              :   // can't strip individual patterns, only sub-patterns
    2460        14339 :   for (auto &alt : pattern.get_alts ())
    2461              :     {
    2462        10375 :       if (alt->is_marked_for_strip ())
    2463            0 :         rust_error_at (alt->get_locus (),
    2464              :                        "cannot strip pattern in this position");
    2465              :       // TODO: quit stripping now? or keep going?
    2466              :     }
    2467         3964 : }
    2468              : 
    2469              : void
    2470       506456 : CfgStrip::visit (AST::LetStmt &stmt)
    2471              : {
    2472              :   // initial strip test based on outer attrs
    2473       506456 :   expand_cfg_attrs (stmt.get_outer_attrs ());
    2474       506456 :   if (fails_cfg_with_expand (stmt.get_outer_attrs ()))
    2475              :     {
    2476            0 :       stmt.mark_for_strip ();
    2477            0 :       return;
    2478              :     }
    2479              : 
    2480       506456 :   AST::DefaultASTVisitor::visit (stmt);
    2481              :   // can't strip pattern, but call for sub-patterns
    2482       506456 :   auto &pattern = stmt.get_pattern ();
    2483       506456 :   if (pattern.is_marked_for_strip ())
    2484            0 :     rust_error_at (pattern.get_locus (),
    2485              :                    "cannot strip pattern in this position");
    2486              : 
    2487              :   // similar for type
    2488       506456 :   if (stmt.has_type ())
    2489              :     {
    2490        55170 :       auto &type = stmt.get_type ();
    2491              : 
    2492        55170 :       if (type.is_marked_for_strip ())
    2493            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2494              :     }
    2495              : 
    2496              :   /* strip any internal sub-expressions - expression itself isn't
    2497              :    * allowed to have external attributes in this position so can't be
    2498              :    * stripped */
    2499       506456 :   if (stmt.has_init_expr ())
    2500              :     {
    2501       488520 :       auto &init_expr = stmt.get_init_expr ();
    2502              : 
    2503       488520 :       if (init_expr.is_marked_for_strip ())
    2504            0 :         rust_error_at (init_expr.get_locus (),
    2505              :                        "cannot strip expression in this position - outer "
    2506              :                        "attributes not allowed");
    2507              :     }
    2508              : }
    2509              : 
    2510              : void
    2511       854056 : CfgStrip::visit (AST::ExprStmt &stmt)
    2512              : {
    2513              :   // outer attributes associated with expr, so rely on expr
    2514              : 
    2515              :   // guard - should prevent null pointer expr
    2516       854056 :   if (stmt.is_marked_for_strip ())
    2517              :     return;
    2518              : 
    2519       854056 :   AST::DefaultASTVisitor::visit (stmt);
    2520              :   // strip if expr is to be stripped
    2521       854056 :   auto &expr = stmt.get_expr ();
    2522       854056 :   if (expr.is_marked_for_strip ())
    2523              :     {
    2524           46 :       stmt.mark_for_strip ();
    2525           46 :       return;
    2526              :     }
    2527              : }
    2528              : 
    2529              : void
    2530       201136 : CfgStrip::visit (AST::TraitBound &bound)
    2531              : {
    2532              :   // nothing in for lifetimes to strip
    2533              : 
    2534              :   // expand but don't strip type path
    2535       201136 :   auto &path = bound.get_type_path ();
    2536       201136 :   visit (path);
    2537       201136 :   if (path.is_marked_for_strip ())
    2538            0 :     rust_error_at (path.get_locus (),
    2539              :                    "cannot strip type path in this position");
    2540       201136 : }
    2541              : 
    2542              : void
    2543          722 : CfgStrip::visit (AST::ParenthesisedType &type)
    2544              : {
    2545          722 :   AST::DefaultASTVisitor::visit (type);
    2546              :   // expand but don't strip inner type
    2547          722 :   auto &inner_type = type.get_type_in_parens ();
    2548          722 :   if (inner_type->is_marked_for_strip ())
    2549            0 :     rust_error_at (inner_type->get_locus (),
    2550              :                    "cannot strip type in this position");
    2551          722 : }
    2552              : 
    2553              : void
    2554        81498 : CfgStrip::visit (AST::TupleType &type)
    2555              : {
    2556        81498 :   AST::DefaultASTVisitor::visit (type);
    2557              :   // TODO: assuming that types can't be stripped as types don't have outer
    2558              :   // attributes
    2559       256842 :   for (auto &elem_type : type.get_elems ())
    2560              :     {
    2561       175344 :       if (elem_type->is_marked_for_strip ())
    2562            0 :         rust_error_at (elem_type->get_locus (),
    2563              :                        "cannot strip type in this position");
    2564              :     }
    2565        81498 : }
    2566              : 
    2567              : void
    2568       172132 : CfgStrip::visit (AST::RawPointerType &type)
    2569              : {
    2570       172132 :   AST::DefaultASTVisitor::visit (type);
    2571              :   // expand but don't strip type pointed to
    2572       172132 :   auto &pointed_type = type.get_type_pointed_to ();
    2573       172132 :   if (pointed_type.is_marked_for_strip ())
    2574            0 :     rust_error_at (pointed_type.get_locus (),
    2575              :                    "cannot strip type in this position");
    2576       172132 : }
    2577              : 
    2578              : void
    2579       742533 : CfgStrip::visit (AST::ReferenceType &type)
    2580              : {
    2581       742533 :   AST::DefaultASTVisitor::visit (type);
    2582              :   // expand but don't strip type referenced
    2583       742533 :   auto &referenced_type = type.get_type_referenced ();
    2584       742533 :   if (referenced_type.is_marked_for_strip ())
    2585            0 :     rust_error_at (referenced_type.get_locus (),
    2586              :                    "cannot strip type in this position");
    2587       742533 : }
    2588              : 
    2589              : void
    2590        27137 : CfgStrip::visit (AST::ArrayType &type)
    2591              : {
    2592        27137 :   AST::DefaultASTVisitor::visit (type);
    2593              :   // expand but don't strip type referenced
    2594        27137 :   auto &base_type = type.get_elem_type ();
    2595        27137 :   if (base_type.is_marked_for_strip ())
    2596            0 :     rust_error_at (base_type.get_locus (),
    2597              :                    "cannot strip type in this position");
    2598              : 
    2599              :   // same for expression
    2600        27137 :   auto &size_expr = type.get_size_expr ();
    2601        27137 :   if (size_expr.is_marked_for_strip ())
    2602            0 :     rust_error_at (size_expr.get_locus (),
    2603              :                    "cannot strip expression in this position");
    2604        27137 : }
    2605              : void
    2606        54965 : CfgStrip::visit (AST::SliceType &type)
    2607              : {
    2608        54965 :   AST::DefaultASTVisitor::visit (type);
    2609              :   // expand but don't strip elem type
    2610        54965 :   auto &elem_type = type.get_elem_type ();
    2611        54965 :   if (elem_type.is_marked_for_strip ())
    2612            0 :     rust_error_at (elem_type.get_locus (),
    2613              :                    "cannot strip type in this position");
    2614        54965 : }
    2615              : 
    2616              : void
    2617        19150 : CfgStrip::visit (AST::BareFunctionType &type)
    2618              : {
    2619              :   // seem to be no generics
    2620        19150 :   AST::DefaultASTVisitor::visit (type);
    2621              : 
    2622              :   // presumably function params can be stripped
    2623        19150 :   auto &params = type.get_function_params ();
    2624       129102 :   for (auto it = params.begin (); it != params.end ();)
    2625              :     {
    2626       109952 :       auto &param = *it;
    2627              : 
    2628       109952 :       auto &param_attrs = param.get_outer_attrs ();
    2629       109952 :       expand_cfg_attrs (param_attrs);
    2630       109952 :       if (fails_cfg_with_expand (param_attrs))
    2631              :         {
    2632            0 :           it = params.erase (it);
    2633            0 :           continue;
    2634              :         }
    2635              : 
    2636       109952 :       auto &type = param.get_type ();
    2637       109952 :       if (type.is_marked_for_strip ())
    2638            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2639              : 
    2640              :       // increment if nothing else happens
    2641       109952 :       ++it;
    2642              :     }
    2643              : 
    2644              :   /* TODO: assuming that variadic nature cannot be stripped. If this
    2645              :    * is not true, then have code here to do so. */
    2646              : 
    2647        19150 :   if (type.has_return_type ())
    2648              :     {
    2649              :       // FIXME: Can we have type expansion in this position?
    2650              :       // In that case, we need to handle AST::TypeNoBounds on top of just
    2651              :       // AST::Types
    2652        18298 :       auto &return_type = type.get_return_type ();
    2653        18298 :       if (return_type.is_marked_for_strip ())
    2654            0 :         rust_error_at (return_type.get_locus (),
    2655              :                        "cannot strip type in this position");
    2656              :     }
    2657              : 
    2658              :   // no where clause, apparently
    2659        19150 : }
    2660              : 
    2661              : void
    2662       585798 : CfgStrip::visit (AST::SelfParam &param)
    2663              : {
    2664       585798 :   AST::DefaultASTVisitor::visit (param);
    2665              : 
    2666       585798 :   if (param.has_type ())
    2667              :     {
    2668          984 :       auto &type = param.get_type ();
    2669          984 :       if (type.is_marked_for_strip ())
    2670            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2671              :     }
    2672              :   /* TODO: maybe check for invariants being violated - e.g. both type and
    2673              :    * lifetime? */
    2674       585798 : }
    2675              : 
    2676              : } // 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.