//--------------------------------------------------------------------*- C++ -*- // CLING - the C++ LLVM-based InterpreterG :) // author: Vassil Vassilev // // This file is dual-licensed: you can choose to license it under the University // of Illinois Open Source License or the GNU Lesser General Public License. See // LICENSE.TXT for details. //------------------------------------------------------------------------------ #ifndef CLING_DYNAMIC_LOOKUP_H #define CLING_DYNAMIC_LOOKUP_H #include "ASTTransformer.h" #include "clang/AST/StmtVisitor.h" #include "clang/Sema/Ownership.h" #include "llvm/Support/Casting.h" namespace clang { class Decl; class Sema; } namespace cling { typedef llvm::SmallVector ASTNodes; /// \brief Helper structure that allows children of a node to delegate how /// to be replaced from their parent. For example a child can return more than /// one replacement node. class ASTNodeInfo { private: ASTNodes Nodes; bool forReplacement; bool m_HasErrorOccurred; public: ASTNodeInfo() : forReplacement(false), m_HasErrorOccurred(false) {} ASTNodeInfo(clang::Stmt* S, bool needed) : forReplacement(needed), m_HasErrorOccurred(false) { Nodes.push_back(S); } bool isForReplacement() { return forReplacement; } void setForReplacement(bool val = true) { forReplacement = val; } void setErrorOccurred(bool val = true) { m_HasErrorOccurred = val; } bool hasErrorOccurred() { return m_HasErrorOccurred; } bool hasSingleNode() { return Nodes.size() == 1; } clang::Stmt* getAsSingleNode() { assert(hasSingleNode() && "There is more than one node!"); return Nodes[0]; } ASTNodes& getNodes() { return Nodes; } void addNode(clang::Stmt* Node) { Nodes.push_back(Node); } template T* getAs() { return llvm::dyn_cast(getAsSingleNode()); } template T* castTo() { T* Result = llvm::dyn_cast(getAsSingleNode()); assert(Result && "Cannot cast to type!"); return Result; } }; } //end namespace cling namespace cling { typedef llvm::DenseMap MapTy; /// \brief In order to implement the runtime type binding and expression /// evaluation we need to be able to compile code which contains unknown /// symbols (undefined variables, types, functions, etc.). This cannot be done /// by a compiler like clang, because it is not valid C++ code. /// /// DynamicExprTransformer transforms these unknown symbols into valid C++ /// code at AST (abstract syntax tree) level. Thus it provides an opportunity /// their evaluation to happen at runtime. Several steps are performed: /// /// 1. Skip compiler's error diagnostics - if a compiler encounters unknown /// symbol, by definition, it must output an error and it mustn't produce /// machine code. Cling implements an extension to Clang semantic analyzer /// that allows the compiler to recover even an unknown symbol is encountered. /// For instance if the compiler sees a symbol it looks for its definition in /// a internal structure (symbol table) and it is not found it asks whether /// somebody else could provide the missing symbol. That is the place where /// the DynamicIDHandler, which is controlled by DynamicExprTransformer comes /// into play. It marks all unknown symbols as dependent as if they are /// templates and are going to be resolved at first instantiation, with the /// only difference that an instantiation never happens. The advantage is that /// the unknown symbols are not diagnosed but the disadvantage is that /// somebody needs to transform them into valid expressions with valid types. /// /// 2. Replace all dependent symbols - all artificially dependent symbols need /// to be replaced with appropriate valid symbols in order the compiler to /// produce executable machine code. The DynamicExprTransformer walks up all /// statements and declarations that might be possibly marked earlier as /// dependent and replaces them with valid expression, which preserves the /// meant behavior. Main implementation goal is to replace the as little /// as possible part of the statement. The replacement is done immediately /// after the expected type can be deduced. /// /// 2.1. EvaluateT - this is a templated function, which is put at the /// place of the dependent expression. It will be called at runtime and it /// will use the runtime instance of the interpreter (cling interprets itself) /// to evaluate the replaced expression. The template parameter of the /// function carries the expected expression type. If unknown symbol is /// encountered as a right-hand-side of an assignment one can claim that /// the type of the unknown expression should be compatible with the type of /// the left-hand-side. /// /// 2.2 LifetimeHandler - in some more complex situation in order to preserve /// the behavior the expression must be replaced with more complex structures. /// /// 3. Evaluate interface - this is the core function in the interpreter, /// which does the delayed evaluation. It uses a callback function, which /// should be reimplemented in the subsystem that provides the runtime types /// and addresses of the expressions. class EvaluateTSynthesizer : public ASTTransformer, public clang::StmtVisitor { private: /// \brief Stores the declaration of the EvaluateT function. clang::FunctionDecl* m_EvalDecl; /// \brief Stores helper structure dealing with static initializers. clang::CXXRecordDecl* m_LifetimeHandlerDecl; /// \brief Stores member function defined in the LifetimeHanlder. clang::CXXMethodDecl* m_LHgetMemoryDecl; /// \brief Stores helper class used in EvaluateT call. clang::CXXRecordDecl* m_DynamicExprInfoDecl; /// \brief Stores the clang::DeclContext declaration, used in as an parameter /// in EvaluateT call. clang::CXXRecordDecl* m_DeclContextDecl; /// \brief Stores the cling::Interpreter (cling::runtime::gCling), /// used in as an parameter LifetimeHandler's ctor. clang::VarDecl* m_gCling; /// \brief Keeps track of the replacements being made. If an AST node is /// changed with another it should be added to the map (newNode->oldNode). MapTy m_SubstSymbolMap; /// \brief Stores the actual declaration context, in which declarations are /// being visited. clang::DeclContext* m_CurDeclContext; /// \brief Use instead of clang::SourceRange(). clang::SourceRange m_NoRange; /// \brief Use instead of clang::SourceLocation() as start location. clang::SourceLocation m_NoSLoc; /// \brief Use instead of clang::SourceLocation() as end location. clang::SourceLocation m_NoELoc; /// \brief Needed for the AST transformations, owned by Sema. clang::ASTContext* m_Context; /// \brief Counter used when we need unique names. unsigned long long m_UniqueNameCounter; /// \brief Counter used when entering/exitting compound stmt. Needed for /// value printing of dynamic expressions. unsigned m_NestedCompoundStmts; public: typedef clang::StmtVisitor BaseStmtVisitor; using BaseStmtVisitor::Visit; EvaluateTSynthesizer(clang::Sema* S); ~EvaluateTSynthesizer(); Result Transform(clang::Decl* D) override; MapTy& getSubstSymbolMap() { return m_SubstSymbolMap; } ASTNodeInfo VisitStmt(clang::Stmt* Node); ASTNodeInfo VisitCompoundStmt(clang::CompoundStmt* Node); ASTNodeInfo VisitIfStmt(clang::IfStmt* Node); /// \brief Transforms a declaration with initializer of dependent type. /// If an object on the free store is being initialized we use the /// EvaluateT /// If an object on the stack is being initialized it is transformed into /// reference and an object on the free store is created in order to /// avoid the copy constructors, which might be private /// /// For example: /// @code /// int i = 5; /// MyClass my(dep->Symbol(i)) /// @endcode /// where dep->Symbol() is of artificially dependent type it is being /// transformed into: /// @code /// cling::runtime::internal::LifetimeHandler /// __unique("dep->Sybmol(*(int*)@)",(void*[]){&i}, DC, "MyClass"); /// MyClass &my(*(MyClass*)__unique.getMemory()); /// @endcode /// /// Note: here our main priority is to preserve equivalent behavior. We have /// to clean the heap memory afterwords. /// ASTNodeInfo VisitDeclStmt(clang::DeclStmt* Node); ///\brief \c delete t; \c if t is dependent, the whole stmt must be escaped. /// ASTNodeInfo VisitCXXDeleteExpr(clang::CXXDeleteExpr* Node); ///\brief Surrounds member accesses into dependent types; remove on /// subsitution of its child expression. /// ASTNodeInfo VisitCXXDependentScopeMemberExpr( clang::CXXDependentScopeMemberExpr* Node); ASTNodeInfo VisitExpr(clang::Expr* Node); ASTNodeInfo VisitBinaryOperator(clang::BinaryOperator* Node); ASTNodeInfo VisitArraySubscriptExpr(clang::ArraySubscriptExpr* ASE); ASTNodeInfo VisitCallExpr(clang::CallExpr* E); ASTNodeInfo VisitDeclRefExpr(clang::DeclRefExpr* DRE); ASTNodeInfo VisitDependentScopeDeclRefExpr( clang::DependentScopeDeclRefExpr* Node); protected: ///\brief On first use it finds commonly used declarations. /// /// For example: EvaluateT, clang::DeclContext and so on. /// void Initialize(); /// @{ /// @name Helpers, which simplify node replacement ///\brief Replaces given dependent AST node with an instantiation of /// EvaluateT with the deduced type. /// /// @param[in] InstTy The deduced type used to create instantiation. /// @param[in] SubTree The AST node or subtree, which is being replaced. /// @param[in] ValuePrinterReq Whether to turn on the value printing or not /// clang::Expr* SubstituteUnknownSymbol(const clang::QualType InstTy, clang::Expr* SubTree, bool ValuePrinterReq = false); ///\brief Builds the actual call expression, which is put in the place of /// the dependent AST node. /// /// @param[in] InstTy The deduced type used to create instantiation. /// @param[in] SubTree The AST node or subtree, which is being replaced. /// @param[in] CallArgs Proper arguments, which the call will use. /// clang::CallExpr* BuildEvalCallExpr(clang::QualType InstTy, clang::Expr* SubTree, llvm::SmallVector& CallArgs); ///\brief Builds the DynamicExprInfo class with proper info. /// clang::Expr* BuildDynamicExprInfo(clang::Expr* SubTree, bool ValuePrinterReq = false); ///\brief Creates const char* expression from given value. clang::Expr* ConstructConstCharPtrExpr(llvm::StringRef Val); ///\brief Checks if the given node is marked as dependent by us. /// bool IsArtificiallyDependent(clang::Expr* Node); ///\brief Checks if the function might contain dynamically scoped Decls. /// bool ShouldVisit(clang::FunctionDecl* D); /// \brief Gets all children of a given node. /// bool GetChildren(ASTNodes& Children, clang::Stmt* Node); /// \brief Creates unique name (eg. of a variable). Used internally for /// AST node synthesis. /// std::string createUniqueName(); /// @} }; } // end namespace cling #endif // CLING_DYNAMIC_LOOKUP_H