Lay the groundwork for converting the entire parser-sema chain to smart pointers.

llvm-svn: 60782
This commit is contained in:
Sebastian Redl 2008-12-09 19:36:21 +00:00
parent b0498eebc2
commit 7379577ab0
4 changed files with 402 additions and 36 deletions

View File

@ -17,6 +17,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Parse/AccessSpecifier.h"
#include "clang/Parse/Ownership.h"
namespace clang {
// Semantic.
@ -49,15 +50,15 @@ namespace clang {
/// isCurrentClassName(), which must be specified in order for the
/// parse to complete accurately. The MinimalAction class does this
/// bare-minimum of tracking to implement this functionality.
class Action {
class Action : public ActionBase {
public:
/// Out-of-line virtual destructor to provide home for this class.
virtual ~Action();
// Types - Though these don't actually enforce strong typing, they document
// what types are required to be identical for the actions.
typedef void ExprTy;
typedef void StmtTy;
typedef ActionBase::ExprTy ExprTy;
typedef ActionBase::StmtTy StmtTy;
typedef void DeclTy;
typedef void TypeTy;
typedef void AttrTy;
@ -65,26 +66,6 @@ public:
typedef void MemInitTy;
typedef void CXXScopeTy;
/// ActionResult - This structure is used while parsing/acting on expressions,
/// stmts, etc. It encapsulates both the object returned by the action, plus
/// a sense of whether or not it is valid.
template<unsigned UID>
struct ActionResult {
void *Val;
bool isInvalid;
ActionResult(bool Invalid = false) : Val(0), isInvalid(Invalid) {}
template<typename ActualExprTy>
ActionResult(ActualExprTy *val) : Val(val), isInvalid(false) {}
ActionResult(const DiagnosticBuilder &) : Val(0), isInvalid(true) {}
const ActionResult &operator=(void *RHS) {
Val = RHS;
isInvalid = false;
return *this;
}
};
/// Expr/Stmt/Type/BaseResult - Provide a unique type to wrap
/// ExprTy/StmtTy/TypeTy/BaseTy, providing strong typing and
/// allowing for failure.
@ -94,12 +75,20 @@ public:
typedef ActionResult<3> BaseResult;
typedef ActionResult<4> MemInitResult;
/// Deletion callbacks - Since the parser doesn't know the concrete types of
/// the AST nodes being generated, it must do callbacks to delete objects when
/// recovering from errors.
virtual void DeleteExpr(ExprTy *E) {}
virtual void DeleteStmt(StmtTy *E) {}
/// Same, but with ownership.
typedef ASTOwningResult<&ActionBase::DeleteExpr> OwningExprResult;
typedef ASTOwningResult<&ActionBase::DeleteStmt> OwningStmtResult;
// Note that these will replace ExprResult and StmtResult when the transition
// is complete.
/// Single expressions or statements as arguments.
typedef ASTOwningPtr<&ActionBase::DeleteExpr> ExprArg;
typedef ASTOwningPtr<&ActionBase::DeleteStmt> StmtArg;
/// Multiple expressions or statements as arguments.
typedef ASTMultiPtr<&ActionBase::DeleteExpr> MultiExprArg;
typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg;
/// Statistics.
virtual void PrintStats() const {}
//===--------------------------------------------------------------------===//

View File

@ -0,0 +1,374 @@
//===--- Ownership.h - Parser Ownership Helpers -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains classes for managing ownership of Stmt and Expr nodes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_PARSE_OWNERSHIP_H
#define LLVM_CLANG_PARSE_OWNERSHIP_H
namespace clang
{
class DiagnosticBuilder;
/// ActionBase - A small part split from Action because of the horrible
/// definition order dependencies between Action and the smart pointers.
class ActionBase {
public:
/// Out-of-line virtual destructor to provide home for this class.
virtual ~ActionBase();
// Types - Though these don't actually enforce strong typing, they document
// what types are required to be identical for the actions.
typedef void ExprTy;
typedef void StmtTy;
/// ActionResult - This structure is used while parsing/acting on
/// expressions, stmts, etc. It encapsulates both the object returned by
/// the action, plus a sense of whether or not it is valid.
template<unsigned UID>
struct ActionResult {
void *Val;
bool isInvalid;
ActionResult(bool Invalid = false) : Val(0), isInvalid(Invalid) {}
template<typename ActualExprTy>
ActionResult(ActualExprTy *val) : Val(val), isInvalid(false) {}
ActionResult(const DiagnosticBuilder &) : Val(0), isInvalid(true) {}
const ActionResult &operator=(void *RHS) {
Val = RHS;
isInvalid = false;
return *this;
}
};
/// Deletion callbacks - Since the parser doesn't know the concrete types of
/// the AST nodes being generated, it must do callbacks to delete objects
/// when recovering from errors. These are in ActionBase because the smart
/// pointers need access to them.
virtual void DeleteExpr(ExprTy *E) {}
virtual void DeleteStmt(StmtTy *E) {}
};
/// ASTDestroyer - The type of an AST node destruction function pointer.
typedef void (ActionBase::*ASTDestroyer)(void *);
/// For the transition phase: translate from an ASTDestroyer to its
/// ActionResult UID.
template <ASTDestroyer Destroyer> struct DestroyerToUID;
template <> struct DestroyerToUID<&ActionBase::DeleteExpr> {
static const unsigned UID = 0;
};
template <> struct DestroyerToUID<&ActionBase::DeleteStmt> {
static const unsigned UID = 1;
};
/// ASTOwningResult - A moveable smart pointer for AST nodes that also
/// has an extra flag to indicate an additional success status.
template <ASTDestroyer Destroyer> class ASTOwningResult;
/// ASTOwningPtr - A moveable smart pointer for AST nodes.
template <ASTDestroyer Destroyer> class ASTOwningPtr;
/// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns
/// the individual pointers, not the array holding them.
template <ASTDestroyer Destroyer> class ASTMultiPtr;
/// Move emulation helper for ASTOwningResult
template <ASTDestroyer Destroyer>
class ASTResultMover
{
ASTOwningResult<Destroyer> &Moved;
public:
ASTResultMover(ASTOwningResult<Destroyer> &moved) : Moved(moved) {}
ASTOwningResult<Destroyer> * operator ->() { return &Moved; }
// For the transition phase.
operator void*();
// For the transition phase.
operator ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID>();
};
/// Move emulation helper for ASTOwningPtr
template <ASTDestroyer Destroyer>
class ASTPtrMover
{
ASTOwningPtr<Destroyer> &Moved;
public:
ASTPtrMover(ASTOwningPtr<Destroyer> &moved) : Moved(moved) {}
ASTOwningPtr<Destroyer> * operator ->() { return &Moved; }
operator void*();
};
/// Move emulation helper for ASTMultiPtr
template <ASTDestroyer Destroyer>
class ASTMultiMover
{
ASTMultiPtr<Destroyer> &Moved;
public:
ASTMultiMover(ASTMultiPtr<Destroyer> &moved) : Moved(moved) {}
/// Reset the moved object's internal structures.
void release();
};
template <ASTDestroyer Destroyer>
class ASTOwningResult
{
ActionBase *Actions;
void *Node;
bool Invalid;
friend class ASTResultMover<Destroyer>;
friend class ASTOwningPtr<Destroyer>;
ASTOwningResult(const ASTOwningResult&); // DO NOT IMPLEMENT
ASTOwningResult& operator =(const ASTOwningResult&); // DO NOT IMPLEMENT
void destroy() {
if (Node) {
assert(Actions && "Owning pointer without Action owns node.");
(Actions->*Destroyer)(Node);
}
}
void * take() {
if (Invalid)
return 0;
return Node;
}
public:
// For convenience and compatibility.
ASTOwningResult(bool invalid = false)
: Actions(0), Node(0), Invalid(invalid) {}
// Same
ASTOwningResult(const DiagnosticBuilder &)
: Actions(0), Node(0), Invalid(true) {}
explicit ASTOwningResult(ActionBase &actions, bool invalid = false)
: Actions(&actions), Node(0), Invalid(invalid) {}
ASTOwningResult(ActionBase &actions, void *node)
: Actions(&actions), Node(node), Invalid(false) {}
/// Move from another owning result
ASTOwningResult(ASTResultMover<Destroyer> mover)
: Actions(mover->Actions), Node(mover->take()), Invalid(mover->Invalid) {}
/// Move from an owning pointer
ASTOwningResult(ASTPtrMover<Destroyer> mover);
/// Move assignment from another owning result
ASTOwningResult & operator =(ASTResultMover<Destroyer> mover) {
Actions = mover->Actions;
Node = mover->take();
Invalid = mover->Invalid;
return *this;
}
/// Move assignment from an owning ptr
ASTOwningResult & operator =(ASTPtrMover<Destroyer> mover);
/// Assignment from a raw pointer. Takes ownership - beware!
ASTOwningResult & operator =(void *raw)
{
assert((!raw || Actions) &&
"Cannot have raw assignment when there's no Action");
Node = raw;
Invalid = false;
return *this;
}
/// Assignment from an ActionResult. Takes ownership - beware!
ASTOwningResult & operator =(
const ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> &res) {
assert((!res.Val || Actions) &&
"Cannot assign from ActionResult when there's no Action");
Node = res.Val;
Invalid = res.isInvalid;
return *this;
}
/// Access to the raw pointer.
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; }
/// Move hook
ASTResultMover<Destroyer> move() {
return ASTResultMover<Destroyer>(*this);
}
};
template <ASTDestroyer Destroyer>
class ASTOwningPtr
{
ActionBase *Actions;
void *Node;
friend class ASTPtrMover<Destroyer>;
friend class ASTOwningResult<Destroyer>;
ASTOwningPtr(const ASTOwningPtr&); // DO NOT IMPLEMENT
ASTOwningPtr& operator =(const ASTOwningPtr&); // DO NOT IMPLEMENT
void destroy() {
if (Node) {
assert(Actions && "Owning pointer without Action owns node.");
(Actions->*Destroyer)(Node);
}
}
public:
explicit ASTOwningPtr(ActionBase &actions)
: Actions(&actions), Node(0) {}
ASTOwningPtr(ActionBase &actions, void *node)
: Actions(&actions), Node(node) {}
/// Move from another owning pointer
ASTOwningPtr(ASTPtrMover<Destroyer> mover)
: Actions(mover->Actions), Node(mover->take()) {}
/// Move from an owning result
ASTOwningPtr(ASTResultMover<Destroyer> mover);
/// Move assignment from another owning pointer
ASTOwningPtr & operator =(ASTPtrMover<Destroyer> mover) {
Actions = mover->Actions;
Node = mover->take();
return *this;
}
/// Move assignment from an owning result
ASTOwningPtr & operator =(ASTResultMover<Destroyer> mover);
/// Assignment from a raw pointer. Takes ownership - beware!
ASTOwningPtr & operator =(void *raw)
{
assert((Actions || !raw) && "Cannot assign non-null raw without Action");
Node = raw;
return *this;
}
/// Access to the raw pointer.
void * get() const { return Node; }
/// Move hook
ASTPtrMover<Destroyer> move() {
return ASTPtrMover<Destroyer>(*this);
}
};
template <ASTDestroyer Destroyer>
class ASTMultiPtr
{
ActionBase &Actions;
void **Nodes;
unsigned Count;
friend class ASTMultiMover<Destroyer>;
ASTMultiPtr(const ASTMultiPtr&); // DO NOT IMPLEMENT
// Reference member prevents copy assignment.
void destroy() {
assert((Count == 0 || Nodes) && "No nodes when count is not zero.");
for (unsigned i = 0; i < Count; ++i) {
if (Nodes[i])
(Actions.*Destroyer)(Nodes[i]);
}
}
public:
explicit ASTMultiPtr(ActionBase &actions)
: Actions(actions), Nodes(0), Count(0) {}
ASTMultiPtr(ActionBase &actions, void **nodes, unsigned count)
: Actions(actions), Nodes(nodes), Count(count) {}
/// Move constructor
ASTMultiPtr(ASTMultiMover<Destroyer> mover)
: Actions(mover->Actions), Nodes(mover->Nodes), Count(mover->Count) {
mover->Nodes = 0;
mover->Count = 0;
}
/// Move assignment
ASTMultiPtr & operator =(ASTMultiMover<Destroyer> mover) {
Actions = mover->Actions;
Nodes = mover->Nodes;
Count = mover->Count;
mover.release();
return *this;
}
/// Access to the raw pointers.
void ** get() const { return Nodes; }
/// Access to the count.
unsigned size() const { return Count; }
/// Move hook
ASTMultiMover<Destroyer> move() {
return ASTMultiMover<Destroyer>(*this);
}
};
// Out-of-line implementations due to definition dependencies
template <ASTDestroyer Destroyer> inline
ASTResultMover<Destroyer>::operator void*() {
return Moved.take();
}
template <ASTDestroyer Destroyer> inline
ASTPtrMover<Destroyer>::operator void*() {
return Moved.take();
}
template <ASTDestroyer Destroyer> inline
void ASTMultiMover<Destroyer>::release() {
Moved.Nodes = 0;
Moved.Count = 0;
}
template <ASTDestroyer Destroyer> inline
ASTOwningResult<Destroyer>::ASTOwningResult(ASTPtrMover<Destroyer> mover)
: Actions(mover->Actions), Node(mover->take()), Invalid(false) {}
template <ASTDestroyer Destroyer> inline
ASTOwningResult<Destroyer> &
ASTOwningResult<Destroyer>::operator =(ASTPtrMover<Destroyer> mover) {
Actions = mover->Actions;
Node = mover->take();
Invalid = false;
return *this;
}
template <ASTDestroyer Destroyer> inline
ASTOwningPtr<Destroyer>::ASTOwningPtr(ASTResultMover<Destroyer> mover)
: Actions(mover->Actions), Node(mover->take()) {
}
template <ASTDestroyer Destroyer> inline
ASTOwningPtr<Destroyer> &
ASTOwningPtr<Destroyer>::operator =(ASTResultMover<Destroyer> mover) {
Actions = mover->Actions;
Node = mover->take();
return *this;
}
}
#endif

View File

@ -19,11 +19,11 @@
namespace clang
{
template <void (Action::*Destroyer)(void*)>
template <void (ActionBase::*Destroyer)(void*)>
class ASTOwner;
typedef ASTOwner<&Action::DeleteStmt> StmtOwner;
typedef ASTOwner<&Action::DeleteExpr> ExprOwner;
typedef ASTOwner<&ActionBase::DeleteStmt> StmtOwner;
typedef ASTOwner<&ActionBase::DeleteExpr> ExprOwner;
/// Some trickery to switch between an ActionResult and an ASTOwner
template <typename Owner> struct ResultOfOwner;
@ -36,7 +36,7 @@ namespace clang
/// Move emulation helper for ASTOwner. Implicitly convertible to ActionResult
/// and void*, which means ASTOwner::move() can be used universally.
template <void (Action::*Destroyer)(void*)>
template <void (ActionBase::*Destroyer)(void*)>
class ASTMove {
ASTOwner<Destroyer> &Moved;
@ -62,7 +62,7 @@ namespace clang
};
/// RAII owning pointer for StmtTys and ExprTys. Simple move emulation.
template <void (Action::*Destroyer)(void*)>
template <void (ActionBase::*Destroyer)(void*)>
class ASTOwner {
typedef typename ResultOfOwner<ASTOwner>::type Result;
@ -136,7 +136,7 @@ namespace clang
/// 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>
template <void (ActionBase::*Destroyer)(void*), unsigned N>
class ASTVector : public llvm::SmallVector<void*, N> {
private:
Action &Actions;

View File

@ -38,6 +38,9 @@ Parser::Parser(Preprocessor &pp, Action &actions)
PushTopClassStack();
}
/// Out-of-line virtual destructor to provide home for Action class.
ActionBase::~ActionBase() {}
/// Out-of-line virtual destructor to provide home for Action class.
Action::~Action() {}