diff options
author | SimplyTheOther <simplytheother@gmail.com> | 2020-11-17 22:00:30 +0800 |
---|---|---|
committer | SimplyTheOther <simplytheother@gmail.com> | 2020-12-08 21:10:32 +0800 |
commit | 9b252167a77316750f34c455222e5f30724e51e4 (patch) | |
tree | e5a69430cc9104031ef958852605f15c6aa76494 | |
parent | 4ec3b8d62b1b6ae79d55b71b423dcb04129884c6 (diff) | |
download | gcc-9b252167a77316750f34c455222e5f30724e51e4.zip gcc-9b252167a77316750f34c455222e5f30724e51e4.tar.gz gcc-9b252167a77316750f34c455222e5f30724e51e4.tar.bz2 |
Added more expression cfg stripping
Fixed compile errors
-rw-r--r-- | gcc/rust/ast/rust-ast-full-test.cc | 12 | ||||
-rw-r--r-- | gcc/rust/ast/rust-expr.h | 164 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile.cc | 22 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 532 |
4 files changed, 660 insertions, 70 deletions
diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc index f9dd99c..5601a1a 100644 --- a/gcc/rust/ast/rust-ast-full-test.cc +++ b/gcc/rust/ast/rust-ast-full-test.cc @@ -1700,10 +1700,8 @@ ReturnExpr::as_string () const { std::string str ("return "); - if (has_return_expr ()) - { + if (has_returned_expr ()) str += return_expr->as_string (); - } return str; } @@ -2255,13 +2253,9 @@ WhileLetLoopExpr::as_string () const str += "\n Label: "; if (!has_loop_label ()) - { str += "none"; - } else - { str += loop_label.as_string (); - } str += "\n Match arm patterns: "; if (match_arm_patterns.empty ()) @@ -2271,12 +2265,10 @@ WhileLetLoopExpr::as_string () const else { for (const auto &pattern : match_arm_patterns) - { str += "\n " + pattern->as_string (); - } } - str += "\n Scrutinee expr: " + condition->as_string (); + str += "\n Scrutinee expr: " + scrutinee->as_string (); str += "\n Loop block: " + loop_block->as_string (); diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 66ffe16..df77611 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -3281,7 +3281,6 @@ protected: // Return expression AST node representation class ReturnExpr : public ExprWithoutBlock { -public: std::unique_ptr<Expr> return_expr; Location locus; @@ -3289,11 +3288,12 @@ public: // TODO: find another way to store this to save memory? bool marked_for_strip = false; +public: std::string as_string () const override; /* Returns whether the object has an expression returned (i.e. not void return * type). */ - bool has_return_expr () const { return return_expr != nullptr; } + bool has_returned_expr () const { return return_expr != nullptr; } // Constructor for ReturnExpr. ReturnExpr (Location locus, std::unique_ptr<Expr> returned_expr = nullptr, @@ -3341,6 +3341,12 @@ public: void mark_for_strip () override { marked_for_strip = true; } bool is_marked_for_strip () const override { return marked_for_strip; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_returned_expr () { + rust_assert (return_expr != nullptr); + return return_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3358,7 +3364,6 @@ class UnsafeBlockExpr : public ExprWithBlock { // Or just have it extend BlockExpr std::unique_ptr<BlockExpr> expr; - Location locus; public: @@ -3408,6 +3413,12 @@ public: void mark_for_strip () override { expr = nullptr; } bool is_marked_for_strip () const override { return expr == nullptr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_block_expr () { + rust_assert (expr != nullptr); + return expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3422,7 +3433,6 @@ protected: class LoopLabel /*: public Node*/ { Lifetime label; // or type LIFETIME_OR_LABEL - Location locus; public: @@ -3504,6 +3514,12 @@ public: // Invalid if loop block is null, so base stripping on that. void mark_for_strip () override { loop_block = nullptr; } bool is_marked_for_strip () const override { return loop_block == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_loop_block () { + rust_assert (loop_block != nullptr); + return loop_block; + } }; // 'Loop' expression (i.e. the infinite loop) AST node @@ -3573,6 +3589,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_predicate_expr () { + rust_assert (condition != nullptr); + return condition; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3587,14 +3609,14 @@ class WhileLetLoopExpr : public BaseLoopExpr { // MatchArmPatterns patterns; std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined - std::unique_ptr<Expr> condition; + std::unique_ptr<Expr> scrutinee; public: std::string as_string () const override; // Constructor with a loop label WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, - std::unique_ptr<Expr> condition, + std::unique_ptr<Expr> scrutinee, std::unique_ptr<BlockExpr> loop_block, Location locus, LoopLabel loop_label = LoopLabel::error (), std::vector<Attribute> outer_attribs @@ -3602,14 +3624,14 @@ public: : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), std::move (outer_attribs)), match_arm_patterns (std::move (match_arm_patterns)), - condition (std::move (condition)) + scrutinee (std::move (scrutinee)) {} // Copy constructor with clone WhileLetLoopExpr (WhileLetLoopExpr const &other) : BaseLoopExpr (other), - /*match_arm_patterns(other.match_arm_patterns),*/ condition ( - other.condition->clone_expr ()) + /*match_arm_patterns(other.match_arm_patterns),*/ scrutinee ( + other.scrutinee->clone_expr ()) { match_arm_patterns.reserve (other.match_arm_patterns.size ()); for (const auto &e : other.match_arm_patterns) @@ -3621,7 +3643,7 @@ public: { BaseLoopExpr::operator= (other); // match_arm_patterns = other.match_arm_patterns; - condition = other.condition->clone_expr (); + scrutinee = other.scrutinee->clone_expr (); // loop_block = other.loop_block->clone_block_expr(); // loop_label = other.loop_label; // outer_attrs = other.outer_attrs; @@ -3639,6 +3661,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_scrutinee_expr () { + rust_assert (scrutinee != nullptr); + return scrutinee; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3694,6 +3722,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_iterator_expr () { + rust_assert (iterator_expr != nullptr); + return iterator_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3777,8 +3811,17 @@ public: void vis_if_condition (ASTVisitor &vis) { condition->accept_vis (vis); } void vis_if_block (ASTVisitor &vis) { if_block->accept_vis (vis); } - Expr *get_if_condition () { return condition.get (); } - BlockExpr *get_if_block () { return if_block.get (); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_condition_expr () { + rust_assert (condition != nullptr); + return condition; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_if_block () { + rust_assert (if_block != nullptr); + return if_block; + } // Invalid if if block or condition is null, so base stripping on that. void mark_for_strip () override { if_block = nullptr; condition = nullptr; } @@ -3836,6 +3879,12 @@ public: void vis_else_block (ASTVisitor &vis) { else_block->accept_vis (vis); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_else_block () { + rust_assert (else_block != nullptr); + return else_block; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3888,6 +3937,12 @@ public: conseq_if_expr->accept_vis (vis); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfExpr> &get_conseq_if_expr () { + rust_assert (conseq_if_expr != nullptr); + return conseq_if_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3976,6 +4031,18 @@ public: void mark_for_strip () override { if_block = nullptr; value = nullptr; } bool is_marked_for_strip () const override { return if_block == nullptr && value == nullptr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_value_expr () { + rust_assert (value != nullptr); + return value; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_if_block () { + rust_assert (if_block != nullptr); + return if_block; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base (or rather this or any derived object) */ @@ -4030,6 +4097,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfLetExpr> &get_conseq_if_let_expr () { + rust_assert (if_let_expr != nullptr); + return if_let_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4082,6 +4155,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_else_block () { + rust_assert (else_block != nullptr); + return else_block; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4133,6 +4212,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfExpr> &get_conseq_if_expr () { + rust_assert (if_expr != nullptr); + return if_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4184,6 +4269,12 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfLetExpr> &get_conseq_if_let_expr () { + rust_assert (if_let_expr != nullptr); + return if_let_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4265,6 +4356,16 @@ public: } std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_guard_expr () { + rust_assert (has_match_arm_guard ()); + return guard_expr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } }; /* @@ -4330,6 +4431,18 @@ public: ~MatchCase () = default; std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr () { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + MatchArm &get_arm () { + rust_assert (!arm.is_error ()); + return arm; + } }; #if 0 @@ -4502,6 +4615,19 @@ public: void mark_for_strip () override { branch_value = nullptr; } bool is_marked_for_strip () const override { return branch_value == nullptr; } + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_scrutinee_expr () { + rust_assert (branch_value != nullptr); + return branch_value; + } + + const std::vector<MatchCase> &get_match_cases () const { return match_arms; } + std::vector<MatchCase> &get_match_cases () { return match_arms; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4515,7 +4641,6 @@ protected: class AwaitExpr : public ExprWithoutBlock { std::unique_ptr<Expr> awaited_expr; - Location locus; public: @@ -4565,6 +4690,12 @@ public: void mark_for_strip () override { awaited_expr = nullptr; } bool is_marked_for_strip () const override { return awaited_expr == nullptr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_awaited_expr () { + rust_assert (awaited_expr != nullptr); + return awaited_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4580,7 +4711,6 @@ class AsyncBlockExpr : public ExprWithBlock // TODO: should this extend BlockExpr rather than be a composite of it? bool has_move; std::unique_ptr<BlockExpr> block_expr; - Location locus; public: @@ -4630,6 +4760,12 @@ public: void mark_for_strip () override { block_expr = nullptr; } bool is_marked_for_strip () const override { return block_expr == nullptr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_block_expr () { + rust_assert (block_expr != nullptr); + return block_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index 17d9cde..eb01b12 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -740,10 +740,10 @@ void Compilation::visit (AST::ReturnExpr &expr) { Bexpression *ret = NULL; - VISIT_POP (expr.return_expr->get_locus_slow (), expr.return_expr, ret, exprs); + VISIT_POP (expr.get_returned_expr ()->get_locus_slow (), expr.get_returned_expr ().get (), ret, exprs); if (ret == NULL) { - rust_fatal_error (expr.return_expr->get_locus_slow (), + rust_fatal_error (expr.get_returned_expr ()->get_locus_slow (), "failed to compile"); return; } @@ -778,11 +778,11 @@ void Compilation::visit (AST::IfExpr &expr) { Bexpression *cond = NULL; - VISIT_POP (expr.get_if_condition ()->get_locus_slow (), - expr.get_if_condition (), cond, exprs); + VISIT_POP (expr.get_condition_expr ()->get_locus_slow (), + expr.get_condition_expr ().get (), cond, exprs); if (cond == NULL) { - rust_error_at (expr.get_if_condition ()->get_locus_slow (), + rust_error_at (expr.get_condition_expr ()->get_locus_slow (), "failed to compile"); return; } @@ -799,11 +799,11 @@ void Compilation::visit (AST::IfExprConseqElse &expr) { Bexpression *cond = NULL; - VISIT_POP (expr.get_if_condition ()->get_locus_slow (), - expr.get_if_condition (), cond, exprs); + VISIT_POP (expr.get_condition_expr ()->get_locus_slow (), + expr.get_condition_expr ().get (), cond, exprs); if (cond == NULL) { - rust_error_at (expr.get_if_condition ()->get_locus_slow (), + rust_error_at (expr.get_condition_expr ()->get_locus_slow (), "failed to compile"); return; } @@ -824,11 +824,11 @@ void Compilation::visit (AST::IfExprConseqIf &expr) { Bexpression *cond = NULL; - VISIT_POP (expr.get_if_condition ()->get_locus_slow (), - expr.get_if_condition (), cond, exprs); + VISIT_POP (expr.get_condition_expr ()->get_locus_slow (), + expr.get_condition_expr ().get (), cond, exprs); if (cond == NULL) { - rust_error_at (expr.get_if_condition ()->get_locus_slow (), + rust_error_at (expr.get_condition_expr ()->get_locus_slow (), "failed to compile"); return; } diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 417f51b..7dd9750 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -956,23 +956,436 @@ namespace Rust { rust_error_at(to_expr->get_locus_slow(), "cannot strip expression in this position - outer attributes not allowed"); } - void visit(AST::ReturnExpr& expr) override {} - void visit(AST::UnsafeBlockExpr& expr) override {} - void visit(AST::LoopExpr& expr) override {} - void visit(AST::WhileLoopExpr& expr) override {} - void visit(AST::WhileLetLoopExpr& expr) override {} - void visit(AST::ForLoopExpr& expr) override {} - void visit(AST::IfExpr& expr) override {} - void visit(AST::IfExprConseqElse& expr) override {} - void visit(AST::IfExprConseqIf& expr) override {} - void visit(AST::IfExprConseqIfLet& expr) override {} - void visit(AST::IfLetExpr& expr) override {} - void visit(AST::IfLetExprConseqElse& expr) override {} - void visit(AST::IfLetExprConseqIf& expr) override {} - void visit(AST::IfLetExprConseqIfLet& expr) override {} - void visit(AST::MatchExpr& expr) override {} - void visit(AST::AwaitExpr& expr) override {} - void visit(AST::AsyncBlockExpr& expr) override {} + void visit(AST::ReturnExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + /* 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(); + + returned_expr->accept_vis(*this); + + if (returned_expr->is_marked_for_strip()) + rust_error_at(returned_expr->get_locus_slow(), + "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 visit(AST::UnsafeBlockExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip block itself, but can strip sub-expressions + auto& block_expr = expr.get_block_expr(); + block_expr->accept_vis(*this); + if (block_expr->is_marked_for_strip()) + rust_error_at(block_expr->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::LoopExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip block itself, but can strip sub-expressions + auto& loop_block = expr.get_loop_block(); + loop_block->accept_vis(*this); + if (loop_block->is_marked_for_strip()) + rust_error_at(loop_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::WhileLoopExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip predicate expr itself, but can strip sub-expressions + auto& predicate_expr = expr.get_predicate_expr(); + predicate_expr->accept_vis(*this); + if (predicate_expr->is_marked_for_strip()) + rust_error_at(predicate_expr->get_locus_slow(), + "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(); + loop_block->accept_vis(*this); + if (loop_block->is_marked_for_strip()) + rust_error_at(loop_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::WhileLetLoopExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip scrutinee expr itself, but can strip sub-expressions + auto& scrutinee_expr = expr.get_scrutinee_expr(); + scrutinee_expr->accept_vis(*this); + if (scrutinee_expr->is_marked_for_strip()) + rust_error_at(scrutinee_expr->get_locus_slow(), + "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(); + loop_block->accept_vis(*this); + if (loop_block->is_marked_for_strip()) + rust_error_at(loop_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::ForLoopExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip scrutinee expr itself, but can strip sub-expressions + auto& iterator_expr = expr.get_iterator_expr(); + iterator_expr->accept_vis(*this); + if (iterator_expr->is_marked_for_strip()) + rust_error_at(iterator_expr->get_locus_slow(), + "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(); + loop_block->accept_vis(*this); + if (loop_block->is_marked_for_strip()) + rust_error_at(loop_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::IfExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto& condition_expr = expr.get_condition_expr(); + condition_expr->accept_vis(*this); + if (condition_expr->is_marked_for_strip()) + rust_error_at(condition_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::IfExprConseqElse& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto& condition_expr = expr.get_condition_expr(); + condition_expr->accept_vis(*this); + if (condition_expr->is_marked_for_strip()) + rust_error_at(condition_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "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(); + else_block->accept_vis(*this); + if (else_block->is_marked_for_strip()) + rust_error_at(else_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::IfExprConseqIf& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto& condition_expr = expr.get_condition_expr(); + condition_expr->accept_vis(*this); + if (condition_expr->is_marked_for_strip()) + rust_error_at(condition_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + + // can't strip if expr itself, but can strip sub-expressions + auto& conseq_if_expr = expr.get_conseq_if_expr(); + conseq_if_expr->accept_vis(*this); + if (conseq_if_expr->is_marked_for_strip()) + rust_error_at(conseq_if_expr->get_locus_slow(), + "cannot strip consequent if expression in this position - outer attributes not allowed"); + } + void visit(AST::IfExprConseqIfLet& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto& condition_expr = expr.get_condition_expr(); + condition_expr->accept_vis(*this); + if (condition_expr->is_marked_for_strip()) + rust_error_at(condition_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + + // can't strip if let expr itself, but can strip sub-expressions + auto& conseq_if_let_expr = expr.get_conseq_if_let_expr(); + conseq_if_let_expr->accept_vis(*this); + if (conseq_if_let_expr->is_marked_for_strip()) + rust_error_at(conseq_if_let_expr->get_locus_slow(), + "cannot strip consequent if let expression in this position - outer attributes not allowed"); + } + void visit(AST::IfLetExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip value expr itself, but can strip sub-expressions + auto& value_expr = expr.get_value_expr(); + value_expr->accept_vis(*this); + if (value_expr->is_marked_for_strip()) + rust_error_at(value_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::IfLetExprConseqElse& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip value expr itself, but can strip sub-expressions + auto& value_expr = expr.get_value_expr(); + value_expr->accept_vis(*this); + if (value_expr->is_marked_for_strip()) + rust_error_at(value_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "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(); + else_block->accept_vis(*this); + if (else_block->is_marked_for_strip()) + rust_error_at(else_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } + void visit(AST::IfLetExprConseqIf& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip value expr itself, but can strip sub-expressions + auto& value_expr = expr.get_value_expr(); + value_expr->accept_vis(*this); + if (value_expr->is_marked_for_strip()) + rust_error_at(value_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + + // can't strip if expr itself, but can strip sub-expressions + auto& conseq_if_expr = expr.get_conseq_if_expr(); + conseq_if_expr->accept_vis(*this); + if (conseq_if_expr->is_marked_for_strip()) + rust_error_at(conseq_if_expr->get_locus_slow(), + "cannot strip consequent if expression in this position - outer attributes not allowed"); + } + void visit(AST::IfLetExprConseqIfLet& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip value expr itself, but can strip sub-expressions + auto& value_expr = expr.get_value_expr(); + value_expr->accept_vis(*this); + if (value_expr->is_marked_for_strip()) + rust_error_at(value_expr->get_locus_slow(), + "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_block->accept_vis(*this); + if (if_block->is_marked_for_strip()) + rust_error_at(if_block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + + // can't strip if let expr itself, but can strip sub-expressions + auto& conseq_if_let_expr = expr.get_conseq_if_let_expr(); + conseq_if_let_expr->accept_vis(*this); + if (conseq_if_let_expr->is_marked_for_strip()) + rust_error_at(conseq_if_let_expr->get_locus_slow(), + "cannot strip consequent if let expression in this position - outer attributes not allowed"); + } + void visit(AST::MatchExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // inner attr strip test + expander.expand_cfg_attrs(expr.get_inner_attrs()); + if (expander.fails_cfg(expr.get_inner_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip scrutinee expr itself, but can strip sub-expressions + auto& scrutinee_expr = expr.get_scrutinee_expr(); + scrutinee_expr->accept_vis(*this); + if (scrutinee_expr->is_marked_for_strip()) + rust_error_at(scrutinee_expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); + + // strip match cases + auto& match_cases = expr.get_match_cases(); + for (int i = 0; i < match_cases.size(); ) { + auto& match_case = match_cases[i]; + + // strip match case based on outer attributes in match arm + auto& match_arm = match_case.get_arm(); + expander.expand_cfg_attrs(match_arm.get_outer_attrs()); + if (expander.fails_cfg(match_arm.get_outer_attrs())) { + // strip match case + match_cases.erase(match_cases.begin() + i); + continue; + } + + /* 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(); + guard_expr->accept_vis(*this); + if (guard_expr->is_marked_for_strip()) + rust_error_at(guard_expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); + } + + // strip sub-expressions from match cases + auto& case_expr = match_case.get_expr(); + case_expr->accept_vis(*this); + if (case_expr->is_marked_for_strip()) + rust_error_at(case_expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); + + // increment to next case if haven't continued + i++; + } + } + void visit(AST::AwaitExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(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_slow(), + "cannot strip expression in this position - outer attributes not allowed"); + } + void visit(AST::AsyncBlockExpr& expr) override { + // initial strip test based on outer attrs + expander.expand_cfg_attrs(expr.get_outer_attrs()); + if (expander.fails_cfg(expr.get_outer_attrs())) { + expr.mark_for_strip(); + return; + } + + // can't strip block itself, but can strip sub-expressions + auto& block_expr = expr.get_block_expr(); + block_expr->accept_vis(*this); + if (block_expr->is_marked_for_strip()) + rust_error_at(block_expr->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); + } void visit(AST::TypeParam& param) override { // shouldn't require? @@ -1001,8 +1414,12 @@ namespace Rust { /* body should always exist - if error state, should have returned * before now */ - method.get_definition()->accept_vis(*this); - // TODO: can block as a whole be invalidated here? Assuming no + // can't strip block itself, but can strip sub-expressions + auto& block_expr = method.get_definition(); + block_expr->accept_vis(*this); + if (block_expr->is_marked_for_strip()) + rust_error_at(block_expr->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); } void visit(AST::ModuleBodied& module) override { // strip test based on outer attrs @@ -1080,8 +1497,12 @@ namespace Rust { /* body should always exist - if error state, should have returned * before now */ - function.get_definition()->accept_vis(*this); - // TODO: can block as a whole be invalidated here? Assuming no + // can't strip block itself, but can strip sub-expressions + auto& block_expr = function.get_definition(); + block_expr->accept_vis(*this); + if (block_expr->is_marked_for_strip()) + rust_error_at(block_expr->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); } void visit(AST::TypeAlias& type_alias) override { // initial test based on outer attrs @@ -1158,7 +1579,11 @@ namespace Rust { /* strip any internal sub-expressions - expression itself isn't * allowed to have external attributes in this position so can't be * stripped. */ - item.get_expr()->accept_vis(*this); + auto& expr = item.get_expr(); + expr->accept_vis(*this); + if (expr->is_marked_for_strip()) + rust_error_at(expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); } void visit(AST::Enum& enum_item) override { // initial test based on outer attrs @@ -1206,7 +1631,11 @@ namespace Rust { /* strip any internal sub-expressions - expression itself isn't * allowed to have external attributes in this position so can't be * stripped. */ - const_item.get_expr()->accept_vis(*this); + auto& expr = const_item.get_expr(); + expr->accept_vis(*this); + if (expr->is_marked_for_strip()) + rust_error_at(expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); } void visit(AST::StaticItem& static_item) override { // initial test based on outer attrs @@ -1219,7 +1648,11 @@ namespace Rust { /* strip any internal sub-expressions - expression itself isn't * allowed to have external attributes in this position so can't be * stripped. */ - static_item.get_expr()->accept_vis(*this); + auto& expr = static_item.get_expr(); + expr->accept_vis(*this); + if (expr->is_marked_for_strip()) + rust_error_at(expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); } void visit(AST::TraitItemFunc& item) override { // initial test based on outer attrs @@ -1234,8 +1667,14 @@ namespace Rust { expand_function_params(item.get_function_params()); if (item.has_definition()) { - item.get_definition()->accept_vis(*this); - // TODO: can block as a whole be invalidated here? Assuming no + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto& block = item.get_definition(); + block->accept_vis(*this); + if (block->is_marked_for_strip()) + rust_error_at(block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); } } void visit(AST::TraitItemMethod& item) override { @@ -1255,8 +1694,14 @@ namespace Rust { expand_function_params(item.get_function_params()); if (item.has_definition()) { - item.get_definition()->accept_vis(*this); - // TODO: can block as a whole be invalidated here? Assuming no + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto& block = item.get_definition(); + block->accept_vis(*this); + if (block->is_marked_for_strip()) + rust_error_at(block->get_locus_slow(), + "cannot strip block expression in this position - outer attributes not allowed"); } } void visit(AST::TraitItemConst& item) override { @@ -1270,8 +1715,13 @@ namespace Rust { /* 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()) - item.get_expr()->accept_vis(*this); + if (item.has_expression()) { + auto& expr = item.get_expr(); + expr->accept_vis(*this); + if (expr->is_marked_for_strip()) + rust_error_at(expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); + } } void visit(AST::TraitItemType& item) override { // initial test based on outer attrs @@ -1474,7 +1924,9 @@ namespace Rust { void visit(AST::StructPatternFieldTuplePat& field) override {} void visit(AST::StructPatternFieldIdentPat& field) override {} void visit(AST::StructPatternFieldIdent& field) override {} - void visit(AST::StructPattern& pattern) override {} + void visit(AST::StructPattern& pattern) override { + // TODO: apparently struct pattern fields can have outer attrs. so can they be stripped? + } void visit(AST::TupleStructItemsNoRange& tuple_items) override {} void visit(AST::TupleStructItemsRange& tuple_items) override {} void visit(AST::TupleStructPattern& pattern) override {} @@ -1498,8 +1950,13 @@ namespace Rust { /* 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()) - stmt.get_init_expr()->accept_vis(*this); + if (stmt.has_init_expr()) { + auto& init_expr = stmt.get_init_expr(); + init_expr->accept_vis(*this); + if (init_expr->is_marked_for_strip()) + rust_error_at(init_expr->get_locus_slow(), + "cannot strip expression in this position - outer attributes not allowed"); + } } void visit(AST::ExprStmtWithoutBlock& stmt) override { // outer attributes associated with expr, so rely on expr @@ -1543,10 +2000,15 @@ namespace Rust { void visit(AST::NeverType& type) override {} void visit(AST::RawPointerType& type) override {} void visit(AST::ReferenceType& type) override {} - void visit(AST::ArrayType& type) override {} + void visit(AST::ArrayType& type) override { + // TODO: array type contains a "constant expression" - could this have strippable sub-exprs? + } void visit(AST::SliceType& type) override {} void visit(AST::InferredType& type) override {} - void visit(AST::BareFunctionType& type) override {} + void visit(AST::BareFunctionType& type) override { + // TODO: bare function type contains "maybe-named params" that have outer attributes - could this be strippable? + // apparently "attribute rules are same as on regular function params", so looks like a yes + } }; void MacroExpander::expand_invoc(std::unique_ptr<AST::MacroInvocation>& invoc) { |