LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-cfg-strip.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 72.4 % 1161 840
Test Date: 2026-06-20 15:32:29 Functions: 95.1 % 122 116
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-cfg-strip.h"
      20              : #include "rust-ast-full.h"
      21              : #include "rust-ast-visitor.h"
      22              : #include "rust-path.h"
      23              : #include "rust-session-manager.h"
      24              : #include "rust-attribute-values.h"
      25              : #include "rust-macro-expand.h"
      26              : 
      27              : namespace Rust {
      28              : 
      29              : /**
      30              :  * Determines whether any cfg predicate is false and hence item with attributes
      31              :  * should be stripped. Will expand attributes as well.
      32              :  */
      33              : bool
      34      1877865 : CfgStrip::fails_cfg_with_expand (AST::AttrVec &attrs) const
      35              : {
      36      1877865 :   auto &session = Session::get_instance ();
      37              : 
      38              :   // TODO: maybe have something that strips cfg attributes that evaluate true?
      39      1979849 :   for (auto &attr : attrs)
      40              :     {
      41       102098 :       if (attr.get_path () == Values::Attributes::CFG)
      42              :         {
      43         2117 :           if (!attr.is_parsed_to_meta_item ())
      44          480 :             attr.parse_attr_to_meta_item ();
      45              : 
      46              :           // DEBUG
      47         2117 :           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         2116 :             rust_debug ("attr has been successfully parsed to meta item, "
      52              :                         "right before cfg predicate check");
      53              : 
      54         2117 :           if (!attr.check_cfg_predicate (session))
      55              :             {
      56              :               // DEBUG
      57          113 :               rust_debug (
      58              :                 "cfg predicate failed for attribute: \033[0;31m'%s'\033[0m",
      59              :                 attr.as_string ().c_str ());
      60              : 
      61          113 :               return true;
      62              :             }
      63              :           else
      64              :             {
      65              :               // DEBUG
      66         2004 :               rust_debug ("cfg predicate succeeded for attribute: "
      67              :                           "\033[0;31m'%s'\033[0m",
      68              :                           attr.as_string ().c_str ());
      69              :             }
      70              :         }
      71        99981 :       else if (!expansion_cfg.should_test
      72       199962 :                && 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      1882561 : expand_cfg_attrs (AST::AttrVec &attrs)
      83              : {
      84      1882561 :   auto &session = Session::get_instance ();
      85              : 
      86      1996587 :   for (std::size_t i = 0; i < attrs.size (); i++)
      87              :     {
      88       114026 :       auto &attr = attrs[i];
      89       114026 :       if (attr.get_path () == Values::Attributes::CFG_ATTR)
      90              :         {
      91           17 :           if (!attr.is_parsed_to_meta_item ())
      92            3 :             attr.parse_attr_to_meta_item ();
      93              : 
      94           17 :           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            9 :               AST::AttrVec new_attrs = attr.separate_cfg_attrs ();
     101              : 
     102              :               // remove attr from vector
     103            9 :               attrs.erase (attrs.begin () + i);
     104              : 
     105              :               // add new attrs to vector
     106            9 :               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            9 :               i--;
     115            9 :             }
     116              :           else
     117              :             {
     118              :               // Key has not been found, remove the whole attribute
     119            8 :               attrs.erase (attrs.begin () + i);
     120            8 :               i--;
     121              :             }
     122              : 
     123              :           /* do something - if feature (first token in tree) is in fact enabled,
     124              :            * make tokens listed afterwards into attributes. i.e.: for
     125              :            * [cfg_attr(feature = "wow", wow1, wow2)], if "wow" is true, then add
     126              :            * attributes [wow1] and [wow2] to attribute list. This can also be
     127              :            * recursive, so check for expanded attributes being recursive and
     128              :            * possibly recursively call the expand_attrs? */
     129              :         }
     130              :     }
     131      1882561 :   attrs.shrink_to_fit ();
     132      1882561 : }
     133              : 
     134              : void
     135        10802 : CfgStrip::go (AST::Crate &crate)
     136              : {
     137        10802 :   visit (crate);
     138        10802 : }
     139              : 
     140              : void
     141        10802 : CfgStrip::visit (AST::Crate &crate)
     142              : {
     143              :   // expand crate cfg_attr attributes
     144        10802 :   expand_cfg_attrs (crate.inner_attrs);
     145              : 
     146        10802 :   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        10802 :   auto &items = crate.items;
     154              : 
     155        10802 :   AST::DefaultASTVisitor::visit (crate);
     156        57080 :   for (auto it = items.begin (); it != items.end ();)
     157              :     {
     158        46278 :       auto &item = *it;
     159        46278 :       if (item->is_marked_for_strip ())
     160           19 :         it = items.erase (it);
     161              :       else
     162        46259 :         it++;
     163              :     }
     164              :   // expand module attributes?
     165        10802 : }
     166              : 
     167              : // Visitor used to expand attributes.
     168              : void
     169         4785 : CfgStrip::maybe_strip_struct_fields (std::vector<AST::StructField> &fields)
     170              : {
     171        10587 :   for (auto it = fields.begin (); it != fields.end ();)
     172              :     {
     173         5802 :       auto &field = *it;
     174              : 
     175         5802 :       auto &field_attrs = field.get_outer_attrs ();
     176         5802 :       expand_cfg_attrs (field_attrs);
     177         5802 :       if (fails_cfg_with_expand (field_attrs))
     178              :         {
     179            1 :           it = fields.erase (it);
     180            1 :           continue;
     181              :         }
     182              : 
     183              :       // expand sub-types of type, but can't strip type itself
     184         5801 :       auto &type = field.get_field_type ();
     185         5801 :       type.accept_vis (*this);
     186              : 
     187         5801 :       if (type.is_marked_for_strip ())
     188            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
     189              : 
     190              :       // if nothing else happens, increment
     191         5801 :       ++it;
     192              :     }
     193         4785 : }
     194              : 
     195              : void
     196         5764 : CfgStrip::maybe_strip_struct_expr_fields (
     197              :   std::vector<std::unique_ptr<AST::StructExprField>> &fields)
     198              : {
     199        16057 :   for (auto it = fields.begin (); it != fields.end ();)
     200              :     {
     201        10293 :       auto &field = *it;
     202              : 
     203        10293 :       auto &field_attrs = field->get_outer_attrs ();
     204        10293 :       expand_cfg_attrs (field_attrs);
     205        10293 :       if (fails_cfg_with_expand (field_attrs))
     206              :         {
     207            1 :           it = fields.erase (it);
     208            1 :           continue;
     209              :         }
     210              : 
     211        10292 :       ++it;
     212              :     }
     213         5764 : }
     214              : 
     215              : void
     216         4730 : CfgStrip::maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields)
     217              : {
     218        12255 :   for (auto it = fields.begin (); it != fields.end ();)
     219              :     {
     220         7525 :       auto &field = *it;
     221              : 
     222         7525 :       auto &field_attrs = field.get_outer_attrs ();
     223         7525 :       expand_cfg_attrs (field_attrs);
     224         7525 :       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         7525 :       auto &type = field.get_field_type ();
     232         7525 :       type.accept_vis (*this);
     233         7525 :       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         7525 :       ++it;
     238              :     }
     239         4730 : }
     240              : 
     241              : void
     242        68564 : CfgStrip::maybe_strip_function_params (
     243              :   std::vector<std::unique_ptr<AST::Param>> &params)
     244              : {
     245       153317 :   for (auto it = params.begin (); it != params.end ();)
     246              :     {
     247        84753 :       if (!(*it)->is_self () && !(*it)->is_variadic ())
     248              :         {
     249        43332 :           auto param = static_cast<AST::FunctionParam *> (it->get ());
     250              : 
     251        43332 :           auto &param_attrs = param->get_outer_attrs ();
     252        43332 :           expand_cfg_attrs (param_attrs);
     253        43332 :           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        43332 :           auto &pattern = param->get_pattern ();
     261        43332 :           pattern.accept_vis (*this);
     262        43332 :           if (pattern.is_marked_for_strip ())
     263            0 :             rust_error_at (pattern.get_locus (),
     264              :                            "cannot strip pattern in this position");
     265              : 
     266        43332 :           auto &type = param->get_type ();
     267        43332 :           type.accept_vis (*this);
     268              : 
     269        43332 :           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        84753 :       ++it;
     275              :     }
     276        68564 : }
     277              : 
     278              : void
     279        20645 : 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        42028 :   for (auto &arg : args.get_generic_args ())
     286              :     {
     287        21383 :       switch (arg.get_kind ())
     288              :         {
     289         9435 :         case AST::GenericArg::Kind::Type:
     290         9435 :           {
     291         9435 :             auto &type = arg.get_type ();
     292         9435 :             type.accept_vis (*this);
     293              : 
     294         9435 :             if (type.is_marked_for_strip ())
     295            0 :               rust_error_at (type.get_locus (),
     296              :                              "cannot strip type in this position");
     297              :             break;
     298              :           }
     299          400 :         case AST::GenericArg::Kind::Const:
     300          400 :           {
     301          400 :             auto &expr = arg.get_expression ();
     302          400 :             expr.accept_vis (*this);
     303              : 
     304          400 :             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        20977 :   for (auto &binding : args.get_binding_args ())
     322              :     {
     323          332 :       auto &type = binding.get_type ();
     324          332 :       type.accept_vis (*this);
     325              : 
     326          332 :       if (type.is_marked_for_strip ())
     327            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
     328              :     }
     329        20645 : }
     330              : 
     331              : void
     332         1785 : CfgStrip::maybe_strip_qualified_path_type (AST::QualifiedPathType &path_type)
     333              : {
     334         1785 :   auto &type = path_type.get_type ();
     335         1785 :   type.accept_vis (*this);
     336              : 
     337         1785 :   if (type.is_marked_for_strip ())
     338            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
     339              : 
     340         1785 :   if (path_type.has_as_clause ())
     341              :     {
     342         1595 :       auto &type_path = path_type.get_as_type_path ();
     343         1595 :       visit (type_path);
     344         1595 :       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         1785 : }
     349              : 
     350              : void
     351          250 : CfgStrip::CfgStrip::maybe_strip_closure_params (
     352              :   std::vector<AST::ClosureParam> &params)
     353              : {
     354          500 :   for (auto it = params.begin (); it != params.end ();)
     355              :     {
     356          250 :       auto &param = *it;
     357              : 
     358          250 :       auto &param_attrs = param.get_outer_attrs ();
     359          250 :       expand_cfg_attrs (param_attrs);
     360          250 :       if (fails_cfg_with_expand (param_attrs))
     361              :         {
     362            0 :           it = params.erase (it);
     363            0 :           continue;
     364              :         }
     365              : 
     366          250 :       auto &pattern = param.get_pattern ();
     367          250 :       pattern.accept_vis (*this);
     368          250 :       if (pattern.is_marked_for_strip ())
     369            0 :         rust_error_at (pattern.get_locus (),
     370              :                        "cannot strip pattern in this position");
     371              : 
     372          250 :       if (param.has_type_given ())
     373              :         {
     374          232 :           auto &type = param.get_type ();
     375          232 :           type.accept_vis (*this);
     376              : 
     377          232 :           if (type.is_marked_for_strip ())
     378            0 :             rust_error_at (type.get_locus (),
     379              :                            "cannot strip type in this position");
     380              :         }
     381              : 
     382              :       // increment if found nothing else so far
     383          250 :       ++it;
     384              :     }
     385          250 : }
     386              : 
     387              : void
     388            0 : CfgStrip::maybe_strip_where_clause (AST::WhereClause &where_clause)
     389              : {
     390              :   // items cannot be stripped conceptually, so just accept visitor
     391            0 :   for (auto &item : where_clause.get_items ())
     392            0 :     item->accept_vis (*this);
     393            0 : }
     394              : 
     395              : void
     396       208436 : CfgStrip::visit (AST::IdentifierExpr &ident_expr)
     397              : {
     398              :   // strip test based on outer attrs
     399       208436 :   AST::DefaultASTVisitor::visit (ident_expr);
     400       208436 :   expand_cfg_attrs (ident_expr.get_outer_attrs ());
     401       208436 :   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         4603 : CfgStrip::visit (AST::MacroInvocation &macro_invoc)
     410              : {
     411              :   // initial strip test based on outer attrs
     412         4603 :   expand_cfg_attrs (macro_invoc.get_outer_attrs ());
     413         4603 :   if (fails_cfg_with_expand (macro_invoc.get_outer_attrs ()))
     414              :     {
     415            0 :       macro_invoc.mark_for_strip ();
     416            0 :       return;
     417              :     }
     418              : 
     419              :   // can't strip simple path
     420              : 
     421              :   // I don't think any macro token trees can be stripped in any way
     422              : 
     423              :   // TODO: maybe have cfg! macro stripping behaviour here?
     424              : }
     425              : 
     426              : void
     427       172057 : CfgStrip::visit (AST::PathInExpression &path)
     428              : {
     429              :   // initial strip test based on outer attrs
     430       172057 :   expand_cfg_attrs (path.get_outer_attrs ());
     431       172057 :   if (fails_cfg_with_expand (path.get_outer_attrs ()))
     432              :     {
     433            0 :       path.mark_for_strip ();
     434            0 :       return;
     435              :     }
     436              : 
     437       172057 :   if (!path.is_lang_item ())
     438              :     {
     439       405850 :       for (auto &segment : path.get_segments ())
     440              :         {
     441       468582 :           if (segment.has_generic_args ())
     442         7105 :             maybe_strip_generic_args (segment.get_generic_args ());
     443              :         }
     444              :     }
     445              : }
     446              : 
     447              : void
     448        13456 : CfgStrip::visit (AST::TypePathSegmentGeneric &segment)
     449              : {
     450              :   // TODO: strip inside generic args
     451              : 
     452        13456 :   if (!segment.has_generic_args ())
     453              :     return;
     454              : 
     455        13452 :   maybe_strip_generic_args (segment.get_generic_args ());
     456              : }
     457              : void
     458           78 : CfgStrip::visit (AST::TypePathSegmentFunction &segment)
     459              : {
     460           78 :   AST::DefaultASTVisitor::visit (segment);
     461           78 :   auto &type_path_function = segment.get_type_path_function ();
     462              : 
     463          160 :   for (auto &type : type_path_function.get_params ())
     464              :     {
     465           82 :       if (type->is_marked_for_strip ())
     466            0 :         rust_error_at (type->get_locus (),
     467              :                        "cannot strip type in this position");
     468              :     }
     469              : 
     470           78 :   if (type_path_function.has_return_type ())
     471              :     {
     472           74 :       auto &return_type = type_path_function.get_return_type ();
     473              : 
     474           74 :       if (return_type.is_marked_for_strip ())
     475            0 :         rust_error_at (return_type.get_locus (),
     476              :                        "cannot strip type in this position");
     477              :     }
     478           78 : }
     479              : 
     480              : void
     481          532 : CfgStrip::visit (AST::QualifiedPathInExpression &path)
     482              : {
     483              :   // initial strip test based on outer attrs
     484          532 :   AST::DefaultASTVisitor::visit (path);
     485              : 
     486          532 :   expand_cfg_attrs (path.get_outer_attrs ());
     487          532 :   if (fails_cfg_with_expand (path.get_outer_attrs ()))
     488              :     {
     489            0 :       path.mark_for_strip ();
     490            0 :       return;
     491              :     }
     492              : 
     493          532 :   maybe_strip_qualified_path_type (path.get_qualified_path_type ());
     494              : 
     495         1064 :   for (auto &segment : path.get_segments ())
     496              :     {
     497         1064 :       if (segment.has_generic_args ())
     498            0 :         maybe_strip_generic_args (segment.get_generic_args ());
     499              :     }
     500              : }
     501              : 
     502              : void
     503         1253 : CfgStrip::visit (AST::QualifiedPathInType &path)
     504              : {
     505         1253 :   maybe_strip_qualified_path_type (path.get_qualified_path_type ());
     506              : 
     507              :   // this shouldn't strip any segments, but can strip inside them
     508         1253 :   AST::DefaultASTVisitor::visit (path);
     509         1253 : }
     510              : 
     511              : void
     512       701148 : CfgStrip::visit (AST::LiteralExpr &expr)
     513              : {
     514              :   // initial strip test based on outer attrs
     515       701148 :   expand_cfg_attrs (expr.get_outer_attrs ());
     516       701148 :   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        17526 : CfgStrip::visit (AST::BorrowExpr &expr)
     525              : {
     526        17526 :   AST::DefaultASTVisitor::visit (expr);
     527              :   // initial strip test based on outer attrs
     528        17526 :   expand_cfg_attrs (expr.get_outer_attrs ());
     529        17526 :   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        17526 :   auto &borrowed_expr = expr.get_borrowed_expr ();
     539        17526 :   if (borrowed_expr.is_marked_for_strip ())
     540            0 :     rust_error_at (borrowed_expr.get_locus (),
     541              :                    "cannot strip expression in this position - outer "
     542              :                    "attributes not allowed");
     543              : }
     544              : void
     545        21384 : CfgStrip::visit (AST::DereferenceExpr &expr)
     546              : {
     547              :   // initial strip test based on outer attrs
     548        21384 :   expand_cfg_attrs (expr.get_outer_attrs ());
     549        21384 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     550              :     {
     551            0 :       expr.mark_for_strip ();
     552            0 :       return;
     553              :     }
     554              : 
     555              :   /* strip any internal sub-expressions - expression itself isn't
     556              :    * allowed to have external attributes in this position so can't be
     557              :    * stripped. */
     558        21384 :   auto &dereferenced_expr = expr.get_dereferenced_expr ();
     559        21384 :   dereferenced_expr.accept_vis (*this);
     560        21384 :   if (dereferenced_expr.is_marked_for_strip ())
     561            0 :     rust_error_at (dereferenced_expr.get_locus (),
     562              :                    "cannot strip expression in this position - outer "
     563              :                    "attributes not allowed");
     564              : }
     565              : void
     566            4 : CfgStrip::visit (AST::ErrorPropagationExpr &expr)
     567              : {
     568            4 :   AST::DefaultASTVisitor::visit (expr);
     569              : 
     570              :   // initial strip test based on outer attrs
     571            4 :   expand_cfg_attrs (expr.get_outer_attrs ());
     572            4 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     573              :     {
     574            0 :       expr.mark_for_strip ();
     575            0 :       return;
     576              :     }
     577              : 
     578              :   /* strip any internal sub-expressions - expression itself isn't
     579              :    * allowed to have external attributes in this position so can't be
     580              :    * stripped. */
     581            4 :   auto &propagating_expr = expr.get_propagating_expr ();
     582            4 :   if (propagating_expr.is_marked_for_strip ())
     583            0 :     rust_error_at (propagating_expr.get_locus (),
     584              :                    "cannot strip expression in this position - outer "
     585              :                    "attributes not allowed");
     586              : }
     587              : void
     588         3891 : CfgStrip::visit (AST::NegationExpr &expr)
     589              : {
     590         3891 :   AST::DefaultASTVisitor::visit (expr);
     591              :   // initial strip test based on outer attrs
     592         3891 :   expand_cfg_attrs (expr.get_outer_attrs ());
     593         3891 :   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         3891 :   auto &negated_expr = expr.get_negated_expr ();
     603         3891 :   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       540431 : CfgStrip::visit (AST::ArithmeticOrLogicalExpr &expr)
     610              : {
     611       540431 :   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       540431 :   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       540431 :   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       540431 : }
     626              : 
     627              : void
     628        17047 : 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        17047 :   AST::DefaultASTVisitor::visit (expr);
     633              : 
     634              :   // ensure that they are not marked for strip
     635        17047 :   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        17047 :   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        17047 : }
     645              : 
     646              : void
     647         1580 : CfgStrip::visit (AST::LazyBooleanExpr &expr)
     648              : {
     649              :   /* outer attributes never allowed before these. while cannot strip
     650              :    * two direct descendant expressions, can strip ones below that */
     651         1580 :   AST::DefaultASTVisitor::visit (expr);
     652              : 
     653              :   // ensure that they are not marked for strip
     654         1580 :   if (expr.get_left_expr ().is_marked_for_strip ())
     655            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     656              :                    "cannot strip expression in this position - outer "
     657              :                    "attributes are never allowed "
     658              :                    "before binary op exprs");
     659         1580 :   if (expr.get_right_expr ().is_marked_for_strip ())
     660            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     661              :                    "cannot strip expression in this position - outer "
     662              :                    "attributes not allowed");
     663         1580 : }
     664              : 
     665              : void
     666        52302 : 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        52302 :   AST::DefaultASTVisitor::visit (expr);
     671              : 
     672        52302 :   auto &casted_expr = expr.get_casted_expr ();
     673              :   // ensure that they are not marked for strip
     674        52302 :   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        52302 :   auto &type = expr.get_type_to_cast_to ();
     681        52302 :   if (type.is_marked_for_strip ())
     682            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
     683        52302 : }
     684              : void
     685        15868 : CfgStrip::visit (AST::AssignmentExpr &expr)
     686              : {
     687        15868 :   expand_cfg_attrs (expr.get_outer_attrs ());
     688        15868 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     689              :     {
     690           14 :       expr.mark_for_strip ();
     691           14 :       return;
     692              :     }
     693        15854 :   AST::DefaultASTVisitor::visit (expr);
     694              : 
     695              :   // ensure that they are not marked for strip
     696        15854 :   if (expr.get_left_expr ().is_marked_for_strip ())
     697            0 :     rust_error_at (expr.get_left_expr ().get_locus (),
     698              :                    "cannot strip expression in this position - outer "
     699              :                    "attributes are never allowed "
     700              :                    "before binary op exprs");
     701        15854 :   if (expr.get_right_expr ().is_marked_for_strip ())
     702            0 :     rust_error_at (expr.get_right_expr ().get_locus (),
     703              :                    "cannot strip expression in this position - outer "
     704              :                    "attributes not allowed");
     705              : }
     706              : void
     707         6342 : 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         6342 :   AST::DefaultASTVisitor::visit (expr);
     712              : 
     713              :   // ensure that they are not marked for strip
     714         6342 :   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         6342 :   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         6342 : }
     724              : void
     725         2147 : CfgStrip::visit (AST::GroupedExpr &expr)
     726              : {
     727              :   // initial strip test based on outer attrs
     728         2147 :   expand_cfg_attrs (expr.get_outer_attrs ());
     729         2147 :   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         2147 :   expand_cfg_attrs (expr.get_inner_attrs ());
     738         2147 :   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         2147 :   AST::DefaultASTVisitor::visit (expr);
     748              : 
     749         2147 :   auto &inner_expr = expr.get_expr_in_parens ();
     750         2147 :   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         1165 : CfgStrip::visit (AST::ArrayElemsValues &elems)
     757              : {
     758              :   /* apparently outer attributes are allowed in "elements of array
     759              :    * expressions" according to spec */
     760         1165 :   maybe_strip_pointer_allow_strip (elems.get_values ());
     761         1165 : }
     762              : void
     763          466 : CfgStrip::visit (AST::ArrayElemsCopied &elems)
     764              : {
     765              :   /* apparently outer attributes are allowed in "elements of array
     766              :    * expressions" according to spec. on the other hand, it would not
     767              :    * make conceptual sense to be able to remove either expression. As
     768              :    * such, not implementing. TODO clear up the ambiguity here */
     769          466 :   AST::DefaultASTVisitor::visit (elems);
     770              : 
     771              :   // only intend stripping for internal sub-expressions
     772          466 :   auto &copied_expr = elems.get_elem_to_copy ();
     773          466 :   if (copied_expr.is_marked_for_strip ())
     774            0 :     rust_error_at (copied_expr.get_locus (),
     775              :                    "cannot strip expression in this position - outer "
     776              :                    "attributes not allowed");
     777              : 
     778          466 :   auto &copy_count = elems.get_num_copies ();
     779          466 :   copy_count.accept_vis (*this);
     780          466 :   if (copy_count.is_marked_for_strip ())
     781            0 :     rust_error_at (copy_count.get_locus (),
     782              :                    "cannot strip expression in this position - outer "
     783              :                    "attributes not allowed");
     784          466 : }
     785              : void
     786         1631 : CfgStrip::visit (AST::ArrayExpr &expr)
     787              : {
     788              :   // initial strip test based on outer attrs
     789         1631 :   expand_cfg_attrs (expr.get_outer_attrs ());
     790         1631 :   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         1631 :   expand_cfg_attrs (expr.get_inner_attrs ());
     799         1631 :   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         1631 :   AST::DefaultASTVisitor::visit (expr);
     808              : }
     809              : 
     810              : void
     811         1405 : 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         1405 :   expand_cfg_attrs (expr.get_outer_attrs ());
     818         1405 :   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         1405 :   AST::DefaultASTVisitor::visit (expr);
     828              : 
     829         1405 :   const auto &array_expr = expr.get_array_expr ();
     830         1405 :   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         1404 :   const auto &index_expr = expr.get_index_expr ();
     840         1404 :   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         2641 : 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         2641 :   expand_cfg_attrs (expr.get_outer_attrs ());
     853         2641 :   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         2641 :   expand_cfg_attrs (expr.get_inner_attrs ());
     862         2641 :   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         2641 :   maybe_strip_pointer_allow_strip (expr.get_tuple_elems ());
     871              : }
     872              : void
     873         5628 : CfgStrip::visit (AST::TupleIndexExpr &expr)
     874              : {
     875              :   // initial strip test based on outer attrs
     876         5628 :   expand_cfg_attrs (expr.get_outer_attrs ());
     877         5628 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
     878              :     {
     879            0 :       expr.mark_for_strip ();
     880            0 :       return;
     881              :     }
     882              : 
     883         5628 :   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         5628 :   auto &tuple_expr = expr.get_tuple_expr ();
     888         5628 :   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          328 : CfgStrip::visit (AST::StructExprStruct &expr)
     896              : {
     897              :   // initial strip test based on outer attrs
     898          328 :   expand_cfg_attrs (expr.get_outer_attrs ());
     899          328 :   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          328 :   expand_cfg_attrs (expr.get_inner_attrs ());
     908          328 :   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          328 :   auto &struct_name = expr.get_struct_name ();
     916          328 :   visit (struct_name);
     917          328 :   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         9451 : CfgStrip::visit (AST::StructExprFieldIdentifierValue &field)
     924              : {
     925              :   /* as no attrs possible (at moment, at least), only sub-expression
     926              :    * stripping is possible */
     927         9451 :   AST::DefaultASTVisitor::visit (field);
     928              : 
     929         9451 :   auto &value = field.get_value ();
     930         9451 :   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         9451 : }
     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         5764 : CfgStrip::visit (AST::StructExprStructFields &expr)
     950              : {
     951              :   // initial strip test based on outer attrs
     952         5764 :   expand_cfg_attrs (expr.get_outer_attrs ());
     953         5764 :   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         5764 :   expand_cfg_attrs (expr.get_inner_attrs ());
     962         5764 :   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         5764 :   auto &struct_name = expr.get_struct_name ();
     970         5764 :   visit (struct_name);
     971         5764 :   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         5764 :   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         5764 :   if (expr.has_struct_base ())
     984              :     {
     985          252 :       auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
     986          252 :       base_struct_expr.accept_vis (*this);
     987          252 :       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         5764 :   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        79536 : CfgStrip::visit (AST::CallExpr &expr)
    1035              : {
    1036              :   // initial strip test based on outer attrs
    1037        79536 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1038        79536 :   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        79535 :   AST::DefaultASTVisitor::visit (expr);
    1048              : 
    1049        79535 :   auto &function = expr.get_function_expr ();
    1050        79535 :   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        79534 :   maybe_strip_pointer_allow_strip (expr.get_params ());
    1064              : }
    1065              : void
    1066        20153 : CfgStrip::visit (AST::MethodCallExpr &expr)
    1067              : {
    1068              :   // initial strip test based on outer attrs
    1069        20153 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1070        20153 :   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        20153 :   AST::DefaultASTVisitor::visit (expr);
    1080              : 
    1081        20153 :   auto &receiver = expr.get_receiver_expr ();
    1082        20153 :   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        20153 :   auto &method_name = expr.get_method_name ();
    1088        20153 :   if (method_name.has_generic_args ())
    1089           88 :     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        20153 :   maybe_strip_pointer_allow_strip (expr.get_params ());
    1094              : }
    1095              : void
    1096        39961 : CfgStrip::visit (AST::FieldAccessExpr &expr)
    1097              : {
    1098              :   // initial strip test based on outer attrs
    1099        39961 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1100        39961 :   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        39961 :   AST::DefaultASTVisitor::visit (expr);
    1110              : 
    1111        39961 :   auto &receiver = expr.get_receiver_expr ();
    1112        39961 :   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          130 : CfgStrip::visit (AST::ClosureExprInner &expr)
    1119              : {
    1120              :   // initial strip test based on outer attrs
    1121          130 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1122          130 :   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          130 :   maybe_strip_closure_params (expr.get_params ());
    1131              : 
    1132          130 :   AST::DefaultASTVisitor::visit (expr);
    1133              : 
    1134              :   // can't strip expression itself, but can strip sub-expressions
    1135          130 :   auto &definition_expr = expr.get_definition_expr ();
    1136          130 :   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        94781 : CfgStrip::visit (AST::BlockExpr &expr)
    1144              : {
    1145              :   // initial strip test based on outer attrs
    1146        94781 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1147        94781 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1148              :     {
    1149           54 :       expr.mark_for_strip ();
    1150           54 :       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        94727 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1156        94727 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1157              :     {
    1158            0 :       expr.mark_for_strip ();
    1159            0 :       return;
    1160              :     }
    1161              : 
    1162        94727 :   maybe_strip_pointer_allow_strip (expr.get_statements ());
    1163              : 
    1164        94727 :   AST::DefaultASTVisitor::visit (expr);
    1165              : 
    1166              :   // strip tail expression if exists - can actually fully remove it
    1167        94727 :   if (expr.has_tail_expr ())
    1168              :     {
    1169        71435 :       auto &tail_expr = expr.get_tail_expr ();
    1170              : 
    1171        71435 :       if (tail_expr.is_marked_for_strip ())
    1172           57 :         expr.strip_tail_expr ();
    1173              :     }
    1174              : }
    1175              : 
    1176              : void
    1177          120 : CfgStrip::visit (AST::ClosureExprInnerTyped &expr)
    1178              : {
    1179              :   // initial strip test based on outer attrs
    1180          120 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1181          120 :   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          120 :   maybe_strip_closure_params (expr.get_params ());
    1190              : 
    1191          120 :   AST::DefaultASTVisitor::visit (expr);
    1192              : 
    1193              :   // can't strip return type, but can strip sub-types
    1194          120 :   auto &type = expr.get_return_type ();
    1195              : 
    1196          120 :   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          120 :   auto &definition_block = expr.get_definition_expr ();
    1201          120 :   definition_block.accept_vis (*this);
    1202          120 :   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          154 : CfgStrip::visit (AST::ContinueExpr &expr)
    1209              : {
    1210              :   // initial strip test based on outer attrs
    1211          154 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1212          154 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1213              :     {
    1214            0 :       expr.mark_for_strip ();
    1215            0 :       return;
    1216              :     }
    1217              : }
    1218              : void
    1219          660 : CfgStrip::visit (AST::BreakExpr &expr)
    1220              : {
    1221              :   // initial strip test based on outer attrs
    1222          660 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1223          660 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1224              :     {
    1225            0 :       expr.mark_for_strip ();
    1226            0 :       return;
    1227              :     }
    1228          660 :   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          660 :   if (expr.has_break_expr ())
    1234              :     {
    1235          280 :       auto &break_expr = expr.get_break_expr_unchecked ();
    1236              : 
    1237          280 :       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          356 : 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          356 :   AST::DefaultASTVisitor::visit (expr);
    1249              : 
    1250              :   // ensure that they are not marked for strip
    1251          356 :   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          356 :   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          356 : }
    1261              : void
    1262           28 : 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           28 :   AST::DefaultASTVisitor::visit (expr);
    1268              :   /* should have no possibility for outer attrs as would be parsed
    1269              :    * with outer expr */
    1270           28 :   auto &from_expr = expr.get_from_expr ();
    1271           28 :   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           28 : }
    1276              : void
    1277           28 : 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           28 :   AST::DefaultASTVisitor::visit (expr);
    1283              :   /* should syntactically not have outer attributes, though this may
    1284              :    * not have worked in practice */
    1285           28 :   auto &to_expr = expr.get_to_expr ();
    1286           28 :   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           28 : }
    1291              : 
    1292              : void
    1293           28 : 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           28 :   AST::DefaultASTVisitor::visit (expr);
    1299              : 
    1300              :   // ensure that they are not marked for strip
    1301           28 :   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           28 :   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           28 : }
    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         3132 : CfgStrip::visit (AST::ReturnExpr &expr)
    1328              : {
    1329              :   // initial strip test based on outer attrs
    1330         3132 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1331         3132 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1332              :     {
    1333            0 :       expr.mark_for_strip ();
    1334            0 :       return;
    1335              :     }
    1336              : 
    1337         3132 :   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         3132 :   if (expr.has_returned_expr ())
    1343              :     {
    1344         2774 :       auto &returned_expr = expr.get_returned_expr ();
    1345         2774 :       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        16780 : CfgStrip::visit (AST::UnsafeBlockExpr &expr)
    1358              : {
    1359              :   // initial strip test based on outer attrs
    1360        16780 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1361        16780 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1362              :     {
    1363            7 :       expr.mark_for_strip ();
    1364            7 :       return;
    1365              :     }
    1366              : 
    1367        16773 :   AST::DefaultASTVisitor::visit (expr);
    1368              : 
    1369              :   // can't strip block itself, but can strip sub-expressions
    1370        16773 :   auto &block_expr = expr.get_block_expr ();
    1371        16773 :   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          330 : CfgStrip::visit (AST::LoopExpr &expr)
    1378              : {
    1379              :   // initial strip test based on outer attrs
    1380          330 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1381          330 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1382              :     {
    1383            0 :       expr.mark_for_strip ();
    1384            0 :       return;
    1385              :     }
    1386              : 
    1387          330 :   AST::DefaultASTVisitor::visit (expr);
    1388              : 
    1389              :   // can't strip block itself, but can strip sub-expressions
    1390          330 :   auto &loop_block = expr.get_loop_block ();
    1391          330 :   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          474 : CfgStrip::visit (AST::WhileLoopExpr &expr)
    1398              : {
    1399              :   // initial strip test based on outer attrs
    1400          474 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1401          474 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1402              :     {
    1403            0 :       expr.mark_for_strip ();
    1404            0 :       return;
    1405              :     }
    1406              : 
    1407          474 :   AST::DefaultASTVisitor::visit (expr);
    1408              :   // can't strip predicate expr itself, but can strip sub-expressions
    1409          474 :   auto &predicate_expr = expr.get_predicate_expr ();
    1410          474 :   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          474 :   auto &loop_block = expr.get_loop_block ();
    1417          474 :   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            6 : CfgStrip::visit (AST::WhileLetLoopExpr &expr)
    1424              : {
    1425              :   // initial strip test based on outer attrs
    1426            6 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1427            6 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1428              :     {
    1429            0 :       expr.mark_for_strip ();
    1430            0 :       return;
    1431              :     }
    1432              : 
    1433            6 :   AST::DefaultASTVisitor::visit (expr);
    1434              : 
    1435            6 :   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            6 :   auto &scrutinee_expr = expr.get_scrutinee_expr ();
    1441            6 :   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            6 :   auto &loop_block = expr.get_loop_block ();
    1448            6 :   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          122 : CfgStrip::visit (AST::ForLoopExpr &expr)
    1455              : {
    1456              :   // initial strip test based on outer attrs
    1457          122 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1458          122 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1459              :     {
    1460            0 :       expr.mark_for_strip ();
    1461            0 :       return;
    1462              :     }
    1463              : 
    1464          122 :   AST::DefaultASTVisitor::visit (expr);
    1465              :   // strip sub-patterns of pattern
    1466          122 :   auto &pattern = expr.get_pattern ();
    1467          122 :   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          122 :   auto &iterator_expr = expr.get_iterator_expr ();
    1473          122 :   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          122 :   auto &loop_block = expr.get_loop_block ();
    1480          122 :   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        11974 : 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        11974 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1493        11974 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1494              :     {
    1495            0 :       expr.mark_for_strip ();
    1496            0 :       return;
    1497              :     }
    1498              : 
    1499        11974 :   AST::DefaultASTVisitor::visit (expr);
    1500              : 
    1501              :   // can't strip condition expr itself, but can strip sub-expressions
    1502        11974 :   auto &condition_expr = expr.get_condition_expr ();
    1503        11974 :   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        11974 :   auto &if_block = expr.get_if_block ();
    1510        11974 :   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         5924 : CfgStrip::visit (AST::IfExprConseqElse &expr)
    1518              : {
    1519              :   // initial strip test based on outer attrs
    1520         5924 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1521         5924 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1522              :     {
    1523            0 :       expr.mark_for_strip ();
    1524            0 :       return;
    1525              :     }
    1526              : 
    1527         5924 :   AST::DefaultASTVisitor::visit (expr);
    1528              : 
    1529              :   // can't strip condition expr itself, but can strip sub-expressions
    1530         5924 :   auto &condition_expr = expr.get_condition_expr ();
    1531         5924 :   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         5924 :   auto &if_block = expr.get_if_block ();
    1538         5924 :   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         5924 :   auto &else_block = expr.get_else_block ();
    1545         5924 :   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          102 : CfgStrip::visit (AST::IfLetExpr &expr)
    1553              : {
    1554              :   // initial strip test based on outer attrs
    1555          102 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1556          102 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1557              :     {
    1558            0 :       expr.mark_for_strip ();
    1559            0 :       return;
    1560              :     }
    1561              : 
    1562          102 :   AST::DefaultASTVisitor::visit (expr);
    1563              : 
    1564          102 :   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          102 :   auto &value_expr = expr.get_value_expr ();
    1570          102 :   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          102 :   auto &if_block = expr.get_if_block ();
    1577          102 :   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           30 : CfgStrip::visit (AST::IfLetExprConseqElse &expr)
    1584              : {
    1585              :   // initial strip test based on outer attrs
    1586           30 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1587           30 :   if (fails_cfg_with_expand (expr.get_outer_attrs ()))
    1588              :     {
    1589            0 :       expr.mark_for_strip ();
    1590            0 :       return;
    1591              :     }
    1592              : 
    1593           30 :   AST::DefaultASTVisitor::visit (expr);
    1594              : 
    1595           30 :   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           30 :   auto &value_expr = expr.get_value_expr ();
    1601           30 :   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           30 :   auto &if_block = expr.get_if_block ();
    1608           30 :   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           30 :   auto &else_block = expr.get_else_block ();
    1615           30 :   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         4446 : CfgStrip::visit (AST::MatchExpr &expr)
    1622              : {
    1623              :   // initial strip test based on outer attrs
    1624         4446 :   expand_cfg_attrs (expr.get_outer_attrs ());
    1625         4446 :   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         4446 :   expand_cfg_attrs (expr.get_inner_attrs ());
    1633         4446 :   if (fails_cfg_with_expand (expr.get_inner_attrs ()))
    1634              :     {
    1635            0 :       expr.mark_for_strip ();
    1636            0 :       return;
    1637              :     }
    1638              : 
    1639         4446 :   AST::DefaultASTVisitor::visit (expr);
    1640              : 
    1641              :   // can't strip scrutinee expr itself, but can strip sub-expressions
    1642         4446 :   auto &scrutinee_expr = expr.get_scrutinee_expr ();
    1643         4446 :   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         4446 :   auto &match_cases = expr.get_match_cases ();
    1650        14678 :   for (auto it = match_cases.begin (); it != match_cases.end ();)
    1651              :     {
    1652        10232 :       auto &match_case = *it;
    1653              : 
    1654              :       // strip match case based on outer attributes in match arm
    1655        10232 :       auto &match_arm = match_case.get_arm ();
    1656        10232 :       expand_cfg_attrs (match_arm.get_outer_attrs ());
    1657        10232 :       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        10232 :       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        10232 :       if (match_arm.has_match_arm_guard ())
    1673              :         {
    1674            2 :           auto &guard_expr = match_arm.get_guard_expr ();
    1675            2 :           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        10232 :       auto &case_expr = match_case.get_expr ();
    1683        10232 :       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        10232 :       ++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        20639 : CfgStrip::visit (AST::TypeParam &param)
    1737              : {
    1738              :   // outer attributes don't actually do anything, so ignore them
    1739              : 
    1740        20639 :   AST::DefaultASTVisitor::visit (param);
    1741              : 
    1742        20639 :   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        20639 : }
    1746              : 
    1747              : void
    1748         1259 : CfgStrip::visit (AST::TypeBoundWhereClauseItem &item)
    1749              : {
    1750              :   // for lifetimes shouldn't require
    1751         1259 :   AST::DefaultASTVisitor::visit (item);
    1752              : 
    1753         1259 :   auto &type = item.get_type ();
    1754         1259 :   if (type.is_marked_for_strip ())
    1755            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1756         1259 : }
    1757              : 
    1758              : void
    1759         3267 : CfgStrip::visit (AST::Module &module)
    1760              : {
    1761              :   // strip test based on outer attrs
    1762         3267 :   expand_cfg_attrs (module.get_outer_attrs ());
    1763         3267 :   if (fails_cfg_with_expand (module.get_outer_attrs ()))
    1764              :     {
    1765            0 :       module.mark_for_strip ();
    1766            0 :       return;
    1767              :     }
    1768              : 
    1769         3267 :   if (module.get_kind () == AST::Module::UNLOADED)
    1770              :     {
    1771           82 :       module.load_items ();
    1772              :     }
    1773              : 
    1774              :   // strip test based on inner attrs
    1775         3267 :   expand_cfg_attrs (module.get_inner_attrs ());
    1776         3267 :   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         3267 :   maybe_strip_pointer_allow_strip (module.get_items ());
    1784              : }
    1785              : 
    1786              : void
    1787           51 : CfgStrip::visit (AST::ExternCrate &extern_crate)
    1788              : {
    1789              :   // strip test based on outer attrs
    1790           51 :   expand_cfg_attrs (extern_crate.get_outer_attrs ());
    1791           51 :   if (fails_cfg_with_expand (extern_crate.get_outer_attrs ()))
    1792              :     {
    1793            0 :       extern_crate.mark_for_strip ();
    1794            0 :       return;
    1795              :     }
    1796              : 
    1797           51 :   if (!extern_crate.references_self ())
    1798              :     {
    1799           51 :       Session &session = Session::get_instance ();
    1800           51 :       session.load_extern_crate (extern_crate.get_referenced_crate (),
    1801              :                                  extern_crate.get_locus ());
    1802              :     }
    1803              : }
    1804              : 
    1805              : void
    1806         1860 : CfgStrip::visit (AST::UseDeclaration &use_decl)
    1807              : {
    1808              :   // strip test based on outer attrs
    1809         1860 :   expand_cfg_attrs (use_decl.get_outer_attrs ());
    1810         1860 :   if (fails_cfg_with_expand (use_decl.get_outer_attrs ()))
    1811              :     {
    1812            0 :       use_decl.mark_for_strip ();
    1813            0 :       return;
    1814              :     }
    1815              : }
    1816              : 
    1817              : void
    1818        68595 : CfgStrip::visit (AST::Function &function)
    1819              : {
    1820              :   // initial test based on outer attrs
    1821        68595 :   expand_cfg_attrs (function.get_outer_attrs ());
    1822        68595 :   if (fails_cfg_with_expand (function.get_outer_attrs ()))
    1823              :     {
    1824           31 :       function.mark_for_strip ();
    1825           31 :       return;
    1826              :     }
    1827              : 
    1828        68564 :   AST::DefaultASTVisitor::visit (function);
    1829              : 
    1830              :   /* strip function parameters if required - this is specifically
    1831              :    * allowed by spec */
    1832        68564 :   maybe_strip_function_params (function.get_function_params ());
    1833              : 
    1834        68564 :   if (function.has_return_type ())
    1835              :     {
    1836        54479 :       auto &return_type = function.get_return_type ();
    1837        54479 :       if (return_type.is_marked_for_strip ())
    1838            0 :         rust_error_at (return_type.get_locus (),
    1839              :                        "cannot strip type in this position");
    1840              :     }
    1841              : 
    1842              :   /* body should always exist - if error state, should have returned
    1843              :    * before now */
    1844              :   // can't strip block itself, but can strip sub-expressions
    1845        68564 :   if (function.has_body ())
    1846              :     {
    1847        53863 :       auto &block_expr = function.get_definition ();
    1848        53863 :       if (block_expr.value ()->is_marked_for_strip ())
    1849            0 :         rust_error_at (block_expr.value ()->get_locus (),
    1850              :                        "cannot strip block expression in this position - outer "
    1851              :                        "attributes not allowed");
    1852              :     }
    1853              : }
    1854              : 
    1855              : void
    1856         6244 : CfgStrip::visit (AST::TypeAlias &type_alias)
    1857              : {
    1858              :   // initial test based on outer attrs
    1859         6244 :   expand_cfg_attrs (type_alias.get_outer_attrs ());
    1860         6244 :   if (fails_cfg_with_expand (type_alias.get_outer_attrs ()))
    1861              :     {
    1862            0 :       type_alias.mark_for_strip ();
    1863            0 :       return;
    1864              :     }
    1865              : 
    1866         6244 :   AST::DefaultASTVisitor::visit (type_alias);
    1867              : 
    1868         6244 :   auto &type = type_alias.get_type_aliased ();
    1869         6244 :   if (type.is_marked_for_strip ())
    1870            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    1871              : }
    1872              : 
    1873              : void
    1874         4117 : CfgStrip::visit (AST::StructStruct &struct_item)
    1875              : {
    1876              :   // initial test based on outer attrs
    1877         4117 :   expand_cfg_attrs (struct_item.get_outer_attrs ());
    1878         4117 :   if (fails_cfg_with_expand (struct_item.get_outer_attrs ()))
    1879              :     {
    1880            2 :       struct_item.mark_for_strip ();
    1881            2 :       return;
    1882              :     }
    1883              : 
    1884         4115 :   AST::DefaultASTVisitor::visit (struct_item);
    1885              : 
    1886              :   /* strip struct fields if required - this is presumably
    1887              :    * allowed by spec */
    1888         4115 :   maybe_strip_struct_fields (struct_item.get_fields ());
    1889              : }
    1890              : void
    1891         2464 : CfgStrip::visit (AST::TupleStruct &tuple_struct)
    1892              : {
    1893              :   // initial test based on outer attrs
    1894         2464 :   expand_cfg_attrs (tuple_struct.get_outer_attrs ());
    1895         2464 :   if (fails_cfg_with_expand (tuple_struct.get_outer_attrs ()))
    1896              :     {
    1897            0 :       tuple_struct.mark_for_strip ();
    1898            0 :       return;
    1899              :     }
    1900              : 
    1901         2464 :   AST::DefaultASTVisitor::visit (tuple_struct);
    1902              : 
    1903              :   /* strip struct fields if required - this is presumably
    1904              :    * allowed by spec */
    1905         2464 :   maybe_strip_tuple_fields (tuple_struct.get_fields ());
    1906              : }
    1907              : void
    1908         2152 : CfgStrip::visit (AST::EnumItem &item)
    1909              : {
    1910              :   // initial test based on outer attrs
    1911         2152 :   expand_cfg_attrs (item.get_outer_attrs ());
    1912         2152 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1913              :     {
    1914            0 :       item.mark_for_strip ();
    1915            0 :       return;
    1916              :     }
    1917              : }
    1918              : 
    1919              : void
    1920         2266 : CfgStrip::visit (AST::EnumItemTuple &item)
    1921              : {
    1922              :   // initial test based on outer attrs
    1923         2266 :   expand_cfg_attrs (item.get_outer_attrs ());
    1924         2266 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1925              :     {
    1926            0 :       item.mark_for_strip ();
    1927            0 :       return;
    1928              :     }
    1929              : 
    1930              :   /* strip item fields if required - this is presumably
    1931              :    * allowed by spec */
    1932         2266 :   maybe_strip_tuple_fields (item.get_tuple_fields ());
    1933              : }
    1934              : 
    1935              : void
    1936          440 : CfgStrip::visit (AST::EnumItemStruct &item)
    1937              : {
    1938              :   // initial test based on outer attrs
    1939          440 :   expand_cfg_attrs (item.get_outer_attrs ());
    1940          440 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1941              :     {
    1942            0 :       item.mark_for_strip ();
    1943            0 :       return;
    1944              :     }
    1945              : 
    1946              :   /* strip item fields if required - this is presumably
    1947              :    * allowed by spec */
    1948          440 :   maybe_strip_struct_fields (item.get_struct_fields ());
    1949              : }
    1950              : 
    1951              : void
    1952         1410 : CfgStrip::visit (AST::EnumItemDiscriminant &item)
    1953              : {
    1954              :   // initial test based on outer attrs
    1955         1410 :   expand_cfg_attrs (item.get_outer_attrs ());
    1956         1410 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    1957              :     {
    1958            0 :       item.mark_for_strip ();
    1959            0 :       return;
    1960              :     }
    1961              : 
    1962         1410 :   AST::DefaultASTVisitor::visit (item);
    1963              :   /* strip any internal sub-expressions - expression itself isn't
    1964              :    * allowed to have external attributes in this position so can't be
    1965              :    * stripped. */
    1966         1410 :   auto &expr = item.get_expr ();
    1967         1410 :   if (expr.is_marked_for_strip ())
    1968            0 :     rust_error_at (expr.get_locus (),
    1969              :                    "cannot strip expression in this position - outer "
    1970              :                    "attributes not allowed");
    1971              : }
    1972              : void
    1973         1364 : CfgStrip::visit (AST::Enum &enum_item)
    1974              : {
    1975              :   // initial test based on outer attrs
    1976         1364 :   expand_cfg_attrs (enum_item.get_outer_attrs ());
    1977         1364 :   if (fails_cfg_with_expand (enum_item.get_outer_attrs ()))
    1978              :     {
    1979            0 :       enum_item.mark_for_strip ();
    1980            0 :       return;
    1981              :     }
    1982              : 
    1983         1364 :   AST::DefaultASTVisitor::visit (enum_item);
    1984              : 
    1985              :   /* strip enum fields if required - this is presumably
    1986              :    * allowed by spec */
    1987         1364 :   maybe_strip_pointer_allow_strip (enum_item.get_variants ());
    1988              : }
    1989              : void
    1990          230 : CfgStrip::visit (AST::Union &union_item)
    1991              : {
    1992              :   // initial test based on outer attrs
    1993          230 :   expand_cfg_attrs (union_item.get_outer_attrs ());
    1994          230 :   if (fails_cfg_with_expand (union_item.get_outer_attrs ()))
    1995              :     {
    1996            0 :       union_item.mark_for_strip ();
    1997            0 :       return;
    1998              :     }
    1999              : 
    2000          230 :   AST::DefaultASTVisitor::visit (union_item);
    2001              : 
    2002              :   /* strip union fields if required - this is presumably
    2003              :    * allowed by spec */
    2004          230 :   maybe_strip_struct_fields (union_item.get_variants ());
    2005              : }
    2006              : void
    2007         1531 : CfgStrip::visit (AST::ConstantItem &const_item)
    2008              : {
    2009              :   // initial test based on outer attrs
    2010         1531 :   expand_cfg_attrs (const_item.get_outer_attrs ());
    2011         1531 :   if (fails_cfg_with_expand (const_item.get_outer_attrs ()))
    2012              :     {
    2013            0 :       const_item.mark_for_strip ();
    2014            0 :       return;
    2015              :     }
    2016              : 
    2017         1531 :   AST::DefaultASTVisitor::visit (const_item);
    2018              : 
    2019              :   // strip any sub-types
    2020         1531 :   auto &type = const_item.get_type ();
    2021         1531 :   if (type.is_marked_for_strip ())
    2022            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2023              : 
    2024              :   /* strip any internal sub-expressions - expression itself isn't
    2025              :    * allowed to have external attributes in this position so can't be
    2026              :    * stripped. */
    2027         1531 :   if (const_item.has_expr ())
    2028              :     {
    2029         1389 :       auto &expr = const_item.get_expr ();
    2030         1389 :       if (expr.is_marked_for_strip ())
    2031            0 :         rust_error_at (expr.get_locus (),
    2032              :                        "cannot strip expression in this position - outer "
    2033              :                        "attributes not allowed");
    2034              :     }
    2035              : }
    2036              : void
    2037          126 : CfgStrip::visit (AST::StaticItem &static_item)
    2038              : {
    2039              :   // initial test based on outer attrs
    2040          126 :   expand_cfg_attrs (static_item.get_outer_attrs ());
    2041          126 :   if (fails_cfg_with_expand (static_item.get_outer_attrs ()))
    2042              :     {
    2043            0 :       static_item.mark_for_strip ();
    2044            0 :       return;
    2045              :     }
    2046              : 
    2047          126 :   AST::DefaultASTVisitor::visit (static_item);
    2048              : 
    2049              :   // strip any sub-types
    2050          126 :   auto &type = static_item.get_type ();
    2051              : 
    2052          126 :   if (type.is_marked_for_strip ())
    2053            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2054              : 
    2055              :   /* strip any internal sub-expressions - expression itself isn't
    2056              :    * allowed to have external attributes in this position so can't be
    2057              :    * stripped. */
    2058          126 :   auto &expr = static_item.get_expr ();
    2059          126 :   if (expr.is_marked_for_strip ())
    2060            0 :     rust_error_at (expr.get_locus (),
    2061              :                    "cannot strip expression in this position - outer "
    2062              :                    "attributes not allowed");
    2063              : }
    2064              : 
    2065              : void
    2066         3686 : CfgStrip::visit (AST::TraitItemType &item)
    2067              : {
    2068              :   // initial test based on outer attrs
    2069         3686 :   expand_cfg_attrs (item.get_outer_attrs ());
    2070         3686 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2071              :     {
    2072            0 :       item.mark_for_strip ();
    2073            0 :       return;
    2074              :     }
    2075              : 
    2076         3686 :   AST::DefaultASTVisitor::visit (item);
    2077              : }
    2078              : 
    2079              : void
    2080         9012 : CfgStrip::visit (AST::Trait &trait)
    2081              : {
    2082              :   // initial strip test based on outer attrs
    2083         9012 :   expand_cfg_attrs (trait.get_outer_attrs ());
    2084         9012 :   if (fails_cfg_with_expand (trait.get_outer_attrs ()))
    2085              :     {
    2086            1 :       trait.mark_for_strip ();
    2087            1 :       return;
    2088              :     }
    2089              : 
    2090              :   // strip test based on inner attrs
    2091         9011 :   expand_cfg_attrs (trait.get_inner_attrs ());
    2092         9011 :   if (fails_cfg_with_expand (trait.get_inner_attrs ()))
    2093              :     {
    2094            0 :       trait.mark_for_strip ();
    2095            0 :       return;
    2096              :     }
    2097              : 
    2098         9011 :   AST::DefaultASTVisitor::visit (trait);
    2099              : 
    2100         9011 :   maybe_strip_pointer_allow_strip (trait.get_trait_items ());
    2101              : }
    2102              : 
    2103              : void
    2104         2205 : CfgStrip::visit (AST::InherentImpl &impl)
    2105              : {
    2106              :   // initial strip test based on outer attrs
    2107         2205 :   expand_cfg_attrs (impl.get_outer_attrs ());
    2108         2205 :   if (fails_cfg_with_expand (impl.get_outer_attrs ()))
    2109              :     {
    2110            1 :       impl.mark_for_strip ();
    2111            1 :       return;
    2112              :     }
    2113              : 
    2114              :   // strip test based on inner attrs
    2115         2204 :   expand_cfg_attrs (impl.get_inner_attrs ());
    2116         2204 :   if (fails_cfg_with_expand (impl.get_inner_attrs ()))
    2117              :     {
    2118            0 :       impl.mark_for_strip ();
    2119            0 :       return;
    2120              :     }
    2121              : 
    2122         2204 :   AST::DefaultASTVisitor::visit (impl);
    2123              : 
    2124         2204 :   auto &type = impl.get_type ();
    2125              : 
    2126         2204 :   if (type.is_marked_for_strip ())
    2127            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2128              : 
    2129         2204 :   maybe_strip_pointer_allow_strip (impl.get_impl_items ());
    2130              : }
    2131              : 
    2132              : void
    2133        11162 : CfgStrip::visit (AST::TraitImpl &impl)
    2134              : {
    2135              :   // initial strip test based on outer attrs
    2136        11162 :   expand_cfg_attrs (impl.get_outer_attrs ());
    2137        11162 :   if (fails_cfg_with_expand (impl.get_outer_attrs ()))
    2138              :     {
    2139            0 :       impl.mark_for_strip ();
    2140            0 :       return;
    2141              :     }
    2142              : 
    2143              :   // strip test based on inner attrs
    2144        11162 :   expand_cfg_attrs (impl.get_inner_attrs ());
    2145        11162 :   if (fails_cfg_with_expand (impl.get_inner_attrs ()))
    2146              :     {
    2147            0 :       impl.mark_for_strip ();
    2148            0 :       return;
    2149              :     }
    2150              : 
    2151        11162 :   AST::DefaultASTVisitor::visit (impl);
    2152              : 
    2153        11162 :   auto &type = impl.get_type ();
    2154        11162 :   if (type.is_marked_for_strip ())
    2155            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2156              : 
    2157        11162 :   auto &trait_path = impl.get_trait_path ();
    2158        11162 :   visit (trait_path);
    2159        11162 :   if (trait_path.is_marked_for_strip ())
    2160            0 :     rust_error_at (trait_path.get_locus (),
    2161              :                    "cannot strip typepath in this position");
    2162              : 
    2163        11162 :   maybe_strip_pointer_allow_strip (impl.get_impl_items ());
    2164              : }
    2165              : 
    2166              : void
    2167            2 : CfgStrip::visit (AST::ExternalTypeItem &item)
    2168              : {
    2169            2 :   expand_cfg_attrs (item.get_outer_attrs ());
    2170              : 
    2171            2 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2172            0 :     item.mark_for_strip ();
    2173              : 
    2174              :   // TODO: Can we do anything like expand a macro here?
    2175              :   // extern "C" { type ffi_ty!(); }
    2176              :   // ?
    2177            2 : }
    2178              : 
    2179              : void
    2180            2 : CfgStrip::visit (AST::ExternalStaticItem &item)
    2181              : {
    2182              :   // strip test based on outer attrs
    2183            2 :   expand_cfg_attrs (item.get_outer_attrs ());
    2184            2 :   if (fails_cfg_with_expand (item.get_outer_attrs ()))
    2185              :     {
    2186            0 :       item.mark_for_strip ();
    2187            0 :       return;
    2188              :     }
    2189              : 
    2190            2 :   AST::DefaultASTVisitor::visit (item);
    2191              : 
    2192            2 :   auto &type = item.get_type ();
    2193            2 :   if (type.is_marked_for_strip ())
    2194            0 :     rust_error_at (type.get_locus (), "cannot strip type in this position");
    2195              : }
    2196              : 
    2197              : void
    2198         3649 : CfgStrip::visit (AST::ExternBlock &block)
    2199              : {
    2200              :   // initial strip test based on outer attrs
    2201         3649 :   expand_cfg_attrs (block.get_outer_attrs ());
    2202         3649 :   if (fails_cfg_with_expand (block.get_outer_attrs ()))
    2203              :     {
    2204            0 :       block.mark_for_strip ();
    2205            0 :       return;
    2206              :     }
    2207              : 
    2208              :   // strip test based on inner attrs
    2209         3649 :   expand_cfg_attrs (block.get_inner_attrs ());
    2210         3649 :   if (fails_cfg_with_expand (block.get_inner_attrs ()))
    2211              :     {
    2212            0 :       block.mark_for_strip ();
    2213            0 :       return;
    2214              :     }
    2215              : 
    2216         3649 :   maybe_strip_pointer_allow_strip (block.get_extern_items ());
    2217              : }
    2218              : 
    2219              : void
    2220         3845 : CfgStrip::visit (AST::MacroRulesDefinition &rules_def)
    2221              : {
    2222              :   // initial strip test based on outer attrs
    2223         3845 :   expand_cfg_attrs (rules_def.get_outer_attrs ());
    2224         3845 :   if (fails_cfg_with_expand (rules_def.get_outer_attrs ()))
    2225              :     {
    2226            0 :       rules_def.mark_for_strip ();
    2227            0 :       return;
    2228              :     }
    2229              : }
    2230              : 
    2231              : void
    2232       164814 : CfgStrip::visit (AST::IdentifierPattern &pattern)
    2233              : {
    2234              :   // can only strip sub-patterns of the inner pattern to bind
    2235       164814 :   if (!pattern.has_subpattern ())
    2236              :     return;
    2237              : 
    2238           70 :   AST::DefaultASTVisitor::visit (pattern);
    2239              : 
    2240           70 :   auto &sub_pattern = pattern.get_subpattern ();
    2241           70 :   if (sub_pattern.is_marked_for_strip ())
    2242            0 :     rust_error_at (sub_pattern.get_locus (),
    2243              :                    "cannot strip pattern in this position");
    2244              : }
    2245              : 
    2246              : void
    2247           42 : CfgStrip::visit (AST::RangePatternBoundPath &bound)
    2248              : {
    2249              :   // can expand path, but not strip it directly
    2250           42 :   auto &path = bound.get_path ();
    2251           42 :   visit (path);
    2252           42 :   if (path.is_marked_for_strip ())
    2253            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2254           42 : }
    2255              : 
    2256              : void
    2257            0 : CfgStrip::visit (AST::RangePatternBoundQualPath &bound)
    2258              : {
    2259              :   // can expand path, but not strip it directly
    2260            0 :   auto &path = bound.get_qualified_path ();
    2261            0 :   visit (path);
    2262            0 :   if (path.is_marked_for_strip ())
    2263            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2264            0 : }
    2265              : 
    2266              : void
    2267          820 : CfgStrip::visit (AST::ReferencePattern &pattern)
    2268              : {
    2269          820 :   AST::DefaultASTVisitor::visit (pattern);
    2270              : 
    2271          820 :   auto &sub_pattern = pattern.get_referenced_pattern ();
    2272          820 :   if (sub_pattern.is_marked_for_strip ())
    2273            0 :     rust_error_at (sub_pattern.get_locus (),
    2274              :                    "cannot strip pattern in this position");
    2275          820 : }
    2276              : void
    2277           78 : CfgStrip::visit (AST::StructPatternFieldTuplePat &field)
    2278              : {
    2279              :   // initial strip test based on outer attrs
    2280           78 :   expand_cfg_attrs (field.get_outer_attrs ());
    2281           78 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2282              :     {
    2283            0 :       field.mark_for_strip ();
    2284            0 :       return;
    2285              :     }
    2286              : 
    2287           78 :   AST::DefaultASTVisitor::visit (field);
    2288              : 
    2289              :   // strip sub-patterns (can't strip top-level pattern)
    2290           78 :   auto &sub_pattern = field.get_index_pattern ();
    2291           78 :   if (sub_pattern.is_marked_for_strip ())
    2292            0 :     rust_error_at (sub_pattern.get_locus (),
    2293              :                    "cannot strip pattern in this position");
    2294              : }
    2295              : 
    2296              : void
    2297          516 : CfgStrip::visit (AST::StructPatternFieldIdentPat &field)
    2298              : {
    2299              :   // initial strip test based on outer attrs
    2300          516 :   expand_cfg_attrs (field.get_outer_attrs ());
    2301          516 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2302              :     {
    2303            0 :       field.mark_for_strip ();
    2304            0 :       return;
    2305              :     }
    2306              : 
    2307          516 :   AST::DefaultASTVisitor::visit (field);
    2308              :   // strip sub-patterns (can't strip top-level pattern)
    2309          516 :   auto &sub_pattern = field.get_ident_pattern ();
    2310          516 :   if (sub_pattern.is_marked_for_strip ())
    2311            0 :     rust_error_at (sub_pattern.get_locus (),
    2312              :                    "cannot strip pattern in this position");
    2313              : }
    2314              : void
    2315          252 : CfgStrip::visit (AST::StructPatternFieldIdent &field)
    2316              : {
    2317              :   // initial strip test based on outer attrs
    2318          252 :   expand_cfg_attrs (field.get_outer_attrs ());
    2319          252 :   if (fails_cfg_with_expand (field.get_outer_attrs ()))
    2320              :     {
    2321            0 :       field.mark_for_strip ();
    2322            0 :       return;
    2323              :     }
    2324              : }
    2325              : 
    2326              : void
    2327          502 : CfgStrip::visit (AST::StructPattern &pattern)
    2328              : {
    2329              :   // expand (but don't strip) path
    2330          502 :   auto &path = pattern.get_path ();
    2331          502 :   visit (path);
    2332          502 :   if (path.is_marked_for_strip ())
    2333            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2334              : 
    2335              :   /* TODO: apparently struct pattern fields can have outer attrs. so can they
    2336              :    * be stripped? */
    2337          502 :   if (!pattern.has_struct_pattern_elems ())
    2338              :     return;
    2339              : 
    2340          500 :   auto &elems = pattern.get_struct_pattern_elems ();
    2341              : 
    2342              :   // assuming you can strip struct pattern fields
    2343          500 :   maybe_strip_pointer_allow_strip (elems.get_struct_pattern_fields ());
    2344              : 
    2345              :   // assuming you can strip the ".." part
    2346          500 :   if (elems.has_rest ())
    2347              :     {
    2348           10 :       expand_cfg_attrs (elems.get_etc_outer_attrs ());
    2349           10 :       if (fails_cfg_with_expand (elems.get_etc_outer_attrs ()))
    2350            0 :         elems.strip_etc ();
    2351              :     }
    2352              : }
    2353              : 
    2354              : void
    2355         4798 : CfgStrip::visit (AST::TupleStructItemsNoRest &tuple_items)
    2356              : {
    2357         4798 :   AST::DefaultASTVisitor::visit (tuple_items);
    2358              :   // can't strip individual patterns, only sub-patterns
    2359        10138 :   for (auto &pattern : tuple_items.get_patterns ())
    2360              :     {
    2361         5340 :       if (pattern->is_marked_for_strip ())
    2362            0 :         rust_error_at (pattern->get_locus (),
    2363              :                        "cannot strip pattern in this position");
    2364              :       // TODO: quit stripping now? or keep going?
    2365              :     }
    2366         4798 : }
    2367              : void
    2368          148 : CfgStrip::visit (AST::TupleStructItemsHasRest &tuple_items)
    2369              : {
    2370          148 :   AST::DefaultASTVisitor::visit (tuple_items);
    2371              :   // can't strip individual patterns, only sub-patterns
    2372          266 :   for (auto &lower_pattern : tuple_items.get_lower_patterns ())
    2373              :     {
    2374          118 :       if (lower_pattern->is_marked_for_strip ())
    2375            0 :         rust_error_at (lower_pattern->get_locus (),
    2376              :                        "cannot strip pattern in this position");
    2377              :       // TODO: quit stripping now? or keep going?
    2378              :     }
    2379          214 :   for (auto &upper_pattern : tuple_items.get_upper_patterns ())
    2380              :     {
    2381           66 :       if (upper_pattern->is_marked_for_strip ())
    2382            0 :         rust_error_at (upper_pattern->get_locus (),
    2383              :                        "cannot strip pattern in this position");
    2384              :       // TODO: quit stripping now? or keep going?
    2385              :     }
    2386          148 : }
    2387              : 
    2388              : void
    2389         4946 : CfgStrip::visit (AST::TupleStructPattern &pattern)
    2390              : {
    2391              :   // expand (but don't strip) path
    2392         4946 :   auto &path = pattern.get_path ();
    2393         4946 :   visit (path);
    2394         4946 :   if (path.is_marked_for_strip ())
    2395            0 :     rust_error_at (path.get_locus (), "cannot strip path in this position");
    2396              : 
    2397         4946 :   AST::DefaultASTVisitor::visit (pattern);
    2398         4946 : }
    2399              : 
    2400              : void
    2401         3934 : CfgStrip::visit (AST::TuplePatternItemsNoRest &tuple_items)
    2402              : {
    2403         3934 :   AST::DefaultASTVisitor::visit (tuple_items);
    2404              : 
    2405              :   // can't strip individual patterns, only sub-patterns
    2406        11814 :   for (auto &pattern : tuple_items.get_patterns ())
    2407              :     {
    2408         7880 :       if (pattern->is_marked_for_strip ())
    2409            0 :         rust_error_at (pattern->get_locus (),
    2410              :                        "cannot strip pattern in this position");
    2411              :       // TODO: quit stripping now? or keep going?
    2412              :     }
    2413         3934 : }
    2414              : 
    2415              : void
    2416          104 : CfgStrip::visit (AST::TuplePatternItemsHasRest &tuple_items)
    2417              : {
    2418          104 :   AST::DefaultASTVisitor::visit (tuple_items);
    2419              : 
    2420              :   // can't strip individual patterns, only sub-patterns
    2421          210 :   for (auto &lower_pattern : tuple_items.get_lower_patterns ())
    2422              :     {
    2423          106 :       if (lower_pattern->is_marked_for_strip ())
    2424            0 :         rust_error_at (lower_pattern->get_locus (),
    2425              :                        "cannot strip pattern in this position");
    2426              :       // TODO: quit stripping now? or keep going?
    2427              :     }
    2428          216 :   for (auto &upper_pattern : tuple_items.get_upper_patterns ())
    2429              :     {
    2430          112 :       if (upper_pattern->is_marked_for_strip ())
    2431            0 :         rust_error_at (upper_pattern->get_locus (),
    2432              :                        "cannot strip pattern in this position");
    2433              :       // TODO: quit stripping now? or keep going?
    2434              :     }
    2435          104 : }
    2436              : 
    2437              : void
    2438          176 : CfgStrip::visit (AST::GroupedPattern &pattern)
    2439              : {
    2440          176 :   AST::DefaultASTVisitor::visit (pattern);
    2441              :   // can't strip inner pattern, only sub-patterns
    2442          176 :   auto &pattern_in_parens = pattern.get_pattern_in_parens ();
    2443              : 
    2444          176 :   if (pattern_in_parens.is_marked_for_strip ())
    2445            0 :     rust_error_at (pattern_in_parens.get_locus (),
    2446              :                    "cannot strip pattern in this position");
    2447          176 : }
    2448              : 
    2449              : void
    2450          122 : CfgStrip::visit (AST::SlicePatternItemsNoRest &items)
    2451              : {
    2452          122 :   AST::DefaultASTVisitor::visit (items);
    2453              :   // can't strip individual patterns, only sub-patterns
    2454          364 :   for (auto &pattern : items.get_patterns ())
    2455              :     {
    2456          242 :       if (pattern->is_marked_for_strip ())
    2457            0 :         rust_error_at (pattern->get_locus (),
    2458              :                        "cannot strip pattern in this position");
    2459              :     }
    2460          122 : }
    2461              : 
    2462              : void
    2463          172 : CfgStrip::visit (AST::SlicePatternItemsHasRest &items)
    2464              : {
    2465          172 :   AST::DefaultASTVisitor::visit (items);
    2466              :   // can't strip individual patterns, only sub-patterns
    2467          342 :   for (auto &pattern : items.get_lower_patterns ())
    2468              :     {
    2469          170 :       if (pattern->is_marked_for_strip ())
    2470            0 :         rust_error_at (pattern->get_locus (),
    2471              :                        "cannot strip pattern in this position");
    2472              :     }
    2473          342 :   for (auto &pattern : items.get_upper_patterns ())
    2474              :     {
    2475          170 :       if (pattern->is_marked_for_strip ())
    2476            0 :         rust_error_at (pattern->get_locus (),
    2477              :                        "cannot strip pattern in this position");
    2478              :     }
    2479          172 : }
    2480              : 
    2481              : void
    2482          294 : CfgStrip::visit (AST::SlicePattern &pattern)
    2483              : {
    2484          294 :   AST::DefaultASTVisitor::visit (pattern);
    2485          294 : }
    2486              : 
    2487              : void
    2488          970 : CfgStrip::visit (AST::AltPattern &pattern)
    2489              : {
    2490          970 :   AST::DefaultASTVisitor::visit (pattern);
    2491              :   // can't strip individual patterns, only sub-patterns
    2492         3040 :   for (auto &alt : pattern.get_alts ())
    2493              :     {
    2494         2070 :       if (alt->is_marked_for_strip ())
    2495            0 :         rust_error_at (alt->get_locus (),
    2496              :                        "cannot strip pattern in this position");
    2497              :       // TODO: quit stripping now? or keep going?
    2498              :     }
    2499          970 : }
    2500              : 
    2501              : void
    2502        74088 : CfgStrip::visit (AST::LetStmt &stmt)
    2503              : {
    2504              :   // initial strip test based on outer attrs
    2505        74088 :   expand_cfg_attrs (stmt.get_outer_attrs ());
    2506        74088 :   if (fails_cfg_with_expand (stmt.get_outer_attrs ()))
    2507              :     {
    2508            0 :       stmt.mark_for_strip ();
    2509            0 :       return;
    2510              :     }
    2511              : 
    2512        74088 :   AST::DefaultASTVisitor::visit (stmt);
    2513              :   // can't strip pattern, but call for sub-patterns
    2514        74088 :   auto &pattern = stmt.get_pattern ();
    2515        74088 :   if (pattern.is_marked_for_strip ())
    2516            0 :     rust_error_at (pattern.get_locus (),
    2517              :                    "cannot strip pattern in this position");
    2518              : 
    2519              :   // similar for type
    2520        74088 :   if (stmt.has_type ())
    2521              :     {
    2522        10046 :       auto &type = stmt.get_type ();
    2523              : 
    2524        10046 :       if (type.is_marked_for_strip ())
    2525            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2526              :     }
    2527              : 
    2528              :   /* strip any internal sub-expressions - expression itself isn't
    2529              :    * allowed to have external attributes in this position so can't be
    2530              :    * stripped */
    2531        74088 :   if (stmt.has_init_expr ())
    2532              :     {
    2533        68964 :       auto &init_expr = stmt.get_init_expr ();
    2534              : 
    2535        68964 :       if (init_expr.is_marked_for_strip ())
    2536            0 :         rust_error_at (init_expr.get_locus (),
    2537              :                        "cannot strip expression in this position - outer "
    2538              :                        "attributes not allowed");
    2539              :     }
    2540              : }
    2541              : 
    2542              : void
    2543        73575 : CfgStrip::visit (AST::ExprStmt &stmt)
    2544              : {
    2545              :   // outer attributes associated with expr, so rely on expr
    2546              : 
    2547              :   // guard - should prevent null pointer expr
    2548        73575 :   if (stmt.is_marked_for_strip ())
    2549              :     return;
    2550              : 
    2551        73575 :   AST::DefaultASTVisitor::visit (stmt);
    2552              :   // strip if expr is to be stripped
    2553        73575 :   auto &expr = stmt.get_expr ();
    2554        73575 :   if (expr.is_marked_for_strip ())
    2555              :     {
    2556           19 :       stmt.mark_for_strip ();
    2557           19 :       return;
    2558              :     }
    2559              : }
    2560              : 
    2561              : void
    2562         6875 : CfgStrip::visit (AST::TraitBound &bound)
    2563              : {
    2564              :   // nothing in for lifetimes to strip
    2565              : 
    2566              :   // expand but don't strip type path
    2567         6875 :   auto &path = bound.get_type_path ();
    2568         6875 :   visit (path);
    2569         6875 :   if (path.is_marked_for_strip ())
    2570            0 :     rust_error_at (path.get_locus (),
    2571              :                    "cannot strip type path in this position");
    2572         6875 : }
    2573              : 
    2574              : void
    2575           22 : CfgStrip::visit (AST::ParenthesisedType &type)
    2576              : {
    2577           22 :   AST::DefaultASTVisitor::visit (type);
    2578              :   // expand but don't strip inner type
    2579           22 :   auto &inner_type = type.get_type_in_parens ();
    2580           22 :   if (inner_type->is_marked_for_strip ())
    2581            0 :     rust_error_at (inner_type->get_locus (),
    2582              :                    "cannot strip type in this position");
    2583           22 : }
    2584              : 
    2585              : void
    2586         1831 : CfgStrip::visit (AST::TupleType &type)
    2587              : {
    2588         1831 :   AST::DefaultASTVisitor::visit (type);
    2589              :   // TODO: assuming that types can't be stripped as types don't have outer
    2590              :   // attributes
    2591         4713 :   for (auto &elem_type : type.get_elems ())
    2592              :     {
    2593         2882 :       if (elem_type->is_marked_for_strip ())
    2594            0 :         rust_error_at (elem_type->get_locus (),
    2595              :                        "cannot strip type in this position");
    2596              :     }
    2597         1831 : }
    2598              : 
    2599              : void
    2600        48545 : CfgStrip::visit (AST::RawPointerType &type)
    2601              : {
    2602        48545 :   AST::DefaultASTVisitor::visit (type);
    2603              :   // expand but don't strip type pointed to
    2604        48545 :   auto &pointed_type = type.get_type_pointed_to ();
    2605        48545 :   if (pointed_type.is_marked_for_strip ())
    2606            0 :     rust_error_at (pointed_type.get_locus (),
    2607              :                    "cannot strip type in this position");
    2608        48545 : }
    2609              : 
    2610              : void
    2611        32958 : CfgStrip::visit (AST::ReferenceType &type)
    2612              : {
    2613        32958 :   AST::DefaultASTVisitor::visit (type);
    2614              :   // expand but don't strip type referenced
    2615        32958 :   auto &referenced_type = type.get_type_referenced ();
    2616        32958 :   if (referenced_type.is_marked_for_strip ())
    2617            0 :     rust_error_at (referenced_type.get_locus (),
    2618              :                    "cannot strip type in this position");
    2619        32958 : }
    2620              : 
    2621              : void
    2622         4906 : CfgStrip::visit (AST::ArrayType &type)
    2623              : {
    2624         4906 :   AST::DefaultASTVisitor::visit (type);
    2625              :   // expand but don't strip type referenced
    2626         4906 :   auto &base_type = type.get_elem_type ();
    2627         4906 :   if (base_type.is_marked_for_strip ())
    2628            0 :     rust_error_at (base_type.get_locus (),
    2629              :                    "cannot strip type in this position");
    2630              : 
    2631              :   // same for expression
    2632         4906 :   auto &size_expr = type.get_size_expr ();
    2633         4906 :   if (size_expr.is_marked_for_strip ())
    2634            0 :     rust_error_at (size_expr.get_locus (),
    2635              :                    "cannot strip expression in this position");
    2636         4906 : }
    2637              : void
    2638         4023 : CfgStrip::visit (AST::SliceType &type)
    2639              : {
    2640         4023 :   AST::DefaultASTVisitor::visit (type);
    2641              :   // expand but don't strip elem type
    2642         4023 :   auto &elem_type = type.get_elem_type ();
    2643         4023 :   if (elem_type.is_marked_for_strip ())
    2644            0 :     rust_error_at (elem_type.get_locus (),
    2645              :                    "cannot strip type in this position");
    2646         4023 : }
    2647              : 
    2648              : void
    2649          254 : CfgStrip::visit (AST::BareFunctionType &type)
    2650              : {
    2651              :   // seem to be no generics
    2652          254 :   AST::DefaultASTVisitor::visit (type);
    2653              : 
    2654              :   // presumably function params can be stripped
    2655          254 :   auto &params = type.get_function_params ();
    2656          474 :   for (auto it = params.begin (); it != params.end ();)
    2657              :     {
    2658          220 :       auto &param = *it;
    2659              : 
    2660          220 :       auto &param_attrs = param.get_outer_attrs ();
    2661          220 :       expand_cfg_attrs (param_attrs);
    2662          220 :       if (fails_cfg_with_expand (param_attrs))
    2663              :         {
    2664            0 :           it = params.erase (it);
    2665            0 :           continue;
    2666              :         }
    2667              : 
    2668          220 :       auto &type = param.get_type ();
    2669          220 :       if (type.is_marked_for_strip ())
    2670            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2671              : 
    2672              :       // increment if nothing else happens
    2673          220 :       ++it;
    2674              :     }
    2675              : 
    2676              :   /* TODO: assuming that variadic nature cannot be stripped. If this
    2677              :    * is not true, then have code here to do so. */
    2678              : 
    2679          254 :   if (type.has_return_type ())
    2680              :     {
    2681              :       // FIXME: Can we have type expansion in this position?
    2682              :       // In that case, we need to handle AST::TypeNoBounds on top of just
    2683              :       // AST::Types
    2684          182 :       auto &return_type = type.get_return_type ();
    2685          182 :       if (return_type.is_marked_for_strip ())
    2686            0 :         rust_error_at (return_type.get_locus (),
    2687              :                        "cannot strip type in this position");
    2688              :     }
    2689              : 
    2690              :   // no where clause, apparently
    2691          254 : }
    2692              : 
    2693              : void
    2694        39648 : CfgStrip::visit (AST::SelfParam &param)
    2695              : {
    2696        39648 :   AST::DefaultASTVisitor::visit (param);
    2697              : 
    2698        39648 :   if (param.has_type ())
    2699              :     {
    2700            4 :       auto &type = param.get_type ();
    2701            4 :       if (type.is_marked_for_strip ())
    2702            0 :         rust_error_at (type.get_locus (), "cannot strip type in this position");
    2703              :     }
    2704              :   /* TODO: maybe check for invariants being violated - e.g. both type and
    2705              :    * lifetime? */
    2706        39648 : }
    2707              : 
    2708              : } // 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.