// Copyright (C) 2020-2024 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// .
#include "rust-cfg-strip.h"
#include "rust-ast-full.h"
#include "rust-ast-visitor.h"
#include "rust-session-manager.h"
#include "rust-attribute-values.h"
namespace Rust {
/**
* Determines whether any cfg predicate is false and hence item with attributes
* should be stripped. Note that attributes must be expanded before calling.
*/
bool
fails_cfg (const AST::AttrVec &attrs)
{
auto &session = Session::get_instance ();
for (const auto &attr : attrs)
{
if (attr.get_path () == Values::Attributes::CFG
&& !attr.check_cfg_predicate (session))
return true;
}
return false;
}
/**
* Determines whether any cfg predicate is false and hence item with attributes
* should be stripped. Will expand attributes as well.
*/
bool
fails_cfg_with_expand (AST::AttrVec &attrs)
{
auto &session = Session::get_instance ();
// TODO: maybe have something that strips cfg attributes that evaluate true?
for (auto &attr : attrs)
{
if (attr.get_path () == Values::Attributes::CFG)
{
if (!attr.is_parsed_to_meta_item ())
attr.parse_attr_to_meta_item ();
// DEBUG
if (!attr.is_parsed_to_meta_item ())
rust_debug ("failed to parse attr to meta item, right before "
"cfg predicate check");
else
rust_debug ("attr has been successfully parsed to meta item, "
"right before cfg predicate check");
if (!attr.check_cfg_predicate (session))
{
// DEBUG
rust_debug (
"cfg predicate failed for attribute: \033[0;31m'%s'\033[0m",
attr.as_string ().c_str ());
return true;
}
else
{
// DEBUG
rust_debug ("cfg predicate succeeded for attribute: "
"\033[0;31m'%s'\033[0m",
attr.as_string ().c_str ());
}
}
}
return false;
}
/**
* Expands cfg_attr attributes.
*/
void
expand_cfg_attrs (AST::AttrVec &attrs)
{
auto &session = Session::get_instance ();
for (std::size_t i = 0; i < attrs.size (); i++)
{
auto &attr = attrs[i];
if (attr.get_path () == Values::Attributes::CFG_ATTR)
{
if (!attr.is_parsed_to_meta_item ())
attr.parse_attr_to_meta_item ();
if (attr.check_cfg_predicate (session))
{
// split off cfg_attr
AST::AttrVec new_attrs = attr.separate_cfg_attrs ();
// remove attr from vector
attrs.erase (attrs.begin () + i);
// add new attrs to vector
attrs.insert (attrs.begin () + i,
std::make_move_iterator (new_attrs.begin ()),
std::make_move_iterator (new_attrs.end ()));
}
/* do something - if feature (first token in tree) is in fact enabled,
* make tokens listed afterwards into attributes. i.e.: for
* [cfg_attr(feature = "wow", wow1, wow2)], if "wow" is true, then add
* attributes [wow1] and [wow2] to attribute list. This can also be
* recursive, so check for expanded attributes being recursive and
* possibly recursively call the expand_attrs? */
}
else
{
i++;
}
}
attrs.shrink_to_fit ();
}
void
CfgStrip::go (AST::Crate &crate)
{
visit (crate);
}
void
CfgStrip::visit (AST::Crate &crate)
{
// expand crate cfg_attr attributes
expand_cfg_attrs (crate.inner_attrs);
if (fails_cfg_with_expand (crate.inner_attrs))
{
// basically, delete whole crate
crate.strip_crate ();
// TODO: maybe create warning here? probably not desired behaviour
}
auto &items = crate.items;
AST::DefaultASTVisitor::visit (crate);
for (auto it = items.begin (); it != items.end ();)
{
auto &item = *it;
if (item->is_marked_for_strip ())
it = items.erase (it);
else
it++;
}
// expand module attributes?
}
// Visitor used to expand attributes.
void
CfgStrip::maybe_strip_struct_fields (std::vector &fields)
{
for (auto it = fields.begin (); it != fields.end ();)
{
auto &field = *it;
auto &field_attrs = field.get_outer_attrs ();
expand_cfg_attrs (field_attrs);
if (fails_cfg_with_expand (field_attrs))
{
it = fields.erase (it);
continue;
}
// expand sub-types of type, but can't strip type itself
auto &type = field.get_field_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
// if nothing else happens, increment
++it;
}
}
void
CfgStrip::maybe_strip_tuple_fields (std::vector &fields)
{
for (auto it = fields.begin (); it != fields.end ();)
{
auto &field = *it;
auto &field_attrs = field.get_outer_attrs ();
expand_cfg_attrs (field_attrs);
if (fails_cfg_with_expand (field_attrs))
{
it = fields.erase (it);
continue;
}
// expand sub-types of type, but can't strip type itself
auto &type = field.get_field_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
// if nothing else happens, increment
++it;
}
}
void
CfgStrip::maybe_strip_function_params (
std::vector> ¶ms)
{
for (auto it = params.begin (); it != params.end ();)
{
if (!(*it)->is_self () && !(*it)->is_variadic ())
{
auto param = static_cast (it->get ());
auto ¶m_attrs = param->get_outer_attrs ();
expand_cfg_attrs (param_attrs);
if (fails_cfg_with_expand (param_attrs))
{
it = params.erase (it);
continue;
}
// TODO: should an unwanted strip lead to break out of loop?
auto &pattern = param->get_pattern ();
pattern->accept_vis (*this);
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
auto &type = param->get_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
// increment
++it;
}
}
void
CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args)
{
// lifetime args can't be expanded
// FIXME: Can we have macro invocations for lifetimes?
// expand type args - strip sub-types only
for (auto &arg : args.get_generic_args ())
{
switch (arg.get_kind ())
{
case AST::GenericArg::Kind::Type: {
auto &type = arg.get_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
break;
}
case AST::GenericArg::Kind::Const: {
auto &expr = arg.get_expression ();
expr->accept_vis (*this);
if (expr->is_marked_for_strip ())
rust_error_at (expr->get_locus (),
"cannot strip expression in this position");
break;
}
default:
break;
// FIXME: Figure out what to do here if there is ambiguity. Since the
// resolver comes after the expansion, we need to figure out a way to
// strip ambiguous values here
// TODO: Arthur: Probably add a `mark_as_strip` method to `GenericArg`
// or something. This would clean up this whole thing
}
}
// FIXME: Can we have macro invocations in generic type bindings?
// expand binding args - strip sub-types only
for (auto &binding : args.get_binding_args ())
{
auto &type = binding.get_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
}
void
CfgStrip::maybe_strip_qualified_path_type (AST::QualifiedPathType &path_type)
{
auto &type = path_type.get_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
if (path_type.has_as_clause ())
{
auto &type_path = path_type.get_as_type_path ();
visit (type_path);
if (type_path.is_marked_for_strip ())
rust_error_at (type_path.get_locus (),
"cannot strip type path in this position");
}
}
void
CfgStrip::CfgStrip::maybe_strip_closure_params (
std::vector ¶ms)
{
for (auto it = params.begin (); it != params.end ();)
{
auto ¶m = *it;
auto ¶m_attrs = param.get_outer_attrs ();
expand_cfg_attrs (param_attrs);
if (fails_cfg_with_expand (param_attrs))
{
it = params.erase (it);
continue;
}
auto &pattern = param.get_pattern ();
pattern->accept_vis (*this);
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
if (param.has_type_given ())
{
auto &type = param.get_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
// increment if found nothing else so far
++it;
}
}
void
CfgStrip::maybe_strip_where_clause (AST::WhereClause &where_clause)
{
// items cannot be stripped conceptually, so just accept visitor
for (auto &item : where_clause.get_items ())
item->accept_vis (*this);
}
void
CfgStrip::visit (AST::IdentifierExpr &ident_expr)
{
// strip test based on outer attrs
AST::DefaultASTVisitor::visit (ident_expr);
expand_cfg_attrs (ident_expr.get_outer_attrs ());
if (fails_cfg_with_expand (ident_expr.get_outer_attrs ()))
{
ident_expr.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::MacroInvocation ¯o_invoc)
{
// initial strip test based on outer attrs
expand_cfg_attrs (macro_invoc.get_outer_attrs ());
if (fails_cfg_with_expand (macro_invoc.get_outer_attrs ()))
{
macro_invoc.mark_for_strip ();
return;
}
// can't strip simple path
// I don't think any macro token trees can be stripped in any way
// TODO: maybe have cfg! macro stripping behaviour here?
}
void
CfgStrip::visit (AST::PathInExpression &path)
{
// initial strip test based on outer attrs
expand_cfg_attrs (path.get_outer_attrs ());
if (fails_cfg_with_expand (path.get_outer_attrs ()))
{
path.mark_for_strip ();
return;
}
for (auto &segment : path.get_segments ())
{
if (segment.has_generic_args ())
maybe_strip_generic_args (segment.get_generic_args ());
}
}
void
CfgStrip::visit (AST::TypePathSegmentGeneric &segment)
{
// TODO: strip inside generic args
if (!segment.has_generic_args ())
return;
maybe_strip_generic_args (segment.get_generic_args ());
}
void
CfgStrip::visit (AST::TypePathSegmentFunction &segment)
{
AST::DefaultASTVisitor::visit (segment);
auto &type_path_function = segment.get_type_path_function ();
for (auto &type : type_path_function.get_params ())
{
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
if (type_path_function.has_return_type ())
{
auto &return_type = type_path_function.get_return_type ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
}
}
void
CfgStrip::visit (AST::QualifiedPathInExpression &path)
{
// initial strip test based on outer attrs
AST::DefaultASTVisitor::visit (path);
expand_cfg_attrs (path.get_outer_attrs ());
if (fails_cfg_with_expand (path.get_outer_attrs ()))
{
path.mark_for_strip ();
return;
}
maybe_strip_qualified_path_type (path.get_qualified_path_type ());
for (auto &segment : path.get_segments ())
{
if (segment.has_generic_args ())
maybe_strip_generic_args (segment.get_generic_args ());
}
}
void
CfgStrip::visit (AST::QualifiedPathInType &path)
{
maybe_strip_qualified_path_type (path.get_qualified_path_type ());
// this shouldn't strip any segments, but can strip inside them
AST::DefaultASTVisitor::visit (path);
}
void
CfgStrip::visit (AST::LiteralExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::BorrowExpr &expr)
{
AST::DefaultASTVisitor::visit (expr);
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
auto &borrowed_expr = expr.get_borrowed_expr ();
if (borrowed_expr->is_marked_for_strip ())
rust_error_at (borrowed_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::DereferenceExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
auto &dereferenced_expr = expr.get_dereferenced_expr ();
dereferenced_expr->accept_vis (*this);
if (dereferenced_expr->is_marked_for_strip ())
rust_error_at (dereferenced_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ErrorPropagationExpr &expr)
{
AST::DefaultASTVisitor::visit (expr);
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
auto &propagating_expr = expr.get_propagating_expr ();
if (propagating_expr->is_marked_for_strip ())
rust_error_at (propagating_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::NegationExpr &expr)
{
AST::DefaultASTVisitor::visit (expr);
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
auto &negated_expr = expr.get_negated_expr ();
if (negated_expr->is_marked_for_strip ())
rust_error_at (negated_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ArithmeticOrLogicalExpr &expr)
{
AST::DefaultASTVisitor::visit (expr);
/* outer attributes never allowed before these. while cannot strip
* two direct descendant expressions, can strip ones below that */
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_left_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before binary op exprs");
if (expr.get_right_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_right_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ComparisonExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* two direct descendant expressions, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_left_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before binary op exprs");
if (expr.get_right_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_right_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::LazyBooleanExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* two direct descendant expressions, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_left_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before binary op exprs");
if (expr.get_right_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_right_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::TypeCastExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* direct descendant expression, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
auto &casted_expr = expr.get_casted_expr ();
// ensure that they are not marked for strip
if (casted_expr->is_marked_for_strip ())
rust_error_at (casted_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed before cast exprs");
// TODO: strip sub-types of type
auto &type = expr.get_type_to_cast_to ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
}
void
CfgStrip::visit (AST::AssignmentExpr &expr)
{
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_left_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before binary op exprs");
if (expr.get_right_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_right_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::CompoundAssignmentExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* two direct descendant expressions, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_left_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before binary op exprs");
if (expr.get_right_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_right_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::GroupedExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says these are inner
* attributes, not outer attributes of inner expr */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
AST::DefaultASTVisitor::visit (expr);
auto &inner_expr = expr.get_expr_in_parens ();
if (inner_expr->is_marked_for_strip ())
rust_error_at (inner_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ArrayElemsValues &elems)
{
/* apparently outer attributes are allowed in "elements of array
* expressions" according to spec */
maybe_strip_pointer_allow_strip (elems.get_values ());
}
void
CfgStrip::visit (AST::ArrayElemsCopied &elems)
{
/* apparently outer attributes are allowed in "elements of array
* expressions" according to spec. on the other hand, it would not
* make conceptual sense to be able to remove either expression. As
* such, not implementing. TODO clear up the ambiguity here */
AST::DefaultASTVisitor::visit (elems);
// only intend stripping for internal sub-expressions
auto &copied_expr = elems.get_elem_to_copy ();
if (copied_expr->is_marked_for_strip ())
rust_error_at (copied_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
auto ©_count = elems.get_num_copies ();
copy_count->accept_vis (*this);
if (copy_count->is_marked_for_strip ())
rust_error_at (copy_count->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ArrayExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says there are separate
* inner attributes, not just outer attributes of inner exprs */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* assuming you can't strip away the ArrayElems type, but can strip
* internal expressions and whatever */
AST::DefaultASTVisitor::visit (expr);
}
void
CfgStrip::visit (AST::ArrayIndexExpr &expr)
{
/* it is unclear whether outer attributes are supposed to be
* allowed, but conceptually it wouldn't make much sense, but
* having expansion code anyway. TODO */
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
AST::DefaultASTVisitor::visit (expr);
const auto &array_expr = expr.get_array_expr ();
if (array_expr->is_marked_for_strip ())
rust_error_at (array_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
const auto &index_expr = expr.get_index_expr ();
if (index_expr->is_marked_for_strip ())
rust_error_at (index_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::TupleExpr &expr)
{
/* according to spec, outer attributes are allowed on "elements of
* tuple expressions" */
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says these are inner
* attributes, not outer attributes of inner expr */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* apparently outer attributes are allowed in "elements of tuple
* expressions" according to spec */
maybe_strip_pointer_allow_strip (expr.get_tuple_elems ());
}
void
CfgStrip::visit (AST::TupleIndexExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
/* wouldn't strip this directly (as outer attrs should be
* associated with this level), but any sub-expressions would be
* stripped. Thus, no need to erase when strip check called. */
auto &tuple_expr = expr.get_tuple_expr ();
if (tuple_expr->is_marked_for_strip ())
rust_error_at (tuple_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::StructExprStruct &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says these are inner
* attributes, not outer attributes of inner expr */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
// strip sub-exprs of path
auto &struct_name = expr.get_struct_name ();
visit (struct_name);
if (struct_name.is_marked_for_strip ())
rust_error_at (struct_name.get_locus (),
"cannot strip path in this position");
}
void
CfgStrip::visit (AST::StructExprFieldIdentifierValue &field)
{
/* as no attrs possible (at moment, at least), only sub-expression
* stripping is possible */
AST::DefaultASTVisitor::visit (field);
auto &value = field.get_value ();
if (value->is_marked_for_strip ())
rust_error_at (value->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::StructExprFieldIndexValue &field)
{
/* as no attrs possible (at moment, at least), only sub-expression
* stripping is possible */
AST::DefaultASTVisitor::visit (field);
auto &value = field.get_value ();
if (value->is_marked_for_strip ())
rust_error_at (value->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::StructExprStructFields &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says these are inner
* attributes, not outer attributes of inner expr */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
// strip sub-exprs of path
auto &struct_name = expr.get_struct_name ();
visit (struct_name);
if (struct_name.is_marked_for_strip ())
rust_error_at (struct_name.get_locus (),
"cannot strip path in this position");
/* spec does not specify whether expressions are allowed to be
* stripped at top level of struct fields, but I wouldn't think
* that they would be, so operating under the assumption that only
* sub-expressions can be stripped. */
AST::DefaultASTVisitor::visit (expr);
/* struct base presumably can't be stripped, as the '..' is before
* the expression. as such, can only strip sub-expressions. */
if (expr.has_struct_base ())
{
auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
base_struct_expr->accept_vis (*this);
if (base_struct_expr->is_marked_for_strip ())
rust_error_at (base_struct_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
}
void
CfgStrip::visit (AST::StructExprStructBase &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says these are inner
* attributes, not outer attributes of inner expr */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
// strip sub-exprs of path
auto &struct_name = expr.get_struct_name ();
visit (struct_name);
if (struct_name.is_marked_for_strip ())
rust_error_at (struct_name.get_locus (),
"cannot strip path in this position");
/* struct base presumably can't be stripped, as the '..' is before
* the expression. as such, can only strip sub-expressions. */
rust_assert (!expr.get_struct_base ().is_invalid ());
auto &base_struct_expr = expr.get_struct_base ().get_base_struct ();
base_struct_expr->accept_vis (*this);
if (base_struct_expr->is_marked_for_strip ())
rust_error_at (base_struct_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::CallExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* should not be outer attrs on "function" expression - outer attrs
* should be associated with call expr as a whole. only sub-expr
* expansion is possible. */
AST::DefaultASTVisitor::visit (expr);
auto &function = expr.get_function_expr ();
if (function->is_marked_for_strip ())
rust_error_at (function->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
/* spec says outer attributes are specifically allowed for elements
* of call expressions, so full stripping possible */
// FIXME: Arthur: Figure out how to refactor this - This is similar to
// expanding items in the crate or stmts in blocks
maybe_strip_pointer_allow_strip (expr.get_params ());
}
void
CfgStrip::visit (AST::MethodCallExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* should not be outer attrs on "receiver" expression - outer attrs
* should be associated with call expr as a whole. only sub-expr
* expansion is possible. */
AST::DefaultASTVisitor::visit (expr);
auto &receiver = expr.get_receiver_expr ();
if (receiver->is_marked_for_strip ())
rust_error_at (receiver->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
auto &method_name = expr.get_method_name ();
if (method_name.has_generic_args ())
maybe_strip_generic_args (method_name.get_generic_args ());
/* spec says outer attributes are specifically allowed for elements
* of method call expressions, so full stripping possible */
maybe_strip_pointer_allow_strip (expr.get_params ());
}
void
CfgStrip::visit (AST::FieldAccessExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* should not be outer attrs on "receiver" expression - outer attrs
* should be associated with field expr as a whole. only sub-expr
* expansion is possible. */
AST::DefaultASTVisitor::visit (expr);
auto &receiver = expr.get_receiver_expr ();
if (receiver->is_marked_for_strip ())
rust_error_at (receiver->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ClosureExprInner &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip closure parameters if required - this is specifically
* allowed by spec */
maybe_strip_closure_params (expr.get_params ());
AST::DefaultASTVisitor::visit (expr);
// can't strip expression itself, but can strip sub-expressions
auto &definition_expr = expr.get_definition_expr ();
if (definition_expr->is_marked_for_strip ())
rust_error_at (definition_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::BlockExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip test based on inner attrs - spec says there are inner
* attributes, not just outer attributes of inner stmts */
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
maybe_strip_pointer_allow_strip (expr.get_statements ());
AST::DefaultASTVisitor::visit (expr);
// strip tail expression if exists - can actually fully remove it
if (expr.has_tail_expr ())
{
auto &tail_expr = expr.get_tail_expr ();
if (tail_expr->is_marked_for_strip ())
expr.strip_tail_expr ();
}
}
void
CfgStrip::visit (AST::ClosureExprInnerTyped &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* strip closure parameters if required - this is specifically
* allowed by spec */
maybe_strip_closure_params (expr.get_params ());
AST::DefaultASTVisitor::visit (expr);
// can't strip return type, but can strip sub-types
auto &type = expr.get_return_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
// can't strip expression itself, but can strip sub-expressions
auto &definition_block = expr.get_definition_block ();
definition_block->accept_vis (*this);
if (definition_block->is_marked_for_strip ())
rust_error_at (definition_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ContinueExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::BreakExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
/* spec does not say that you can have outer attributes on
* expression, so assuming you can't. stripping for sub-expressions
* is the only thing that can be done */
if (expr.has_break_expr ())
{
auto &break_expr = expr.get_break_expr ();
if (break_expr->is_marked_for_strip ())
rust_error_at (break_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
}
void
CfgStrip::visit (AST::RangeFromToExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* two direct descendant expressions, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
// ensure that they are not marked for strip
if (expr.get_from_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_from_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before range exprs");
if (expr.get_to_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_to_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::RangeFromExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* direct descendant expression, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
/* should have no possibility for outer attrs as would be parsed
* with outer expr */
auto &from_expr = expr.get_from_expr ();
if (from_expr->is_marked_for_strip ())
rust_error_at (from_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed before range exprs");
}
void
CfgStrip::visit (AST::RangeToExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* direct descendant expression, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &to_expr = expr.get_to_expr ();
if (to_expr->is_marked_for_strip ())
rust_error_at (to_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::RangeFromToInclExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* two direct descendant expressions, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
// ensure that they are not marked for strip
if (expr.get_from_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_from_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes are never allowed "
"before range exprs");
if (expr.get_to_expr ()->is_marked_for_strip ())
rust_error_at (expr.get_to_expr ()->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::RangeToInclExpr &expr)
{
/* outer attributes never allowed before these. while cannot strip
* direct descendant expression, can strip ones below that */
AST::DefaultASTVisitor::visit (expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &to_expr = expr.get_to_expr ();
if (to_expr->is_marked_for_strip ())
rust_error_at (to_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ReturnExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
/* spec does not say that you can have outer attributes on
* expression, so assuming you can't. stripping for sub-expressions
* is the only thing that can be done */
if (expr.has_returned_expr ())
{
auto &returned_expr = expr.get_returned_expr ();
if (returned_expr->is_marked_for_strip ())
rust_error_at (returned_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
/* TODO: conceptually, you would maybe be able to remove a returned
* expr - e.g. if you had conditional compilation returning void or
* returning a type. On the other hand, I think that function
* return type cannot be conditionally compiled, so I assumed you
* can't do this either. */
}
void
CfgStrip::visit (AST::UnsafeBlockExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip block itself, but can strip sub-expressions
auto &block_expr = expr.get_block_expr ();
if (block_expr->is_marked_for_strip ())
rust_error_at (block_expr->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::LoopExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip block itself, but can strip sub-expressions
auto &loop_block = expr.get_loop_block ();
if (loop_block->is_marked_for_strip ())
rust_error_at (loop_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::WhileLoopExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip predicate expr itself, but can strip sub-expressions
auto &predicate_expr = expr.get_predicate_expr ();
if (predicate_expr->is_marked_for_strip ())
rust_error_at (predicate_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip block itself, but can strip sub-expressions
auto &loop_block = expr.get_loop_block ();
if (loop_block->is_marked_for_strip ())
rust_error_at (loop_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::WhileLetLoopExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
for (auto &pattern : expr.get_patterns ())
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// can't strip scrutinee expr itself, but can strip sub-expressions
auto &scrutinee_expr = expr.get_scrutinee_expr ();
if (scrutinee_expr->is_marked_for_strip ())
rust_error_at (scrutinee_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip block itself, but can strip sub-expressions
auto &loop_block = expr.get_loop_block ();
if (loop_block->is_marked_for_strip ())
rust_error_at (loop_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::ForLoopExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// strip sub-patterns of pattern
auto &pattern = expr.get_pattern ();
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// can't strip scrutinee expr itself, but can strip sub-expressions
auto &iterator_expr = expr.get_iterator_expr ();
if (iterator_expr->is_marked_for_strip ())
rust_error_at (iterator_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip block itself, but can strip sub-expressions
auto &loop_block = expr.get_loop_block ();
if (loop_block->is_marked_for_strip ())
rust_error_at (loop_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::IfExpr &expr)
{
// rust playground test shows that IfExpr does support outer attrs, at least
// when used as statement
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip condition expr itself, but can strip sub-expressions
auto &condition_expr = expr.get_condition_expr ();
if (condition_expr->is_marked_for_strip ())
rust_error_at (condition_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip if block itself, but can strip sub-expressions
auto &if_block = expr.get_if_block ();
if (if_block->is_marked_for_strip ())
rust_error_at (if_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::IfExprConseqElse &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip condition expr itself, but can strip sub-expressions
auto &condition_expr = expr.get_condition_expr ();
if (condition_expr->is_marked_for_strip ())
rust_error_at (condition_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip if block itself, but can strip sub-expressions
auto &if_block = expr.get_if_block ();
if (if_block->is_marked_for_strip ())
rust_error_at (if_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
// can't strip else block itself, but can strip sub-expressions
auto &else_block = expr.get_else_block ();
if (else_block->is_marked_for_strip ())
rust_error_at (else_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::IfLetExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
for (auto &pattern : expr.get_patterns ())
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// can't strip value expr itself, but can strip sub-expressions
auto &value_expr = expr.get_value_expr ();
if (value_expr->is_marked_for_strip ())
rust_error_at (value_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip if block itself, but can strip sub-expressions
auto &if_block = expr.get_if_block ();
if (if_block->is_marked_for_strip ())
rust_error_at (if_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::IfLetExprConseqElse &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
for (auto &pattern : expr.get_patterns ())
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// can't strip value expr itself, but can strip sub-expressions
auto &value_expr = expr.get_value_expr ();
if (value_expr->is_marked_for_strip ())
rust_error_at (value_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// can't strip if block itself, but can strip sub-expressions
auto &if_block = expr.get_if_block ();
if (if_block->is_marked_for_strip ())
rust_error_at (if_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
// can't strip else block itself, but can strip sub-expressions
auto &else_block = expr.get_else_block ();
if (else_block->is_marked_for_strip ())
rust_error_at (else_block->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::MatchExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
// inner attr strip test
expand_cfg_attrs (expr.get_inner_attrs ());
if (fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip scrutinee expr itself, but can strip sub-expressions
auto &scrutinee_expr = expr.get_scrutinee_expr ();
if (scrutinee_expr->is_marked_for_strip ())
rust_error_at (scrutinee_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// strip match cases
auto &match_cases = expr.get_match_cases ();
for (auto it = match_cases.begin (); it != match_cases.end ();)
{
auto &match_case = *it;
// strip match case based on outer attributes in match arm
auto &match_arm = match_case.get_arm ();
expand_cfg_attrs (match_arm.get_outer_attrs ());
if (fails_cfg_with_expand (match_arm.get_outer_attrs ()))
{
// strip match case
it = match_cases.erase (it);
continue;
}
for (auto &pattern : match_arm.get_patterns ())
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
/* assuming that guard expression cannot be stripped as
* strictly speaking you would have to strip the whole guard to
* make syntactical sense, which you can't do. as such, only
* strip sub-expressions */
if (match_arm.has_match_arm_guard ())
{
auto &guard_expr = match_arm.get_guard_expr ();
if (guard_expr->is_marked_for_strip ())
rust_error_at (guard_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
// strip sub-expressions from match cases
auto &case_expr = match_case.get_expr ();
if (case_expr->is_marked_for_strip ())
rust_error_at (case_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
// increment to next case if haven't continued
++it;
}
}
void
CfgStrip::visit (AST::AwaitExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
/* can't strip awaited expr itself, but can strip sub-expressions
* - this is because you can't have no expr to await */
auto &awaited_expr = expr.get_awaited_expr ();
awaited_expr->accept_vis (*this);
if (awaited_expr->is_marked_for_strip ())
rust_error_at (awaited_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::AsyncBlockExpr &expr)
{
// initial strip test based on outer attrs
expand_cfg_attrs (expr.get_outer_attrs ());
if (fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (expr);
// can't strip block itself, but can strip sub-expressions
auto &block_expr = expr.get_block_expr ();
if (block_expr->is_marked_for_strip ())
rust_error_at (block_expr->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::TypeParam ¶m)
{
// outer attributes don't actually do anything, so ignore them
AST::DefaultASTVisitor::visit (param);
if (param.has_type () && param.get_type ()->is_marked_for_strip ())
rust_error_at (param.get_type ()->get_locus (),
"cannot strip type in this position");
}
void
CfgStrip::visit (AST::TypeBoundWhereClauseItem &item)
{
// for lifetimes shouldn't require
AST::DefaultASTVisitor::visit (item);
auto &type = item.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
}
void
CfgStrip::visit (AST::Module &module)
{
// strip test based on outer attrs
expand_cfg_attrs (module.get_outer_attrs ());
if (fails_cfg_with_expand (module.get_outer_attrs ()))
{
module.mark_for_strip ();
return;
}
// A loaded module might have inner attributes
if (module.get_kind () == AST::Module::ModuleKind::LOADED)
{
// strip test based on inner attrs
expand_cfg_attrs (module.get_inner_attrs ());
if (fails_cfg_with_expand (module.get_inner_attrs ()))
{
module.mark_for_strip ();
return;
}
}
// strip items if required
maybe_strip_pointer_allow_strip (module.get_items ());
}
void
CfgStrip::visit (AST::ExternCrate &extern_crate)
{
// strip test based on outer attrs
expand_cfg_attrs (extern_crate.get_outer_attrs ());
if (fails_cfg_with_expand (extern_crate.get_outer_attrs ()))
{
extern_crate.mark_for_strip ();
return;
}
if (!extern_crate.references_self ())
{
Session &session = Session::get_instance ();
session.load_extern_crate (extern_crate.get_referenced_crate (),
extern_crate.get_locus ());
}
}
void
CfgStrip::visit (AST::UseDeclaration &use_decl)
{
// strip test based on outer attrs
expand_cfg_attrs (use_decl.get_outer_attrs ());
if (fails_cfg_with_expand (use_decl.get_outer_attrs ()))
{
use_decl.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::Function &function)
{
// initial test based on outer attrs
expand_cfg_attrs (function.get_outer_attrs ());
if (fails_cfg_with_expand (function.get_outer_attrs ()))
{
function.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (function);
/* strip function parameters if required - this is specifically
* allowed by spec */
maybe_strip_function_params (function.get_function_params ());
if (function.has_return_type ())
{
auto &return_type = function.get_return_type ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
}
/* body should always exist - if error state, should have returned
* before now */
// can't strip block itself, but can strip sub-expressions
if (function.has_body ())
{
auto &block_expr = function.get_definition ();
if (block_expr.value ()->is_marked_for_strip ())
rust_error_at (block_expr.value ()->get_locus (),
"cannot strip block expression in this position - outer "
"attributes not allowed");
}
}
void
CfgStrip::visit (AST::TypeAlias &type_alias)
{
// initial test based on outer attrs
expand_cfg_attrs (type_alias.get_outer_attrs ());
if (fails_cfg_with_expand (type_alias.get_outer_attrs ()))
{
type_alias.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (type_alias);
auto &type = type_alias.get_type_aliased ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
}
void
CfgStrip::visit (AST::StructStruct &struct_item)
{
// initial test based on outer attrs
expand_cfg_attrs (struct_item.get_outer_attrs ());
if (fails_cfg_with_expand (struct_item.get_outer_attrs ()))
{
struct_item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (struct_item);
}
void
CfgStrip::visit (AST::TupleStruct &tuple_struct)
{
// initial test based on outer attrs
expand_cfg_attrs (tuple_struct.get_outer_attrs ());
if (fails_cfg_with_expand (tuple_struct.get_outer_attrs ()))
{
tuple_struct.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (tuple_struct);
/* strip struct fields if required - this is presumably
* allowed by spec */
maybe_strip_tuple_fields (tuple_struct.get_fields ());
}
void
CfgStrip::visit (AST::EnumItem &item)
{
// initial test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::EnumItemTuple &item)
{
// initial test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
/* strip item fields if required - this is presumably
* allowed by spec */
maybe_strip_tuple_fields (item.get_tuple_fields ());
}
void
CfgStrip::visit (AST::EnumItemStruct &item)
{
// initial test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
/* strip item fields if required - this is presumably
* allowed by spec */
maybe_strip_struct_fields (item.get_struct_fields ());
}
void
CfgStrip::visit (AST::EnumItemDiscriminant &item)
{
// initial test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (item);
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
auto &expr = item.get_expr ();
if (expr->is_marked_for_strip ())
rust_error_at (expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::Enum &enum_item)
{
// initial test based on outer attrs
expand_cfg_attrs (enum_item.get_outer_attrs ());
if (fails_cfg_with_expand (enum_item.get_outer_attrs ()))
{
enum_item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (enum_item);
/* strip enum fields if required - this is presumably
* allowed by spec */
maybe_strip_pointer_allow_strip (enum_item.get_variants ());
}
void
CfgStrip::visit (AST::Union &union_item)
{
// initial test based on outer attrs
expand_cfg_attrs (union_item.get_outer_attrs ());
if (fails_cfg_with_expand (union_item.get_outer_attrs ()))
{
union_item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (union_item);
/* strip union fields if required - this is presumably
* allowed by spec */
maybe_strip_struct_fields (union_item.get_variants ());
}
void
CfgStrip::visit (AST::ConstantItem &const_item)
{
// initial test based on outer attrs
expand_cfg_attrs (const_item.get_outer_attrs ());
if (fails_cfg_with_expand (const_item.get_outer_attrs ()))
{
const_item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (const_item);
// strip any sub-types
auto &type = const_item.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
if (const_item.has_expr ())
{
auto &expr = const_item.get_expr ();
if (expr->is_marked_for_strip ())
rust_error_at (expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
}
void
CfgStrip::visit (AST::StaticItem &static_item)
{
// initial test based on outer attrs
expand_cfg_attrs (static_item.get_outer_attrs ());
if (fails_cfg_with_expand (static_item.get_outer_attrs ()))
{
static_item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (static_item);
// strip any sub-types
auto &type = static_item.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
auto &expr = static_item.get_expr ();
if (expr->is_marked_for_strip ())
rust_error_at (expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
void
CfgStrip::visit (AST::TraitItemConst &item)
{
// initial test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (item);
// strip any sub-types
auto &type = item.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped */
if (item.has_expression ())
{
auto &expr = item.get_expr ();
if (expr->is_marked_for_strip ())
rust_error_at (expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
}
void
CfgStrip::visit (AST::TraitItemType &item)
{
// initial test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (item);
}
void
CfgStrip::visit (AST::Trait &trait)
{
// initial strip test based on outer attrs
expand_cfg_attrs (trait.get_outer_attrs ());
if (fails_cfg_with_expand (trait.get_outer_attrs ()))
{
trait.mark_for_strip ();
return;
}
// strip test based on inner attrs
expand_cfg_attrs (trait.get_inner_attrs ());
if (fails_cfg_with_expand (trait.get_inner_attrs ()))
{
trait.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (trait);
maybe_strip_pointer_allow_strip (trait.get_trait_items ());
}
void
CfgStrip::visit (AST::InherentImpl &impl)
{
// initial strip test based on outer attrs
expand_cfg_attrs (impl.get_outer_attrs ());
if (fails_cfg_with_expand (impl.get_outer_attrs ()))
{
impl.mark_for_strip ();
return;
}
// strip test based on inner attrs
expand_cfg_attrs (impl.get_inner_attrs ());
if (fails_cfg_with_expand (impl.get_inner_attrs ()))
{
impl.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (impl);
auto &type = impl.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
maybe_strip_pointer_allow_strip (impl.get_impl_items ());
}
void
CfgStrip::visit (AST::TraitImpl &impl)
{
// initial strip test based on outer attrs
expand_cfg_attrs (impl.get_outer_attrs ());
if (fails_cfg_with_expand (impl.get_outer_attrs ()))
{
impl.mark_for_strip ();
return;
}
// strip test based on inner attrs
expand_cfg_attrs (impl.get_inner_attrs ());
if (fails_cfg_with_expand (impl.get_inner_attrs ()))
{
impl.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (impl);
auto &type = impl.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
auto &trait_path = impl.get_trait_path ();
visit (trait_path);
if (trait_path.is_marked_for_strip ())
rust_error_at (trait_path.get_locus (),
"cannot strip typepath in this position");
maybe_strip_pointer_allow_strip (impl.get_impl_items ());
}
void
CfgStrip::visit (AST::ExternalTypeItem &item)
{
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
item.mark_for_strip ();
// TODO: Can we do anything like expand a macro here?
// extern "C" { type ffi_ty!(); }
// ?
}
void
CfgStrip::visit (AST::ExternalStaticItem &item)
{
// strip test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (item);
auto &type = item.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
}
void
CfgStrip::visit (AST::ExternalFunctionItem &item)
{
// strip test based on outer attrs
expand_cfg_attrs (item.get_outer_attrs ());
if (fails_cfg_with_expand (item.get_outer_attrs ()))
{
item.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (item);
/* strip function parameters if required - this is specifically
* allowed by spec */
auto ¶ms = item.get_function_params ();
for (auto it = params.begin (); it != params.end ();)
{
auto ¶m = *it;
auto ¶m_attrs = param.get_outer_attrs ();
expand_cfg_attrs (param_attrs);
if (fails_cfg_with_expand (param_attrs))
{
it = params.erase (it);
continue;
}
if (!param.is_variadic ())
{
auto &type = param.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
// increment if nothing else happens
++it;
}
/* NOTE: these are extern function params, which may have different
* rules and restrictions to "normal" function params. So expansion
* handled separately. */
/* TODO: assuming that variadic nature cannot be stripped. If this
* is not true, then have code here to do so. */
if (item.has_return_type ())
{
auto &return_type = item.get_return_type ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
}
}
void
CfgStrip::visit (AST::ExternBlock &block)
{
// initial strip test based on outer attrs
expand_cfg_attrs (block.get_outer_attrs ());
if (fails_cfg_with_expand (block.get_outer_attrs ()))
{
block.mark_for_strip ();
return;
}
// strip test based on inner attrs
expand_cfg_attrs (block.get_inner_attrs ());
if (fails_cfg_with_expand (block.get_inner_attrs ()))
{
block.mark_for_strip ();
return;
}
maybe_strip_pointer_allow_strip (block.get_extern_items ());
}
void
CfgStrip::visit (AST::MacroRulesDefinition &rules_def)
{
// initial strip test based on outer attrs
expand_cfg_attrs (rules_def.get_outer_attrs ());
if (fails_cfg_with_expand (rules_def.get_outer_attrs ()))
{
rules_def.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::IdentifierPattern &pattern)
{
// can only strip sub-patterns of the inner pattern to bind
if (!pattern.has_pattern_to_bind ())
return;
AST::DefaultASTVisitor::visit (pattern);
auto &sub_pattern = pattern.get_pattern_to_bind ();
if (sub_pattern->is_marked_for_strip ())
rust_error_at (sub_pattern->get_locus (),
"cannot strip pattern in this position");
}
void
CfgStrip::visit (AST::RangePatternBoundPath &bound)
{
// can expand path, but not strip it directly
auto &path = bound.get_path ();
visit (path);
if (path.is_marked_for_strip ())
rust_error_at (path.get_locus (), "cannot strip path in this position");
}
void
CfgStrip::visit (AST::RangePatternBoundQualPath &bound)
{
// can expand path, but not strip it directly
auto &path = bound.get_qualified_path ();
visit (path);
if (path.is_marked_for_strip ())
rust_error_at (path.get_locus (), "cannot strip path in this position");
}
void
CfgStrip::visit (AST::ReferencePattern &pattern)
{
AST::DefaultASTVisitor::visit (pattern);
auto &sub_pattern = pattern.get_referenced_pattern ();
if (sub_pattern->is_marked_for_strip ())
rust_error_at (sub_pattern->get_locus (),
"cannot strip pattern in this position");
}
void
CfgStrip::visit (AST::StructPatternFieldTuplePat &field)
{
// initial strip test based on outer attrs
expand_cfg_attrs (field.get_outer_attrs ());
if (fails_cfg_with_expand (field.get_outer_attrs ()))
{
field.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (field);
// strip sub-patterns (can't strip top-level pattern)
auto &sub_pattern = field.get_index_pattern ();
if (sub_pattern->is_marked_for_strip ())
rust_error_at (sub_pattern->get_locus (),
"cannot strip pattern in this position");
}
void
CfgStrip::visit (AST::StructPatternFieldIdentPat &field)
{
// initial strip test based on outer attrs
expand_cfg_attrs (field.get_outer_attrs ());
if (fails_cfg_with_expand (field.get_outer_attrs ()))
{
field.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (field);
// strip sub-patterns (can't strip top-level pattern)
auto &sub_pattern = field.get_ident_pattern ();
if (sub_pattern->is_marked_for_strip ())
rust_error_at (sub_pattern->get_locus (),
"cannot strip pattern in this position");
}
void
CfgStrip::visit (AST::StructPatternFieldIdent &field)
{
// initial strip test based on outer attrs
expand_cfg_attrs (field.get_outer_attrs ());
if (fails_cfg_with_expand (field.get_outer_attrs ()))
{
field.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::StructPattern &pattern)
{
// expand (but don't strip) path
auto &path = pattern.get_path ();
visit (path);
if (path.is_marked_for_strip ())
rust_error_at (path.get_locus (), "cannot strip path in this position");
/* TODO: apparently struct pattern fields can have outer attrs. so can they
* be stripped? */
if (!pattern.has_struct_pattern_elems ())
return;
auto &elems = pattern.get_struct_pattern_elems ();
// assuming you can strip struct pattern fields
maybe_strip_pointer_allow_strip (elems.get_struct_pattern_fields ());
// assuming you can strip the ".." part
if (elems.has_etc ())
{
expand_cfg_attrs (elems.get_etc_outer_attrs ());
if (fails_cfg_with_expand (elems.get_etc_outer_attrs ()))
elems.strip_etc ();
}
}
void
CfgStrip::visit (AST::TupleStructItemsNoRange &tuple_items)
{
AST::DefaultASTVisitor::visit (tuple_items);
// can't strip individual patterns, only sub-patterns
for (auto &pattern : tuple_items.get_patterns ())
{
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
}
void
CfgStrip::visit (AST::TupleStructItemsRange &tuple_items)
{
AST::DefaultASTVisitor::visit (tuple_items);
// can't strip individual patterns, only sub-patterns
for (auto &lower_pattern : tuple_items.get_lower_patterns ())
{
if (lower_pattern->is_marked_for_strip ())
rust_error_at (lower_pattern->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
for (auto &upper_pattern : tuple_items.get_upper_patterns ())
{
if (upper_pattern->is_marked_for_strip ())
rust_error_at (upper_pattern->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
}
void
CfgStrip::visit (AST::TupleStructPattern &pattern)
{
// expand (but don't strip) path
auto &path = pattern.get_path ();
visit (path);
if (path.is_marked_for_strip ())
rust_error_at (path.get_locus (), "cannot strip path in this position");
AST::DefaultASTVisitor::visit (pattern);
}
void
CfgStrip::visit (AST::TuplePatternItemsMultiple &tuple_items)
{
AST::DefaultASTVisitor::visit (tuple_items);
// can't strip individual patterns, only sub-patterns
for (auto &pattern : tuple_items.get_patterns ())
{
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
}
void
CfgStrip::visit (AST::TuplePatternItemsRanged &tuple_items)
{
AST::DefaultASTVisitor::visit (tuple_items);
// can't strip individual patterns, only sub-patterns
for (auto &lower_pattern : tuple_items.get_lower_patterns ())
{
if (lower_pattern->is_marked_for_strip ())
rust_error_at (lower_pattern->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
for (auto &upper_pattern : tuple_items.get_upper_patterns ())
{
if (upper_pattern->is_marked_for_strip ())
rust_error_at (upper_pattern->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
}
void
CfgStrip::visit (AST::GroupedPattern &pattern)
{
AST::DefaultASTVisitor::visit (pattern);
// can't strip inner pattern, only sub-patterns
auto &pattern_in_parens = pattern.get_pattern_in_parens ();
if (pattern_in_parens->is_marked_for_strip ())
rust_error_at (pattern_in_parens->get_locus (),
"cannot strip pattern in this position");
}
void
CfgStrip::visit (AST::SlicePattern &pattern)
{
AST::DefaultASTVisitor::visit (pattern);
// can't strip individual patterns, only sub-patterns
for (auto &item : pattern.get_items ())
{
if (item->is_marked_for_strip ())
rust_error_at (item->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
}
void
CfgStrip::visit (AST::AltPattern &pattern)
{
AST::DefaultASTVisitor::visit (pattern);
// can't strip individual patterns, only sub-patterns
for (auto &alt : pattern.get_alts ())
{
if (alt->is_marked_for_strip ())
rust_error_at (alt->get_locus (),
"cannot strip pattern in this position");
// TODO: quit stripping now? or keep going?
}
}
void
CfgStrip::visit (AST::LetStmt &stmt)
{
// initial strip test based on outer attrs
expand_cfg_attrs (stmt.get_outer_attrs ());
if (fails_cfg_with_expand (stmt.get_outer_attrs ()))
{
stmt.mark_for_strip ();
return;
}
AST::DefaultASTVisitor::visit (stmt);
// can't strip pattern, but call for sub-patterns
auto &pattern = stmt.get_pattern ();
if (pattern->is_marked_for_strip ())
rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
// similar for type
if (stmt.has_type ())
{
auto &type = stmt.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped */
if (stmt.has_init_expr ())
{
auto &init_expr = stmt.get_init_expr ();
if (init_expr->is_marked_for_strip ())
rust_error_at (init_expr->get_locus (),
"cannot strip expression in this position - outer "
"attributes not allowed");
}
}
void
CfgStrip::visit (AST::ExprStmt &stmt)
{
// outer attributes associated with expr, so rely on expr
// guard - should prevent null pointer expr
if (stmt.is_marked_for_strip ())
return;
AST::DefaultASTVisitor::visit (stmt);
// strip if expr is to be stripped
auto &expr = stmt.get_expr ();
if (expr->is_marked_for_strip ())
{
stmt.mark_for_strip ();
return;
}
}
void
CfgStrip::visit (AST::TraitBound &bound)
{
// nothing in for lifetimes to strip
// expand but don't strip type path
auto &path = bound.get_type_path ();
visit (path);
if (path.is_marked_for_strip ())
rust_error_at (path.get_locus (),
"cannot strip type path in this position");
}
void
CfgStrip::visit (AST::ParenthesisedType &type)
{
AST::DefaultASTVisitor::visit (type);
// expand but don't strip inner type
auto &inner_type = type.get_type_in_parens ();
if (inner_type->is_marked_for_strip ())
rust_error_at (inner_type->get_locus (),
"cannot strip type in this position");
}
void
CfgStrip::visit (AST::TupleType &type)
{
AST::DefaultASTVisitor::visit (type);
// TODO: assuming that types can't be stripped as types don't have outer
// attributes
for (auto &elem_type : type.get_elems ())
{
if (elem_type->is_marked_for_strip ())
rust_error_at (elem_type->get_locus (),
"cannot strip type in this position");
}
}
void
CfgStrip::visit (AST::RawPointerType &type)
{
AST::DefaultASTVisitor::visit (type);
// expand but don't strip type pointed to
auto &pointed_type = type.get_type_pointed_to ();
if (pointed_type->is_marked_for_strip ())
rust_error_at (pointed_type->get_locus (),
"cannot strip type in this position");
}
void
CfgStrip::visit (AST::ReferenceType &type)
{
AST::DefaultASTVisitor::visit (type);
// expand but don't strip type referenced
auto &referenced_type = type.get_type_referenced ();
if (referenced_type->is_marked_for_strip ())
rust_error_at (referenced_type->get_locus (),
"cannot strip type in this position");
}
void
CfgStrip::visit (AST::ArrayType &type)
{
AST::DefaultASTVisitor::visit (type);
// expand but don't strip type referenced
auto &base_type = type.get_elem_type ();
if (base_type->is_marked_for_strip ())
rust_error_at (base_type->get_locus (),
"cannot strip type in this position");
// same for expression
auto &size_expr = type.get_size_expr ();
if (size_expr->is_marked_for_strip ())
rust_error_at (size_expr->get_locus (),
"cannot strip expression in this position");
}
void
CfgStrip::visit (AST::SliceType &type)
{
AST::DefaultASTVisitor::visit (type);
// expand but don't strip elem type
auto &elem_type = type.get_elem_type ();
if (elem_type->is_marked_for_strip ())
rust_error_at (elem_type->get_locus (),
"cannot strip type in this position");
}
void
CfgStrip::visit (AST::BareFunctionType &type)
{
// seem to be no generics
AST::DefaultASTVisitor::visit (type);
// presumably function params can be stripped
auto ¶ms = type.get_function_params ();
for (auto it = params.begin (); it != params.end ();)
{
auto ¶m = *it;
auto ¶m_attrs = param.get_outer_attrs ();
expand_cfg_attrs (param_attrs);
if (fails_cfg_with_expand (param_attrs))
{
it = params.erase (it);
continue;
}
auto &type = param.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
// increment if nothing else happens
++it;
}
/* TODO: assuming that variadic nature cannot be stripped. If this
* is not true, then have code here to do so. */
if (type.has_return_type ())
{
// FIXME: Can we have type expansion in this position?
// In that case, we need to handle AST::TypeNoBounds on top of just
// AST::Types
auto &return_type = type.get_return_type ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
}
// no where clause, apparently
}
void
CfgStrip::visit (AST::SelfParam ¶m)
{
AST::DefaultASTVisitor::visit (param);
if (param.has_type ())
{
auto &type = param.get_type ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
/* TODO: maybe check for invariants being violated - e.g. both type and
* lifetime? */
}
} // namespace Rust