diff --git a/interpreter/cling/include/cling/Interpreter/Interpreter.h b/interpreter/cling/include/cling/Interpreter/Interpreter.h index 35a31c37977a5..0c23a90519130 100644 --- a/interpreter/cling/include/cling/Interpreter/Interpreter.h +++ b/interpreter/cling/include/cling/Interpreter/Interpreter.h @@ -48,6 +48,7 @@ namespace clang { class Sema; class SourceLocation; class SourceManager; + class Type; class PresumedLoc; } @@ -196,6 +197,12 @@ namespace cling { /// mutable std::vector m_StoredStates; + enum { + kStdStringTransaction = 0, // Transaction known to contain std::string + kNumTransactions + }; + mutable const Transaction* m_CachedTrns[kNumTransactions] = {}; + ///\brief Worker function, building block for interpreter's public /// interfaces. /// @@ -690,6 +697,12 @@ namespace cling { /// const Transaction* getLatestTransaction() const; + ///\brief Returns a reference to a Transaction known to contain std::string. + /// + const Transaction*& getStdStringTransaction() const { + return m_CachedTrns[kStdStringTransaction]; + } + ///\brief Compile extern "C" function and return its address. /// ///\param[in] name - function name diff --git a/interpreter/cling/include/cling/Interpreter/LookupHelper.h b/interpreter/cling/include/cling/Interpreter/LookupHelper.h index 40e2e266ced87..3b58393e9bb4b 100644 --- a/interpreter/cling/include/cling/Interpreter/LookupHelper.h +++ b/interpreter/cling/include/cling/Interpreter/LookupHelper.h @@ -33,22 +33,33 @@ namespace llvm { namespace cling { class Interpreter; + class Transaction; + ///\brief Reflection information query interface. The class performs lookups /// in the currently loaded information in the AST, using the same Parser, /// Sema and Preprocessor objects. /// class LookupHelper { - private: - std::unique_ptr m_Parser; - Interpreter* m_Interpreter; // we do not own. - const clang::Type* m_StringTy; public: - + enum StringType { + kStdString, + kWCharString, + kUTF16Str, + kUTF32Str, + kNumCachedStrings, + kNotAString = kNumCachedStrings, + }; enum DiagSetting { NoDiagnostics, WithDiagnostics }; + private: + std::unique_ptr m_Parser; + Interpreter* m_Interpreter; // we do not own. + const clang::Type* m_StringTy[kNumCachedStrings]; + + public: LookupHelper(clang::Parser* P, Interpreter* interp); ~LookupHelper(); @@ -222,10 +233,8 @@ namespace cling { bool hasFunction(const clang::Decl* scopeDecl, llvm::StringRef funcName, DiagSetting diagOnOff) const; - - ///\brief Retrieve the QualType of `std::string`. - const clang::Type* getStringType(); - + ///\brief Retrieve the StringType of given Type. + StringType getStringType(const clang::Type* Type); }; } // end namespace diff --git a/interpreter/cling/lib/Interpreter/Interpreter.cpp b/interpreter/cling/lib/Interpreter/Interpreter.cpp index b7d9b565707f3..7f20548b3256e 100644 --- a/interpreter/cling/lib/Interpreter/Interpreter.cpp +++ b/interpreter/cling/lib/Interpreter/Interpreter.cpp @@ -1275,6 +1275,14 @@ namespace cling { } } + // Clear any cached transaction states. + for (unsigned i = 0; i < kNumTransactions; ++i) { + if (m_CachedTrns[i] == &T) { + m_CachedTrns[i] = nullptr; + break; + } + } + if (InterpreterCallbacks* callbacks = getCallbacks()) callbacks->TransactionUnloaded(T); if (m_Executor) { // we also might be in fsyntax-only mode. diff --git a/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/interpreter/cling/lib/Interpreter/LookupHelper.cpp index 2d0e02f087a37..4fd3629c1c25f 100644 --- a/interpreter/cling/lib/Interpreter/LookupHelper.cpp +++ b/interpreter/cling/lib/Interpreter/LookupHelper.cpp @@ -38,7 +38,10 @@ namespace cling { // pin *tor here so that we can have clang::Parser defined and be able to call // the dtor on the OwningPtr LookupHelper::LookupHelper(clang::Parser* P, Interpreter* interp) - : m_Parser(P), m_Interpreter(interp), m_StringTy(nullptr) {} + : m_Parser(P), m_Interpreter(interp) { + // Always properly initialized in getStringType + // ::memset(m_StringTy, 0, sizeof(m_StringTy)); + } LookupHelper::~LookupHelper() {} @@ -1898,10 +1901,39 @@ namespace cling { diagOnOff); } - const Type* LookupHelper::getStringType() { - if (!m_StringTy) - m_StringTy = findType("std::string", WithDiagnostics).getTypePtr(); - return m_StringTy; + static const clang::Type* getType(LookupHelper* LH, llvm::StringRef Type) { + QualType Qt = LH->findType(Type, LookupHelper::WithDiagnostics); + assert(!Qt.isNull() && "Type should exist"); + return Qt.getTypePtr(); + } + + LookupHelper::StringType + LookupHelper::getStringType(const clang::Type* Type) { + assert(Type && "Type cannot be null"); + const Transaction*& Cache = m_Interpreter->getStdStringTransaction(); + if (!Cache || !m_StringTy[kStdString]) { + if (!Cache) ::memset(m_StringTy, 0, sizeof(m_StringTy)); + + QualType Qt = findType("std::string", WithDiagnostics); + m_StringTy[kStdString] = Qt.isNull() ? nullptr : Qt.getTypePtr(); + if (!m_StringTy[kStdString]) return kNotAString; + + Cache = m_Interpreter->getLatestTransaction(); + m_StringTy[kWCharString] = getType(this, "std::wstring"); + + const clang::LangOptions& LO = m_Interpreter->getCI()->getLangOpts(); + if (LO.CPlusPlus11) { + m_StringTy[kUTF16Str] = getType(this, "std::u16string"); + m_StringTy[kUTF32Str] = getType(this, "std::u32string"); + } + } + + ASTContext& Ctx = m_Interpreter->getSema().getASTContext(); + for (unsigned I = 0; I < kNumCachedStrings; ++I) { + if (m_StringTy[I] && Ctx.hasSameType(Type, m_StringTy[I])) + return StringType(I); + } + return kNotAString; } } // end namespace cling diff --git a/interpreter/cling/lib/Interpreter/ValuePrinter.cpp b/interpreter/cling/lib/Interpreter/ValuePrinter.cpp index 1aadfb4152170..f2adf1607c9f1 100644 --- a/interpreter/cling/lib/Interpreter/ValuePrinter.cpp +++ b/interpreter/cling/lib/Interpreter/ValuePrinter.cpp @@ -754,6 +754,22 @@ static std::string printFunctionValue(const Value &V, const void *ptr, clang::Qu return o.str(); } +static std::string printStringType(const Value &V, const clang::Type* Type) { + switch (V.getInterpreter()->getLookupHelper().getStringType(Type)) { + case LookupHelper::kStdString: + return executePrintValue(V, *(std::string*)V.getPtr()); + case LookupHelper::kWCharString: + return executePrintValue(V, *(std::wstring*)V.getPtr()); + case LookupHelper::kUTF16Str: + return executePrintValue(V, *(std::u16string*)V.getPtr()); + case LookupHelper::kUTF32Str: + return executePrintValue(V, *(std::u32string*)V.getPtr()); + default: + break; + } + return ""; +} + static std::string printUnpackedClingValue(const Value &V) { // Find the Type for `std::string`. We are guaranteed to have that declared // when this function is called; RuntimePrintValue.h #includes it. @@ -776,9 +792,10 @@ static std::string printUnpackedClingValue(const Value &V) { } else if (clang::CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl()) { if (CXXRD->isLambda()) return printAddress(V.getPtr(), '@'); - LookupHelper& LH= V.getInterpreter()->getLookupHelper(); - if (C.hasSameType(CXXRD->getTypeForDecl(), LH.getStringType())) - return executePrintValue(V, *(std::string*)V.getPtr()); + + std::string Str = printStringType(V, CXXRD->getTypeForDecl()); + if (!Str.empty()) + return Str; } else if (const clang::BuiltinType *BT = llvm::dyn_cast(Td.getCanonicalType().getTypePtr())) { switch (BT->getKind()) {