From 4e09b2f86eb2ed9fa11c34604774895e252cb470 Mon Sep 17 00:00:00 2001 From: Boris Perovic Date: Thu, 20 Aug 2015 16:33:36 +0200 Subject: [PATCH 1/2] Catch-all printValue implementation changed to enable correct invocation if only parent type overload exists (ex. if there is no overload for TF1*, compiler invokes the overload to its best parent overload match, in the worst case void*). Argument changed from reference to pointer to support this. isEnumType Coverity bug changed from if to assert (coding, not runtime error) Changed the way printValue is invoked in order to correctly cast Value to the needed value (e.g. LL -> short). Extracted value stays in scope while we execute printValue, because we use the address. --- .../cling/Interpreter/RuntimePrintValue.h | 125 +++-- .../cling/lib/Interpreter/ValuePrinter.cpp | 484 +++++++++--------- 2 files changed, 307 insertions(+), 302 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h b/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h index d8e449987e476..8e29b065a2461 100644 --- a/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h +++ b/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h @@ -15,151 +15,148 @@ namespace cling { class Value; + // General fallback - prints the address + std::string printValue(const void *ptr); + // void pointer - std::string printValue(void *ptr); + std::string printValue(const void **ptr); // Bool - std::string printValue(bool val); + std::string printValue(const bool *val); // Chars - std::string printValue(char val); + std::string printValue(const char *val); - std::string printValue(signed char val); + std::string printValue(const signed char *val); - std::string printValue(unsigned char val); + std::string printValue(const unsigned char *val); // Ints - std::string printValue(short val); + std::string printValue(const short *val); - std::string printValue(unsigned short val); + std::string printValue(const unsigned short *val); - std::string printValue(int val); + std::string printValue(const int *val); - std::string printValue(unsigned int val); + std::string printValue(const unsigned int *val); - std::string printValue(long val); + std::string printValue(const long *val); - std::string printValue(unsigned long val); + std::string printValue(const unsigned long *val); - std::string printValue(long long val); + std::string printValue(const long long *val); - std::string printValue(unsigned long long val); + std::string printValue(const unsigned long long *val); // Reals - std::string printValue(float val); + std::string printValue(const float *val); - std::string printValue(double val); + std::string printValue(const double *val); - std::string printValue(long double val); + std::string printValue(const long double *val); // Char pointers - std::string printValue(const char *const val); + std::string printValue(const char *const *val); - std::string printValue(char *val); + std::string printValue(const char **val); // std::string - std::string printValue(const std::string &val); + std::string printValue(const std::string *val); // cling::Value - std::string printValue(const Value &value); + std::string printValue(const Value *value); - namespace internal { + // Collections internal declaration + namespace collectionPrinterInternal { // Maps declaration template - auto printValue_impl(const CollectionType &obj, short) + auto printValue_impl(const CollectionType *obj, short) -> decltype( - ++(obj.begin()), obj.end(), - obj.begin()->first, obj.begin()->second, + ++(obj->begin()), obj->end(), + obj->begin()->first, obj->begin()->second, std::string()); - // Collections like vector, set, deque etc. declaration + // Vector, set, deque etc. declaration template - auto printValue_impl(const CollectionType &obj, int) + auto printValue_impl(const CollectionType *obj, int) -> decltype( - ++(obj.begin()), obj.end(), - *(obj.begin()), + ++(obj->begin()), obj->end(), + *(obj->begin()), std::string()); - // General fallback - print object address declaration - template - std::string printValue_impl(const T &obj, long); + // No general fallback anymore here, void* overload used for that now } - // Collections and general fallback entry function + // Collections template - auto printValue(const CollectionType &obj) - -> decltype(internal::printValue_impl(obj, 0), std::string()) + auto printValue(const CollectionType *obj) + -> decltype(collectionPrinterInternal::printValue_impl(obj, 0), std::string()) { - return internal::printValue_impl(obj, (short)0); // short -> int -> long = priority order + return collectionPrinterInternal::printValue_impl(obj, (short)0); // short -> int -> long = priority order } // Arrays template - std::string printValue(const T (&obj)[N]) { + std::string printValue(const T (*obj)[N]) { std::string str = "{ "; for (int i = 0; i < N; ++i) { - str = str + printValue(obj[i]); - if (i < N-1) str += ", "; + str += printValue(*obj + i); + if (i < N - 1) str += ", "; } return str + " }"; } - namespace internal { + // Collections internal + namespace collectionPrinterInternal { // Maps template - auto printValue_impl(const CollectionType &obj, short) - -> decltype( - ++(obj.begin()), obj.end(), - obj.begin()->first, obj.begin()->second, + auto printValue_impl(const CollectionType *obj, short) + -> decltype( + ++(obj->begin()), obj->end(), + obj->begin()->first, obj->begin()->second, std::string()) { std::string str = "{ "; - auto iter = obj.begin(); - auto iterEnd = obj.end(); + auto iter = obj->begin(); + auto iterEnd = obj->end(); while (iter != iterEnd) { - str = str + printValue(iter->first); - str = str + " => "; - str = str + printValue(iter->second); + str += printValue(&iter->first); + str += " => "; + str += printValue(&iter->second); ++iter; if (iter != iterEnd) { - str = str + ", "; + str += ", "; } } return str + " }"; } - // Collections like vector, set, deque etc. + // Vector, set, deque etc. template - auto printValue_impl(const CollectionType &obj, int) - -> decltype( - ++(obj.begin()), obj.end(), - *(obj.begin()), + auto printValue_impl(const CollectionType *obj, int) + -> decltype( + ++(obj->begin()), obj->end(), + *(obj->begin()), std::string()) { std::string str = "{ "; - auto iter = obj.begin(); - auto iterEnd = obj.end(); + auto iter = obj->begin(); + auto iterEnd = obj->end(); while (iter != iterEnd) { - str = str + printValue(*iter); + str += printValue(&(*iter)); ++iter; if (iter != iterEnd) { - str = str + ", "; + str += ", "; } } return str + " }"; } - - // General fallback - print object address - template - std::string printValue_impl(const T &obj, long) { - return "@" + printValue((void *) &obj); - } } } diff --git a/interpreter/cling/lib/Interpreter/ValuePrinter.cpp b/interpreter/cling/lib/Interpreter/ValuePrinter.cpp index a54e2550380a8..89c85ffe719cd 100644 --- a/interpreter/cling/lib/Interpreter/ValuePrinter.cpp +++ b/interpreter/cling/lib/Interpreter/ValuePrinter.cpp @@ -56,7 +56,7 @@ using namespace cling; // Implements the CValuePrinter interface. -extern "C" void cling_PrintValue(void* /*cling::Value**/ V) { +extern "C" void cling_PrintValue(void * /*cling::Value**/ V) { //Value* value = (Value*)V; // We need stream that doesn't close its file descriptor, thus we are not @@ -71,17 +71,17 @@ extern "C" void cling_PrintValue(void* /*cling::Value**/ V) { // Checking whether the pointer points to a valid memory location // Used for checking of void* output // Should be moved to earlier stages (ex. IR) in the future -static bool isAddressValid(void* P) { - if (!P || P == (void*)-1) +static bool isAddressValid(const void *P) { + if (!P || P == (void *) -1) return false; #ifdef LLVM_ON_WIN32 - MEMORY_BASIC_INFORMATION MBI; - if (!VirtualQuery(P, &MBI, sizeof(MBI))) - return false; - if (MBI.State != MEM_COMMIT) - return false; - return true; + MEMORY_BASIC_INFORMATION MBI; + if (!VirtualQuery(P, &MBI, sizeof(MBI))) + return false; + if (MBI.State != MEM_COMMIT) + return false; + return true; #else // There is a POSIX way of finding whether an address can be accessed for // reading: write() will return EFAULT if not. @@ -99,184 +99,182 @@ static bool isAddressValid(void* P) { #endif } -static std::string getValueString(const Value &V) { - clang::ASTContext &C = V.getASTContext(); - clang::QualType Ty = V.getType().getDesugaredType(C); - if (const clang::BuiltinType *BT - = llvm::dyn_cast(Ty.getCanonicalType())) { - switch (BT->getKind()) { - case clang::BuiltinType::Bool: // intentional fall through - case clang::BuiltinType::Char_U: // intentional fall through - case clang::BuiltinType::Char_S: // intentional fall through - case clang::BuiltinType::SChar: // intentional fall through - case clang::BuiltinType::Short: // intentional fall through - case clang::BuiltinType::Int: // intentional fall through - case clang::BuiltinType::Long: // intentional fall through - case clang::BuiltinType::LongLong: { - std::ostringstream strm; - strm << V.getLL(); - return strm.str(); - } - break; - case clang::BuiltinType::UChar: // intentional fall through - case clang::BuiltinType::UShort: // intentional fall through - case clang::BuiltinType::UInt: // intentional fall through - case clang::BuiltinType::ULong: // intentional fall through - case clang::BuiltinType::ULongLong: { - std::ostringstream strm; - strm << V.getULL(); - return strm.str(); - } - break; - case clang::BuiltinType::Float: { - std::ostringstream strm; - strm << V.getFloat(); - return strm.str(); - } - break; - case clang::BuiltinType::Double: { - std::ostringstream strm; - strm << V.getDouble(); - return strm.str(); - } - break; - case clang::BuiltinType::LongDouble: { - std::ostringstream strm; - strm << V.getLongDouble(); - return strm.str(); - } - break; - default: - std::ostringstream strm; - strm << V.getPtr(); - return strm.str(); - break; - } - } - else if (Ty->isIntegralOrEnumerationType()) { - std::ostringstream strm; - strm << V.getLL(); - return strm.str(); - } - else if (Ty->isFunctionType()) { - std::ostringstream strm; - strm << (const void *) &V; - return strm.str(); - } else if (Ty->isPointerType() - || Ty->isReferenceType() - || Ty->isArrayType()) { - std::ostringstream strm; - strm << V.getPtr(); - return strm.str(); - } - else { - // struct case. - std::ostringstream strm; - strm << V.getPtr(); - return strm.str(); - } -} -static std::string getCastValueString(const Value &V) { +static std::string getTypeString(const Value &V) { std::ostringstream strm; clang::ASTContext &C = V.getASTContext(); clang::QualType Ty = V.getType().getDesugaredType(C).getNonReferenceType(); std::string type = cling::utils::TypeName::GetFullyQualifiedName(Ty, C); std::ostringstream typeWithOptDeref; - std::ostringstream suffix; - if (llvm::dyn_cast(Ty.getCanonicalType())){ - typeWithOptDeref << "(" << type << ")"; + if (llvm::dyn_cast(Ty.getCanonicalType())) { + typeWithOptDeref << "(" << type << "*)"; } else if (Ty->isPointerType()) { if (Ty->getPointeeType()->isCharType()) { // Print char pointers as strings. - typeWithOptDeref << "(" << type << ")"; + typeWithOptDeref << "(" << type << "*)"; } else { // Fallback to void pointer for other pointers and print the address. - typeWithOptDeref << "(void*)"; + typeWithOptDeref << "(const void**)"; } - } else if (Ty->isArrayType()) { - const clang::ArrayType* ArrTy = Ty->getAsArrayTypeUnsafe(); + } + else if (Ty->isArrayType()) { + const clang::ArrayType *ArrTy = Ty->getAsArrayTypeUnsafe(); clang::QualType ElementTy = ArrTy->getElementType(); - // Not implementing printing as string in case of char ElementTy - // Can be done like this: typeWithOptDeref << "(const char void*)"; - if (Ty->isConstantArrayType()) { - const clang::ConstantArrayType* CArrTy = C.getAsConstantArrayType(Ty); - const llvm::APInt& APSize = CArrTy->getSize(); - size_t size = (size_t)APSize.getZExtValue(); - - // typeWithOptDeref example for int[40] array: "((int(&)[40])*(void*)0x5c8f260)" - typeWithOptDeref << "(" << cling::utils::TypeName::GetFullyQualifiedName(ElementTy, C) << "(&)[" << size << "])*(void*)"; + // In case of char ElementTy, printing as string + if (ElementTy->isCharType()) { + typeWithOptDeref << "(const char **)"; + } else if (Ty->isConstantArrayType()) { + const clang::ConstantArrayType *CArrTy = C.getAsConstantArrayType(Ty); + const llvm::APInt &APSize = CArrTy->getSize(); + size_t size = (size_t) APSize.getZExtValue(); + + // typeWithOptDeref example for int[40] array: "((int(*)[40])*(void**)0x5c8f260)" + typeWithOptDeref << "(" << cling::utils::TypeName::GetFullyQualifiedName(ElementTy, C) << "(*)[" << size << "])*(void**)"; } else { - typeWithOptDeref << "(void*)"; + typeWithOptDeref << "(void**)"; } - } else { + } + else { // In other cases, dereference the address of the object. // If no overload or specific template matches, // the general template will be used which only prints the address. - typeWithOptDeref << "*(" << type << "*)"; + typeWithOptDeref << "*(" << type << "**)"; } - strm << typeWithOptDeref.str() << getValueString(V) << suffix.str(); + strm << typeWithOptDeref.str(); return strm.str(); } -static std::string printEnumValue(const Value &V){ +template +static std::string executePrintValue(const Value &V, const T &val) { + Interpreter *Interp = V.getInterpreter(); + std::stringstream printValueSS; + printValueSS << "cling::printValue("; + printValueSS << getTypeString(V); + printValueSS << (const void *) &val; + printValueSS << ");"; + Value printValueV; + Interp->evaluate(printValueSS.str(), printValueV); + assert(printValueV.isValid() && "Must return valid value."); + return *(std::string *) printValueV.getPtr(); +} + +static std::string invokePrintValueOverload(const Value &V) { + clang::ASTContext &C = V.getASTContext(); + clang::QualType Ty = V.getType().getDesugaredType(C); + if (const clang::BuiltinType *BT + = llvm::dyn_cast(Ty.getCanonicalType())) { + switch (BT->getKind()) { + case clang::BuiltinType::Bool: + return executePrintValue(V, V.getLL()); + + case clang::BuiltinType::Char_S: + return executePrintValue(V, V.getLL()); + case clang::BuiltinType::SChar: + return executePrintValue(V, V.getLL()); + case clang::BuiltinType::Short: + return executePrintValue(V, V.getLL()); + case clang::BuiltinType::Int: + return executePrintValue(V, V.getLL()); + case clang::BuiltinType::Long: + return executePrintValue(V, V.getLL()); + case clang::BuiltinType::LongLong: + return executePrintValue(V, V.getLL()); + + case clang::BuiltinType::Char_U: + return executePrintValue(V, V.getULL()); + case clang::BuiltinType::UChar: + return executePrintValue(V, V.getULL()); + case clang::BuiltinType::UShort: + return executePrintValue(V, V.getULL()); + case clang::BuiltinType::UInt: + return executePrintValue(V, V.getULL()); + case clang::BuiltinType::ULong: + return executePrintValue(V, V.getULL()); + case clang::BuiltinType::ULongLong: + return executePrintValue(V, V.getULL()); + + case clang::BuiltinType::Float: + return executePrintValue(V, V.getFloat()); + case clang::BuiltinType::Double: + return executePrintValue(V, V.getDouble()); + case clang::BuiltinType::LongDouble: + return executePrintValue(V, V.getLongDouble()); + + default: + return executePrintValue(V, V.getPtr()); + } + } + else if (Ty->isIntegralOrEnumerationType()) { + return executePrintValue(V, V.getLL()); + } + else if (Ty->isFunctionType()) { + return executePrintValue(V, &V); + } + else if (Ty->isPointerType() + || Ty->isReferenceType() + || Ty->isArrayType()) { + return executePrintValue(V, V.getPtr()); + } + else { + // struct case. + return executePrintValue(V, V.getPtr()); + } +} + +static std::string printEnumValue(const Value &V) { std::stringstream enumString; - clang::ASTContext& C = V.getASTContext(); + clang::ASTContext &C = V.getASTContext(); clang::QualType Ty = V.getType().getDesugaredType(C); const clang::EnumType *EnumTy = Ty.getNonReferenceType()->getAs(); - if(EnumTy != 0) { - clang::EnumDecl *ED = EnumTy->getDecl(); - uint64_t value = *(const uint64_t *) &V; - bool IsFirst = true; - llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, Ty); - for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(), - E = ED->enumerator_end(); I != E; ++I) { - if (I->getInitVal() == ValAsAPSInt) { - if (!IsFirst) { - enumString << " ? "; - } - enumString << "(" << I->getQualifiedNameAsString() << ")"; - IsFirst = false; + assert(EnumTy && "ValuePrinter.cpp: ERROR, printEnumValue invoked for a non enum type."); + clang::EnumDecl *ED = EnumTy->getDecl(); + uint64_t value = *(const uint64_t *) &V; + bool IsFirst = true; + llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, Ty); + for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(), + E = ED->enumerator_end(); I != E; ++I) { + if (I->getInitVal() == ValAsAPSInt) { + if (!IsFirst) { + enumString << " ? "; } + enumString << "(" << I->getQualifiedNameAsString() << ")"; + IsFirst = false; } - enumString << " : (int) " << ValAsAPSInt.toString(/*Radix = */10); - } else { - // Should not happen, we check for isEnumeralType before invoking this func - enumString << "ERROR: Value is not of enum type!"; } + enumString << " : (int) " << ValAsAPSInt.toString(/*Radix = */10); return enumString.str(); } -static std::string printFunctionValue(const Value &V, const void* ptr, clang::QualType Ty) { +static std::string printFunctionValue(const Value &V, const void *ptr, clang::QualType Ty) { std::string functionString; llvm::raw_string_ostream o(functionString); o << "Function @" << ptr << '\n'; - clang::ASTContext& C = V.getASTContext(); - Interpreter& Interp = *const_cast(V.getInterpreter()); - const Transaction* T = Interp.getLastTransaction(); + clang::ASTContext &C = V.getASTContext(); + Interpreter &Interp = *const_cast(V.getInterpreter()); + const Transaction *T = Interp.getLastTransaction(); assert(T->getWrapperFD() && "Must have a wrapper."); - clang::FunctionDecl* WrapperFD = T->getWrapperFD(); + clang::FunctionDecl *WrapperFD = T->getWrapperFD(); - const clang::FunctionDecl* FD = 0; + const clang::FunctionDecl *FD = 0; // CE should be the setValueNoAlloc call expr. - if (const clang::CallExpr* CallE + if (const clang::CallExpr *CallE = llvm::dyn_cast_or_null( utils::Analyze::GetOrCreateLastExpr(WrapperFD, /*foundAtPos*/0, /*omitDS*/false, &Interp.getSema()))) { - if (const clang::FunctionDecl* FDsetValue - = llvm::dyn_cast_or_null(CallE->getCalleeDecl())){ + if (const clang::FunctionDecl *FDsetValue + = llvm::dyn_cast_or_null(CallE->getCalleeDecl())) { if (FDsetValue->getNameAsString() == "setValueNoAlloc" && CallE->getNumArgs() == 5) { - const clang::Expr* Arg4 = CallE->getArg(4); - while (const clang::CastExpr* CastE + const clang::Expr *Arg4 = CallE->getArg(4); + while (const clang::CastExpr *CastE = clang::dyn_cast(Arg4)) Arg4 = CastE->getSubExpr(); - if (const clang::DeclRefExpr* DeclRefExp + if (const clang::DeclRefExpr *DeclRefExp = llvm::dyn_cast(Arg4)) FD = llvm::dyn_cast(DeclRefExp->getDecl()); } @@ -285,11 +283,11 @@ static std::string printFunctionValue(const Value &V, const void* ptr, clang::Qu if (FD) { clang::SourceRange SRange = FD->getSourceRange(); - const char* cBegin = 0; - const char* cEnd = 0; + const char *cBegin = 0; + const char *cEnd = 0; bool Invalid; if (SRange.isValid()) { - clang::SourceManager& SM = C.getSourceManager(); + clang::SourceManager &SM = C.getSourceManager(); clang::SourceLocation LocBegin = SRange.getBegin(); LocBegin = SM.getExpansionRange(LocBegin).first; o << " at " << SM.getFilename(LocBegin); @@ -312,7 +310,7 @@ static std::string printFunctionValue(const Value &V, const void* ptr, clang::Qu if (cBegin && cEnd && cEnd > cBegin && cEnd - cBegin < 16 * 1024) { o << llvm::StringRef(cBegin, cEnd - cBegin + 1); } else { - const clang::FunctionDecl* FDef; + const clang::FunctionDecl *FDef; if (FD->hasBody(FDef)) FD = FDef; FD->print(o); @@ -327,26 +325,14 @@ static std::string printFunctionValue(const Value &V, const void* ptr, clang::Qu return functionString; } -static std::string invokePrintValueOverload(const Value& V) { - Interpreter *Interp = V.getInterpreter(); - std::stringstream printValueSS; - printValueSS << "cling::printValue("; - printValueSS << getCastValueString(V); - printValueSS << ");"; - Value printValueV; - Interp->evaluate(printValueSS.str(), printValueV); - assert(printValueV.isValid() && "Must return valid value."); - return *(std::string*)printValueV.getPtr(); -} - -static std::string printUnpackedClingValue(const Value& V) { +static std::string printUnpackedClingValue(const Value &V) { std::stringstream strm; - clang::ASTContext& C = V.getASTContext(); + clang::ASTContext &C = V.getASTContext(); clang::QualType QT = V.getType(); clang::QualType Ty = QT.getDesugaredType(C).getNonReferenceType(); - if(Ty-> isNullPtrType()) { + if (Ty->isNullPtrType()) { // special case nullptr_t strm << "nullptr_t"; } else if (Ty->isEnumeralType()) { @@ -358,8 +344,15 @@ static std::string printUnpackedClingValue(const Value& V) { } else if ((Ty->isPointerType() || Ty->isMemberPointerType()) && Ty->getPointeeType()->isFunctionProtoType()) { // special case function printing, using compiled information strm << printFunctionValue(V, V.getPtr(), Ty->getPointeeType()); + } else if (clang::CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl()) { + if (CXXRD->isLambda()) { + strm << "@" << V.getPtr(); + } else { + // default case, modular printing using cling::printValue + strm << invokePrintValueOverload(V); + } } else { - // normal case, modular printing using cling::printValue + // default case, modular printing using cling::printValue strm << invokePrintValueOverload(V); } @@ -368,26 +361,39 @@ static std::string printUnpackedClingValue(const Value& V) { namespace cling { - std::string printValue(void* ptr) { + // General fallback - prints the address + std::string printValue(const void *ptr) { if (!ptr) { return "nullptr"; } else { std::ostringstream strm; - strm << ptr; + strm << "@" << ptr; if (!isAddressValid(ptr)) strm << " "; return strm.str(); } } + // void pointer + std::string printValue(const void **ptr) { + if (!*ptr) { + return "nullptr"; + } else { + std::ostringstream strm; + strm << *ptr; + if (!isAddressValid(*ptr)) + strm << " "; + return strm.str(); + } + } + // Bool - std::string printValue(bool val) { + std::string printValue(const bool *val) { return val ? "true" : "false"; } // Chars - - static std::string printChar(signed char val, bool apostrophe){ + static std::string printChar(signed char val, bool apostrophe) { std::ostringstream strm; if (val > 0x1F && val < 0x7F) { if (apostrophe) @@ -401,94 +407,95 @@ namespace cling { return strm.str(); } - std::string printValue(char val) { - return printChar(val, true); + std::string printValue(const char *val) { + return printChar(*val, true); } - std::string printValue(signed char val) { - return printChar(val, true); + std::string printValue(const signed char *val) { + return printChar(*val, true); } - std::string printValue(unsigned char val) { - return printChar(val, true); + std::string printValue(const unsigned char *val) { + return printChar(*val, true); } // Ints - std::string printValue(short val) { + std::string printValue(const short *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(unsigned short val) { + std::string printValue(const unsigned short *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(int val) { + std::string printValue(const int *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(unsigned int val) { + std::string printValue(const unsigned int *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(long val) { + std::string printValue(const long *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(unsigned long val) { + std::string printValue(const unsigned long *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(long long val) { + std::string printValue(const long long *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(unsigned long long val) { + std::string printValue(const unsigned long long *val) { std::ostringstream strm; - strm << val; + strm << *val; return strm.str(); } - std::string printValue(float val) { + // Reals + std::string printValue(const float *val) { std::ostringstream strm; - strm << std::showpoint << val << "f"; + strm << std::showpoint << *val << "f"; return strm.str(); } - std::string printValue(double val) { + std::string printValue(const double *val) { std::ostringstream strm; - strm << std::showpoint << val; + strm << std::showpoint << *val; return strm.str(); } - std::string printValue(long double val) { + std::string printValue(const long double *val) { std::ostringstream strm; - strm << val << "L"; + strm << *val << "L"; return strm.str(); } // Char pointers - std::string printValue(const char *const val) { - if (!val) { + std::string printValue(const char *const *val) { + if (!*val) { return "nullptr"; } else { std::ostringstream strm; strm << "\""; // 10000 limit to prevent potential printing of the whole RAM / inf loop - for (const char *cobj = val; *cobj != 0 && cobj-val < 10000; ++cobj) { + for (const char *cobj = *val; *cobj != 0 && cobj - *val < 10000; ++cobj) { strm << printChar(*cobj, false); } strm << "\""; @@ -496,29 +503,30 @@ namespace cling { } } - std::string printValue(char *val) { - return printValue((const char *const) val); + std::string printValue(const char **val) { + return printValue((const char *const *) val); } // std::string - std::string printValue(const std::string & val) { - return "\"" + val + "\""; + std::string printValue(const std::string *val) { + return "\"" + *val + "\""; } - std::string printValue(const Value &value) { + // cling::Value + std::string printValue(const Value *value) { std::ostringstream strm; - if (!value.isValid()) { - strm << "<<>> @" << &value; + if (!value->isValid()) { + strm << "<<>> @" << value; } else { - clang::ASTContext& C = value.getASTContext(); - clang::QualType QT = value.getType(); + clang::ASTContext &C = value->getASTContext(); + clang::QualType QT = value->getType(); strm << "boxes ["; strm << "(" << cling::utils::TypeName::GetFullyQualifiedName(QT, C) << ") "; if (!QT->isVoidType()) { - strm << printUnpackedClingValue(value); + strm << printUnpackedClingValue(*value); } strm << "]"; } @@ -526,41 +534,41 @@ namespace cling { return strm.str(); } -namespace valuePrinterInternal { + namespace valuePrinterInternal { - std::string printTypeInternal(const Value& V) { - using namespace clang; - std::ostringstream strm; - clang::ASTContext& C = V.getASTContext(); - QualType QT = V.getType().getNonReferenceType(); - std::string ValueTyStr; - if (const TypedefType* TDTy = dyn_cast(QT)) - ValueTyStr = TDTy->getDecl()->getQualifiedNameAsString(); - else if (const TagType* TTy = dyn_cast(QT)) - ValueTyStr = TTy->getDecl()->getQualifiedNameAsString(); - - if (ValueTyStr.empty()) - ValueTyStr = cling::utils::TypeName::GetFullyQualifiedName(QT, C); - else if (QT.hasQualifiers()) - ValueTyStr = QT.getQualifiers().getAsString() + " " + ValueTyStr; - - strm << "("; - strm << ValueTyStr; - if (V.getType()->isReferenceType()) - strm << " &"; - strm << ")"; - return strm.str(); - } + std::string printTypeInternal(const Value &V) { + using namespace clang; + std::ostringstream strm; + clang::ASTContext &C = V.getASTContext(); + QualType QT = V.getType().getNonReferenceType(); + std::string ValueTyStr; + if (const TypedefType *TDTy = dyn_cast(QT)) + ValueTyStr = TDTy->getDecl()->getQualifiedNameAsString(); + else if (const TagType *TTy = dyn_cast(QT)) + ValueTyStr = TTy->getDecl()->getQualifiedNameAsString(); + + if (ValueTyStr.empty()) + ValueTyStr = cling::utils::TypeName::GetFullyQualifiedName(QT, C); + else if (QT.hasQualifiers()) + ValueTyStr = QT.getQualifiers().getAsString() + " " + ValueTyStr; + + strm << "("; + strm << ValueTyStr; + if (V.getType()->isReferenceType()) + strm << " &"; + strm << ")"; + return strm.str(); + } - std::string printValueInternal(const Value& V) { - static bool includedRuntimePrintValue = false; // initialized only once as a static function variable - // Include "RuntimePrintValue.h" only on the first printing. - // This keeps the interpreter lightweight and reduces the startup time. - if(!includedRuntimePrintValue) { - V.getInterpreter()->declare("#include \"cling/Interpreter/RuntimePrintValue.h\""); - includedRuntimePrintValue = true; + std::string printValueInternal(const Value &V) { + static bool includedRuntimePrintValue = false; // initialized only once as a static function variable + // Include "RuntimePrintValue.h" only on the first printing. + // This keeps the interpreter lightweight and reduces the startup time. + if (!includedRuntimePrintValue) { + V.getInterpreter()->declare("#include \"cling/Interpreter/RuntimePrintValue.h\""); + includedRuntimePrintValue = true; + } + return printUnpackedClingValue(V); } - return printUnpackedClingValue(V); - } -} // end namespace valuePrinterInternal + } // end namespace valuePrinterInternal } // end namespace cling From d68a3999ca326c46b14397c5374c632faff95cba Mon Sep 17 00:00:00 2001 From: Boris Perovic Date: Thu, 20 Aug 2015 16:39:45 +0200 Subject: [PATCH 2/2] Dtors.c cling test changed in order to avoid infinite loop when unloading "RuntimePrintValue.h". Should be looked into in the future. --- interpreter/cling/test/CodeUnloading/Dtors.C | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interpreter/cling/test/CodeUnloading/Dtors.C b/interpreter/cling/test/CodeUnloading/Dtors.C index 238d13e4cbf7b..3db86a4f20649 100644 --- a/interpreter/cling/test/CodeUnloading/Dtors.C +++ b/interpreter/cling/test/CodeUnloading/Dtors.C @@ -62,6 +62,8 @@ int T(){ // Make sure we have exactly one symbol of ~X(), i.e. that the unloading does // not remove it and CodeGen re-emits in upon seeing a new use in X c; +12 // This is a temporary fix, not to allow .undo to try to unload RuntimePrintvalue.h + // If this is not here, the test hangs on first .undo 3 below. Should be investigated further. .storeState "preUnload2" .rawInput 1 extern "C" int printf(const char*, ...);