aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/AstGuard.h
blob: 0aae4c082b07ca49538b406f7ac4fdb337f50384 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//===--- AstGuard.h - Parser Ownership Tracking Utilities -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines RAII objects for managing ExprTy* and StmtTy*.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_PARSE_ASTGUARD_H
#define LLVM_CLANG_PARSE_ASTGUARD_H

#include "clang/Parse/Action.h"
#include "llvm/ADT/SmallVector.h"

namespace clang
{
  template <void (Action::*Destroyer)(void*)>
  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);
    }

    ASTOwner(const ASTOwner&); // DO NOT IMPLEMENT
    // Reference member prevents copy assignment.

  public:
    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 = mover->take();
      Invalid = mover->Invalid;
      return *this;
    }
    /// 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; }

    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.
  /// Instantiated for statements and expressions (Action::DeleteStmt and
  /// Action::DeleteExpr).
  template <void (Action::*Destroyer)(void*), unsigned N>
  class ASTVector : public llvm::SmallVector<void*, N> {
  private:
    Action &Actions;
    bool Owns;

    void destroy() {
      if (Owns) {
        while (!this->empty()) {
          (Actions.*Destroyer)(this->back());
          this->pop_back();
        }
      }
    }

    ASTVector(const ASTVector&); // DO NOT IMPLEMENT
    // Reference member prevents copy assignment.

  public:
    ASTVector(Action &actions) : Actions(actions), Owns(true) {}

    ~ASTVector() { destroy(); }

    void **take() {
      Owns = false;
      return &(*this)[0];
    }
  };

  /// A SmallVector of statements, with stack size 32 (as that is the only one
  /// used.)
  typedef ASTVector<&Action::DeleteStmt, 32> StmtVector;
  /// A SmallVector of expressions, with stack size 12 (the maximum used.)
  typedef ASTVector<&Action::DeleteExpr, 12> ExprVector;
}

#endif