From 7379577ab04eedca751acb9ef64d6b1b56c1f1ff Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Tue, 9 Dec 2008 19:36:21 +0000 Subject: [PATCH] Lay the groundwork for converting the entire parser-sema chain to smart pointers. llvm-svn: 60782 --- clang/include/clang/Parse/Action.h | 49 ++-- clang/include/clang/Parse/Ownership.h | 374 ++++++++++++++++++++++++++ clang/lib/Parse/AstGuard.h | 12 +- clang/lib/Parse/Parser.cpp | 3 + 4 files changed, 402 insertions(+), 36 deletions(-) create mode 100644 clang/include/clang/Parse/Ownership.h diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 4d6d4c5e865b..17ea9b1d36bb 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -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 - struct ActionResult { - void *Val; - bool isInvalid; - - ActionResult(bool Invalid = false) : Val(0), isInvalid(Invalid) {} - template - 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 {} //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/Parse/Ownership.h b/clang/include/clang/Parse/Ownership.h new file mode 100644 index 000000000000..87094d6d8889 --- /dev/null +++ b/clang/include/clang/Parse/Ownership.h @@ -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 + struct ActionResult { + void *Val; + bool isInvalid; + + ActionResult(bool Invalid = false) : Val(0), isInvalid(Invalid) {} + template + 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 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 class ASTOwningResult; + + /// ASTOwningPtr - A moveable smart pointer for AST nodes. + template class ASTOwningPtr; + + /// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns + /// the individual pointers, not the array holding them. + template class ASTMultiPtr; + + /// Move emulation helper for ASTOwningResult + template + class ASTResultMover + { + ASTOwningResult &Moved; + + public: + ASTResultMover(ASTOwningResult &moved) : Moved(moved) {} + + ASTOwningResult * operator ->() { return &Moved; } + + // For the transition phase. + operator void*(); + + // For the transition phase. + operator ActionBase::ActionResult::UID>(); + }; + + /// Move emulation helper for ASTOwningPtr + template + class ASTPtrMover + { + ASTOwningPtr &Moved; + + public: + ASTPtrMover(ASTOwningPtr &moved) : Moved(moved) {} + + ASTOwningPtr * operator ->() { return &Moved; } + + operator void*(); + }; + + /// Move emulation helper for ASTMultiPtr + template + class ASTMultiMover + { + ASTMultiPtr &Moved; + + public: + ASTMultiMover(ASTMultiPtr &moved) : Moved(moved) {} + + /// Reset the moved object's internal structures. + void release(); + }; + + template + class ASTOwningResult + { + ActionBase *Actions; + void *Node; + bool Invalid; + + friend class ASTResultMover; + friend class ASTOwningPtr; + + 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 mover) + : Actions(mover->Actions), Node(mover->take()), Invalid(mover->Invalid) {} + /// Move from an owning pointer + ASTOwningResult(ASTPtrMover mover); + + /// Move assignment from another owning result + ASTOwningResult & operator =(ASTResultMover mover) { + Actions = mover->Actions; + Node = mover->take(); + Invalid = mover->Invalid; + return *this; + } + + /// Move assignment from an owning ptr + ASTOwningResult & operator =(ASTPtrMover 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::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 move() { + return ASTResultMover(*this); + } + }; + + template + class ASTOwningPtr + { + ActionBase *Actions; + void *Node; + + friend class ASTPtrMover; + friend class ASTOwningResult; + + 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 mover) + : Actions(mover->Actions), Node(mover->take()) {} + /// Move from an owning result + ASTOwningPtr(ASTResultMover mover); + + /// Move assignment from another owning pointer + ASTOwningPtr & operator =(ASTPtrMover mover) { + Actions = mover->Actions; + Node = mover->take(); + return *this; + } + + /// Move assignment from an owning result + ASTOwningPtr & operator =(ASTResultMover 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 move() { + return ASTPtrMover(*this); + } + }; + + template + class ASTMultiPtr + { + ActionBase &Actions; + void **Nodes; + unsigned Count; + + friend class ASTMultiMover; + + 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 mover) + : Actions(mover->Actions), Nodes(mover->Nodes), Count(mover->Count) { + mover->Nodes = 0; + mover->Count = 0; + } + + /// Move assignment + ASTMultiPtr & operator =(ASTMultiMover 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 move() { + return ASTMultiMover(*this); + } + }; + + // Out-of-line implementations due to definition dependencies + + template inline + ASTResultMover::operator void*() { + return Moved.take(); + } + + template inline + ASTPtrMover::operator void*() { + return Moved.take(); + } + + template inline + void ASTMultiMover::release() { + Moved.Nodes = 0; + Moved.Count = 0; + } + + template inline + ASTOwningResult::ASTOwningResult(ASTPtrMover mover) + : Actions(mover->Actions), Node(mover->take()), Invalid(false) {} + + template inline + ASTOwningResult & + ASTOwningResult::operator =(ASTPtrMover mover) { + Actions = mover->Actions; + Node = mover->take(); + Invalid = false; + return *this; + } + + template inline + ASTOwningPtr::ASTOwningPtr(ASTResultMover mover) + : Actions(mover->Actions), Node(mover->take()) { + } + + template inline + ASTOwningPtr & + ASTOwningPtr::operator =(ASTResultMover mover) { + Actions = mover->Actions; + Node = mover->take(); + return *this; + } +} + +#endif diff --git a/clang/lib/Parse/AstGuard.h b/clang/lib/Parse/AstGuard.h index 0aae4c082b07..71d25650523d 100644 --- a/clang/lib/Parse/AstGuard.h +++ b/clang/lib/Parse/AstGuard.h @@ -19,11 +19,11 @@ namespace clang { - template + template 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 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 + template class ASTMove { ASTOwner &Moved; @@ -62,7 +62,7 @@ namespace clang }; /// RAII owning pointer for StmtTys and ExprTys. Simple move emulation. - template + template class ASTOwner { typedef typename ResultOfOwner::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 + template class ASTVector : public llvm::SmallVector { private: Action &Actions; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index f2d0ce4cc403..3a3b9d88dcaf 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -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() {}