aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/AstGuard.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/AstGuard.h')
-rw-r--r--lib/Parse/AstGuard.h111
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.