diff options
Diffstat (limited to 'lib/Parse/AstGuard.h')
-rw-r--r-- | lib/Parse/AstGuard.h | 111 |
1 files changed, 90 insertions, 21 deletions
diff --git a/lib/Parse/AstGuard.h b/lib/Parse/AstGuard.h index 434c72c554..0aae4c082b 100644 --- a/lib/Parse/AstGuard.h +++ b/lib/Parse/AstGuard.h @@ -19,49 +19,118 @@ namespace clang { - /// RAII guard for freeing StmtTys and ExprTys on early exit in the parser. - /// Instantiated for statements and expressions (Action::DeleteStmt and - /// Action::DeleteExpr). template <void (Action::*Destroyer)(void*)> - class ASTGuard { + class ASTOwner; + + typedef ASTOwner<&Action::DeleteStmt> StmtOwner; + typedef ASTOwner<&Action::DeleteExpr> ExprOwner; + + /// Some trickery to switch between an ActionResult and an ASTOwner + template <typename Owner> struct ResultOfOwner; + template <> struct ResultOfOwner<StmtOwner> { + typedef Action::StmtResult type; + }; + template <> struct ResultOfOwner<ExprOwner> { + typedef Action::ExprResult type; + }; + + /// Move emulation helper for ASTOwner. Implicitly convertible to ActionResult + /// and void*, which means ASTOwner::move() can be used universally. + template <void (Action::*Destroyer)(void*)> + class ASTMove { + ASTOwner<Destroyer> &Moved; + + public: + explicit ASTMove(ASTOwner<Destroyer> &moved) : Moved(moved) {} + ASTOwner<Destroyer> * operator ->() { + return &Moved; + } + + /// Allow moving from ASTOwner to ActionResult + operator typename ResultOfOwner< ASTOwner<Destroyer> >::type() { + if (Moved.isInvalid()) + return true; + return Moved.take(); + } + + /// Allow moving from ASTOwner to void* + operator void*() { + if (Moved.isInvalid()) + return 0; + return Moved.take(); + } + }; + + /// RAII owning pointer for StmtTys and ExprTys. Simple move emulation. + template <void (Action::*Destroyer)(void*)> + class ASTOwner { + typedef typename ResultOfOwner<ASTOwner>::type Result; + Action &Actions; void *Node; + bool Invalid; void destroy() { if (Node) (Actions.*Destroyer)(Node); } - ASTGuard(const ASTGuard&); // DO NOT IMPLEMENT + ASTOwner(const ASTOwner&); // DO NOT IMPLEMENT // Reference member prevents copy assignment. public: - explicit ASTGuard(Action &actions) : Actions(actions), Node(0) {} - ASTGuard(Action &actions, void *node) - : Actions(actions), Node(node) {} - template <unsigned N> - ASTGuard(Action &actions, const Action::ActionResult<N> &res) - : Actions(actions), Node(res.Val) {} - ~ASTGuard() { destroy(); } - - void reset(void *element) { + explicit ASTOwner(Action &actions, bool invalid = false) + : Actions(actions), Node(0), Invalid(invalid) {} + ASTOwner(Action &actions, void *node) + : Actions(actions), Node(node), Invalid(false) {} + ASTOwner(Action &actions, const Result &res) + : Actions(actions), Node(res.Val), Invalid(res.isInvalid) {} + /// Move constructor + ASTOwner(ASTMove<Destroyer> mover) + : Actions(mover->Actions), Node(mover->take()), Invalid(mover->Invalid) {} + /// Move assignment + ASTOwner & operator =(ASTMove<Destroyer> mover) { + assert(&Actions == &mover->Actions && + "AST Owners from different actions."); destroy(); - Node = element; + Node = mover->take(); + Invalid = mover->Invalid; + return *this; } - template <unsigned N> - void reset(const Action::ActionResult<N> &res) { - reset(res.Val); + /// Convenience, for better syntax. reset() is so ugly. Just remember that + /// this takes ownership. + ASTOwner & operator =(const Result &res) { + reset(res); + return *this; } + + void reset(void *node = 0) { + destroy(); + Node = node; + Invalid = false; + } + void reset(const Result &res) { + destroy(); + Node = res.Val; + Invalid = res.isInvalid; + } + /// Take ownership from this pointer and return the node. Calling move() is + /// better. void *take() { void *Temp = Node; Node = 0; return Temp; } void *get() const { return Node; } - }; + bool isInvalid() const { return Invalid; } + /// Does this point to a usable AST node? To be usable, the node must be + /// valid and non-null. + bool isUsable() const { return !Invalid && Node; } - typedef ASTGuard<&Action::DeleteStmt> StmtGuard; - typedef ASTGuard<&Action::DeleteExpr> ExprGuard; + ASTMove<Destroyer> move() { + return ASTMove<Destroyer>(*this); + } + }; /// RAII SmallVector wrapper that holds Action::ExprTy* and similar, /// automatically freeing them on destruction unless it's been disowned. |