diff --git a/core/meta/src/TClingBaseClassInfo.cxx b/core/meta/src/TClingBaseClassInfo.cxx index bafa0d566ef9086c29ffe0905b4f899b37c1d777..ae8e6a34a048d04230e18fadc2a401790f18100b 100644 --- a/core/meta/src/TClingBaseClassInfo.cxx +++ b/core/meta/src/TClingBaseClassInfo.cxx @@ -57,8 +57,6 @@ using namespace llvm; using namespace clang; using namespace std; -static const string indent_string(" "); - TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp, TClingClassInfo* ci) : fInterp(interp), fClassInfo(0), fFirstTime(true), fDescend(false), @@ -159,15 +157,30 @@ TClingClassInfo *TClingBaseClassInfo::GetBase() const return fBaseInfo; } -OffsetPtrFunc_t TClingBaseClassInfo::GenerateBaseOffsetFunction(const TClingClassInfo * derivedClass, TClingClassInfo* targetClass, void* address) const +OffsetPtrFunc_t +TClingBaseClassInfo::GenerateBaseOffsetFunction(const TClingClassInfo * derivedClass, + TClingClassInfo* targetClass, + void* address) const { - // Generate a function at run-time that would calculate the offset + // Generate a function at run-time that would calculate the offset // from the parameter derived class to the parameter target class for the // address. // Get the dedcls for the two classes. - const clang::Decl* derivedDecl = derivedClass->GetDecl(); - const clang::Decl* targetDecl = targetClass->GetDecl(); + const clang::RecordDecl* derivedDecl + = dyn_cast<clang::RecordDecl>(derivedClass->GetDecl()); + if (!derivedDecl) { + Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", + "Offset of non-class %s is ill-defined!", derivedClass->Name()); + return 0; + } + const clang::RecordDecl* targetDecl + = dyn_cast<clang::RecordDecl>(targetClass->GetDecl()); + if (!targetDecl) { + Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", + "Offset of non-class %s is ill-defined!", targetClass->Name()); + return 0; + } // Make the wrapper name. string wrapper_name; @@ -178,108 +191,36 @@ OffsetPtrFunc_t TClingBaseClassInfo::GenerateBaseOffsetFunction(const TClingClas buf << "h" << targetDecl; wrapper_name = buf.str(); } - // Check whether the unction was already generated. - const GlobalValue* GV = fInterp->getModule()->getNamedValue(wrapper_name); - - if (!GV) { + string code; + // Check whether the function was already generated. + if (!fInterp->getModule()->getNamedValue(wrapper_name)) { // Get the class or namespace name. string derived_class_name; - if (derivedClass->GetType()) { - // This is a class, struct, or union member. - clang::QualType QTDerived(derivedClass->GetType(), 0); - ROOT::TMetaUtils::GetFullyQualifiedTypeName(derived_class_name, QTDerived, *fInterp); - } - else if (const clang::NamedDecl* ND = - dyn_cast<clang::NamedDecl>(derivedClass->GetDecl()->getDeclContext())) { - // This is a namespace member. - raw_string_ostream stream(derived_class_name); - ND->getNameForDiagnostic(stream, ND->getASTContext().getPrintingPolicy(), /*Qualified=*/true); - stream.flush(); - } + clang::QualType QTDerived(derivedClass->GetType(), 0); + ROOT::TMetaUtils::GetFullyQualifiedTypeName(derived_class_name, + QTDerived, *fInterp); string target_class_name; - if (targetClass->GetType()) { - // This is a class, struct, or union member. - clang::QualType QTTarget(targetClass->GetType(), 0); - ROOT::TMetaUtils::GetFullyQualifiedTypeName(target_class_name, QTTarget, *fInterp); - } - else if (const clang::NamedDecl* ND = - dyn_cast<clang::NamedDecl>(targetClass->GetDecl()->getDeclContext())) { - // This is a namespace member. - raw_string_ostream stream(target_class_name); - ND->getNameForDiagnostic(stream, ND->getASTContext().getPrintingPolicy(), /*Qualified=*/true); - stream.flush(); - } - - + clang::QualType QTTarget(targetClass->GetType(), 0); + ROOT::TMetaUtils::GetFullyQualifiedTypeName(target_class_name, + QTTarget, *fInterp); // Write the wrapper code. - string wrapperFwdDecl = "long " + wrapper_name + "(void* address)"; - ostringstream buf; - buf << wrapperFwdDecl << "{\n"; - buf << indent_string << derived_class_name << " *object = (" << derived_class_name << "*)address;"; - buf << "\n"; - buf << indent_string << target_class_name << " *target = object;"; - buf << "\n"; - buf << indent_string << "return ((long)target - (long)object);"; - buf << "\n"; - buf << "}\n"; - string wrapper = "extern \"C\" " + wrapperFwdDecl + ";\n" - + buf.str(); - - // Compile the wrapper code. - const FunctionDecl* WFD = 0; - { - cling::Transaction* Tp = 0; - cling::Interpreter::CompilationResult CR = fInterp->declare(wrapper, &Tp); - if (CR != cling::Interpreter::kSuccess) { - Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", "Wrapper compile failed!"); - return 0; - } - for (cling::Transaction::const_iterator I = Tp->decls_begin(), - E = Tp->decls_end(); !WFD && I != E; ++I) { - if (I->m_Call == cling::Transaction::kCCIHandleTopLevelDecl) { - if (const FunctionDecl* createWFD = dyn_cast<FunctionDecl>(*I->m_DGR.begin())) { - if (createWFD && isa<TranslationUnitDecl>(createWFD->getDeclContext())) { - DeclarationName FName = createWFD->getDeclName(); - if (const IdentifierInfo* FII = FName.getAsIdentifierInfo()) { - if (FII->getName() == wrapper_name) { - WFD = createWFD; - } - } - } - } - } - } - if (!WFD) { - Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", - "Wrapper compile did not return a function decl!"); - return 0; - } - } - - // Get the wrapper function pointer - // from the ExecutionEngine (the JIT). - GV = fInterp->getModule()->getNamedValue(wrapper_name); - if (!GV) { - Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", - "Wrapper function name not found in Module!"); - return 0; - } + llvm::raw_string_ostream buf(code); + buf << "extern \"C\" long " + wrapper_name + "(void* address) {\n" + << " " << derived_class_name << " *object = (" << derived_class_name << "*)address;\n" + << " " << target_class_name << " *target = object;\n" + << " return ((long)target - (long)object);\n}\n"; } - ExecutionEngine* EE = fInterp->getExecutionEngine(); - OffsetPtrFunc_t f = (OffsetPtrFunc_t)EE->getPointerToGlobalIfAvailable(GV); + // If we have a GV then compileFunction will use it; empty code is enough. + void* f = fInterp->compileFunction(wrapper_name, code, true /*ifUnique*/, + false /*withAccessControl*/); if (!f) { - // Wrapper function not yet codegened by the JIT, - // force this to happen now. - f = (OffsetPtrFunc_t)EE->getPointerToGlobal(GV); - if (!f) { - Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", "Wrapper function has no " - "mapping in Module after forced codegen!"); - return 0; - } + Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", + "Compilation failed!"); + return 0; } - return f; + return (OffsetPtrFunc_t) f; } bool TClingBaseClassInfo::IsValid() const diff --git a/core/meta/src/TClingCallFunc.cxx b/core/meta/src/TClingCallFunc.cxx index 8fac459056c1e414cde1a6dde0c338efa46e608e..753abb29930a32880eaa12d9615ee2103feec9f1 100644 --- a/core/meta/src/TClingCallFunc.cxx +++ b/core/meta/src/TClingCallFunc.cxx @@ -464,176 +464,8 @@ void* TClingCallFunc::compile_wrapper(const string& wrapper_name, const string& wrapper, bool withAccessControl/*=true*/) { - // - // Compile the wrapper code. - // - const FunctionDecl* WFD = 0; - { - DiagnosticsEngine& Diag = fInterp->getCI()->getDiagnostics(); - /* - In CallFunc we currently always (intentionally and somewhat necessarily) - always fully specify member function template, however this can lead to - an ambiguity with a class template. For example in - roottest/cling/functionTemplate we get: - - input_line_171:3:15: warning: lookup of 'set' in member access expression is ambiguous; using member of 't' - ((t*)obj)->set<int>(*(int*)args[0]); - ^ - /local2/pcanal/cint_working/rootcling/root/roottest/cling/functionTemplate/t.h:19:9: note: lookup in the object type 't' refers here - void set(T targ) { - ^ - /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/bits/stl_set.h:87:11: note: lookup from the current scope refers here - class set - ^ - This is an intention warning implemented in clang, see - http://llvm.org/viewvc/llvm-project?view=revision&revision=105518 - - which 'should have been' an error: - - C++ [basic.lookup.classref] requires this to be an error, but, - because it's hard to work around, Clang downgrades it to a warning as - an extension.</p> - - // C++98 [basic.lookup.classref]p1: - // In a class member access expression (5.2.5), if the . or -> token is - // immediately followed by an identifier followed by a <, the identifier must - // be looked up to determine whether the < is the beginning of a template - // argument list (14.2) or a less-than operator. The identifier is first - // looked up in the class of the object expression. If the identifier is not - // found, it is then looked up in the context of the entire postfix-expression - // and shall name a class or function template. If the lookup in the class of - // the object expression finds a template, the name is also looked up in the - // context of the entire postfix-expression and - // -- if the name is not found, the name found in the class of the object - // expression is used, otherwise - // -- if the name is found in the context of the entire postfix-expression - // and does not name a class template, the name found in the class of the - // object expression is used, otherwise - // -- if the name found is a class template, it must refer to the same - // entity as the one found in the class of the object expression, - // otherwise the program is ill-formed. - - See -Wambiguous-member-template - - An alternative to disabling the diagnostics is to use a pointer to - member function: - - #include <set> - using namespace std; - - extern "C" int printf(const char*,...); - - struct S { - template <typename T> - void set(T) {}; - - virtual void virtua() { printf("S\n"); } - }; - - struct T: public S { - void virtua() { printf("T\n"); } - }; - - int main() { - S *s = new T(); - typedef void (S::*Func_p)(int); - Func_p p = &S::set<int>; - (s->*p)(12); - - typedef void (S::*Vunc_p)(void); - Vunc_p q = &S::virtua; - (s->*q)(); // prints "T" - return 0; - } - */ - Diag.setDiagnosticMapping(clang::diag::ext_nested_name_member_ref_lookup_ambiguous, - clang::diag::MAP_IGNORE, SourceLocation()); - - LangOptions& LO = const_cast<LangOptions&>( - fInterp->getCI()->getLangOpts()); - - bool savedAccessControl = LO.AccessControl; - LO.AccessControl = withAccessControl; - cling::Transaction* T = 0; - cling::Interpreter::CompilationResult CR = fInterp->declare(wrapper, &T); - LO.AccessControl = savedAccessControl; - if (CR != cling::Interpreter::kSuccess) { - Error("TClingCallFunc::compile_wrapper", "Wrapper compile failed!"); - return 0; - } - for (cling::Transaction::const_iterator I = T->decls_begin(), - E = T->decls_end(); I != E; ++I) { - if (I->m_Call != cling::Transaction::kCCIHandleTopLevelDecl) { - continue; - } - const FunctionDecl* D = dyn_cast<FunctionDecl>(*I->m_DGR.begin()); - if (!isa<TranslationUnitDecl>(D->getDeclContext())) { - continue; - } - DeclarationName N = D->getDeclName(); - const IdentifierInfo* II = N.getAsIdentifierInfo(); - if (!II) { - continue; - } - if (II->getName() == wrapper_name) { - WFD = D; - break; - } - } - if (!WFD) { - Error("TClingCallFunc::compile_wrapper", - "Wrapper compile did not return a function decl!"); - return 0; - } - } - // - // Lookup the new wrapper declaration. - // - string MN; - GlobalDecl GD; - if (const CXXConstructorDecl* Ctor = dyn_cast<CXXConstructorDecl>(WFD)) - GD = GlobalDecl(Ctor, Ctor_Complete); - else if (const CXXDestructorDecl* Dtor = dyn_cast<CXXDestructorDecl>(WFD)) - GD = GlobalDecl(Dtor, Dtor_Deleting); - else - GD = GlobalDecl(WFD); - - cling::utils::Analyze::maybeMangleDeclName(GD, MN); - const NamedDecl* WND = dyn_cast<NamedDecl>(WFD); - if (!WND) { - Error("TClingCallFunc::make_wrapper", "Wrapper named decl is null!"); - return 0; - } - { - //WND->dump(); - //fInterp->getModule()->dump(); - //gROOT->ProcessLine(".printIR"); - } - // - // Get the wrapper function pointer - // from the ExecutionEngine (the JIT). - // - const GlobalValue* GV = fInterp->getModule()->getNamedValue(MN); - if (!GV) { - Error("TClingCallFunc::make_wrapper", - "Wrapper function name not found in Module!"); - return 0; - } - ExecutionEngine* EE = fInterp->getExecutionEngine(); - void* F = EE->getPointerToGlobalIfAvailable(GV); - if (!F) { - // - // Wrapper function not yet codegened by the JIT, - // force this to happen now. - // - F = EE->getPointerToGlobal(GV); - if (!F) { - Error("TClingCallFunc::make_wrapper", "Wrapper function has no " - "mapping in Module after forced codegen!"); - return 0; - } - } - return F; + return fInterp->compileFunction(wrapper_name, wrapper, false /*ifUnique*/, + withAccessControl); } void @@ -1444,7 +1276,7 @@ TClingCallFunc::make_wrapper() int indent_level = 0; ostringstream buf; buf << "__attribute__((used)) "; - buf << "void "; + buf << "extern \"C\" void "; buf << wrapper_name; buf << "(void* obj, int nargs, void** args, void* ret)\n"; buf << "{\n"; @@ -1566,7 +1398,7 @@ TClingCallFunc::make_ctor_wrapper(const TClingClassInfo* info) int indent_level = 0; ostringstream buf; buf << "__attribute__((used)) "; - buf << "void "; + buf << "extern \"C\" void "; buf << wrapper_name; buf << "(void** ret, void* arena, unsigned long nary)\n"; buf << "{\n"; @@ -1718,7 +1550,7 @@ TClingCallFunc::make_dtor_wrapper(const TClingClassInfo* info) int indent_level = 0; ostringstream buf; buf << "__attribute__((used)) "; - buf << "void "; + buf << "extern \"C\" void "; buf << wrapper_name; buf << "(void* obj, unsigned long nary, int withFree)\n"; buf << "{\n"; diff --git a/interpreter/cling/include/cling/Interpreter/Interpreter.h b/interpreter/cling/include/cling/Interpreter/Interpreter.h index ccbf3cc1504f7ed53610355000e9aff47b96b8af..2bf74a5a12e549ab8c54ec4af346116ce293b1ce 100644 --- a/interpreter/cling/include/cling/Interpreter/Interpreter.h +++ b/interpreter/cling/include/cling/Interpreter/Interpreter.h @@ -231,7 +231,7 @@ namespace cling { /// ///\param [in] fname - The function name. ///\param [in,out] res - The return result of the run function. Must be - /// initialized to point to the return value's location if the + /// initialized to point to the return value's location if the /// expression result is an aggregate. /// ///\returns The result of the execution. @@ -248,6 +248,15 @@ namespace cling { /// void ignoreFakeDiagnostics() const; + ///\brief Compile the function definition and return its Decl. + /// + ///\param[in] name - name of the function, used to find its Decl. + ///\param[in] code - function definition, starting with 'extern "C"'. + ///\param[in] withAccessControl - whether to enforce access restrictions. + const clang::FunctionDecl* ParseCFunction(llvm::StringRef name, + llvm::StringRef code, + bool withAccessControl); + public: Interpreter(int argc, const char* const *argv, const char* llvmdir = 0); virtual ~Interpreter(); @@ -546,6 +555,18 @@ namespace cling { const Transaction* getFirstTransaction() const; + ///\brief Compile extern "C" function and return its address. + /// + ///\param[in] name - function name + ///\param[in] code - function definition, must contain 'extern "C"' + ///\param[in] ifUniq - only compile this function if no function + /// with the same name exists, else return the existing address + ///\param[in] withAccessControl - whether to enforce access restrictions + /// + ///\returns the address of the function or 0 if the compilation failed. + void* compileFunction(llvm::StringRef name, llvm::StringRef code, + bool ifUniq = true, bool withAccessControl = true); + ///\brief Gets the address of an existing global and whether it was JITted. /// /// JIT symbols might not be immediately convertible to e.g. a function @@ -553,8 +574,7 @@ namespace cling { /// ///\param[in] D - the global's Decl to find ///\param[out] fromJIT - whether the symbol was JITted. - /// - void* getAddressOfGlobal(const clang::GlobalDecl& D, + void* getAddressOfGlobal(const clang::GlobalDecl& D, bool* fromJIT = 0) const; ///\brief Gets the address of an existing global and whether it was JITted. diff --git a/interpreter/cling/lib/Interpreter/ExecutionContext.cpp b/interpreter/cling/lib/Interpreter/ExecutionContext.cpp index 371eead34ef55077caf3c4976fcd83c3f1d10637..7a44299ab8b11ec379a5743b895c4616e9091a63 100644 --- a/interpreter/cling/lib/Interpreter/ExecutionContext.cpp +++ b/interpreter/cling/lib/Interpreter/ExecutionContext.cpp @@ -413,3 +413,12 @@ void* ExecutionContext::getAddressOfGlobal(llvm::Module* m, } return address; } + +void* +ExecutionContext::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) const { + if (void* addr = m_engine->getPointerToGlobalIfAvailable(&GV)) + return addr; + + // Function not yet codegened by the JIT, force this to happen now. + return m_engine->getPointerToGlobal(&GV); +} diff --git a/interpreter/cling/lib/Interpreter/ExecutionContext.h b/interpreter/cling/lib/Interpreter/ExecutionContext.h index 28bed25993e7d9d6192704a1c8cb36414adadf12..26f323be1220c464f741e9b71503f342459e3822 100644 --- a/interpreter/cling/lib/Interpreter/ExecutionContext.h +++ b/interpreter/cling/lib/Interpreter/ExecutionContext.h @@ -14,8 +14,9 @@ #include <set> namespace llvm { - class Module; class ExecutionEngine; + class GlobalValue; + class Module; } namespace clang { @@ -177,6 +178,13 @@ namespace cling { void* getAddressOfGlobal(llvm::Module* m, const char* mangledName, bool* fromJIT = 0) const; + ///\brief Return the address of a global from the ExecutionEngine (as + /// opposed to dynamic libraries). Forces the emission of the symbol if + /// it has not happened yet. + /// + ///param[in] GV - global value for which the address will be returned. + void* getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) const; + llvm::ExecutionEngine* getExecutionEngine() const { if (!m_engine) return 0; diff --git a/interpreter/cling/lib/Interpreter/Interpreter.cpp b/interpreter/cling/lib/Interpreter/Interpreter.cpp index 801ad363a8f9c1c94c23ebdfbc54773121da0018..3031de48be2ebf22f83683dfc49afdc53707ffa5 100644 --- a/interpreter/cling/lib/Interpreter/Interpreter.cpp +++ b/interpreter/cling/lib/Interpreter/Interpreter.cpp @@ -35,6 +35,7 @@ #include "clang/Sema/SemaInternal.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -667,6 +668,150 @@ namespace cling { return ConvertExecutionResult(ExeRes); } + const FunctionDecl* Interpreter::ParseCFunction(StringRef name, + StringRef code, + bool withAccessControl) { + /* + In CallFunc we currently always (intentionally and somewhat necessarily) + always fully specify member function template, however this can lead to + an ambiguity with a class template. For example in + roottest/cling/functionTemplate we get: + + input_line_171:3:15: warning: lookup of 'set' in member access expression + is ambiguous; using member of 't' + ((t*)obj)->set<int>(*(int*)args[0]); + ^ + roottest/cling/functionTemplate/t.h:19:9: note: lookup in the object type + 't' refers here + void set(T targ) { + ^ + /usr/include/c++/4.4.5/bits/stl_set.h:87:11: note: lookup from the + current scope refers here + class set + ^ + This is an intention warning implemented in clang, see + http://llvm.org/viewvc/llvm-project?view=revision&revision=105518 + + which 'should have been' an error: + + C++ [basic.lookup.classref] requires this to be an error, but, + because it's hard to work around, Clang downgrades it to a warning as + an extension.</p> + + // C++98 [basic.lookup.classref]p1: + // In a class member access expression (5.2.5), if the . or -> token is + // immediately followed by an identifier followed by a <, the identifier + // must be looked up to determine whether the < is the beginning of a + // template argument list (14.2) or a less-than operator. The identifier + // is first looked up in the class of the object expression. If the + // identifier is not found, it is then looked up in the context of the + // entire postfix-expression and shall name a class or function template. If + // the lookup in the class of the object expression finds a template, the + // name is also looked up in the context of the entire postfix-expression + // and + // -- if the name is not found, the name found in the class of the + // object expression is used, otherwise + // -- if the name is found in the context of the entire postfix-expression + // and does not name a class template, the name found in the class of the + // object expression is used, otherwise + // -- if the name found is a class template, it must refer to the same + // entity as the one found in the class of the object expression, + // otherwise the program is ill-formed. + + See -Wambiguous-member-template + + An alternative to disabling the diagnostics is to use a pointer to + member function: + + #include <set> + using namespace std; + + extern "C" int printf(const char*,...); + + struct S { + template <typename T> + void set(T) {}; + + virtual void virtua() { printf("S\n"); } + }; + + struct T: public S { + void virtua() { printf("T\n"); } + }; + + int main() { + S *s = new T(); + typedef void (S::*Func_p)(int); + Func_p p = &S::set<int>; + (s->*p)(12); + + typedef void (S::*Vunc_p)(void); + Vunc_p q = &S::virtua; + (s->*q)(); // prints "T" + return 0; + } + */ + DiagnosticsEngine& Diag = getCI()->getDiagnostics(); + Diag.setDiagnosticMapping( + clang::diag::ext_nested_name_member_ref_lookup_ambiguous, + clang::diag::MAP_IGNORE, SourceLocation()); + + + LangOptions& LO = const_cast<LangOptions&>(getCI()->getLangOpts()); + bool savedAccessControl = LO.AccessControl; + LO.AccessControl = withAccessControl; + cling::Transaction* T = 0; + cling::Interpreter::CompilationResult CR = declare(code, &T); + LO.AccessControl = savedAccessControl; + + if (CR != cling::Interpreter::kSuccess) + return 0; + + for (cling::Transaction::const_iterator I = T->decls_begin(), + E = T->decls_end(); I != E; ++I) { + if (I->m_Call != cling::Transaction::kCCIHandleTopLevelDecl) + continue; + if (const LinkageSpecDecl* LSD + = dyn_cast<LinkageSpecDecl>(*I->m_DGR.begin())) { + DeclContext::decl_iterator DeclBegin = LSD->decls_begin(); + if (DeclBegin == LSD->decls_end()) + continue; + if (const FunctionDecl* D = dyn_cast<FunctionDecl>(*DeclBegin)) { + const IdentifierInfo* II = D->getDeclName().getAsIdentifierInfo(); + if (II && II->getName() == name) + return D; + } + } + } + return 0; + } + + void* + Interpreter::compileFunction(llvm::StringRef name, llvm::StringRef code, + bool ifUnique, bool withAccessControl) { + // + // Compile the wrapper code. + // + const llvm::GlobalValue* GV = 0; + if (ifUnique) + GV = getModule()->getNamedValue(name); + + if (!GV) { + const FunctionDecl* FD = ParseCFunction(name, code, withAccessControl); + if (!FD) return 0; + // + // Get the wrapper function pointer + // from the ExecutionEngine (the JIT). + // + GV = getModule()->getNamedValue(name); + } + + if (!GV) + return 0; + + return m_ExecutionContext->getPointerToGlobalFromJIT(*GV); + } + void Interpreter::createUniqueName(std::string& out) { out += utils::Synthesize::UniquePrefix; llvm::raw_string_ostream(out) << m_UniqueCounter++; @@ -677,7 +822,7 @@ namespace cling { } llvm::StringRef Interpreter::createUniqueWrapper() { - const size_t size + const size_t size = sizeof(utils::Synthesize::UniquePrefix) + sizeof(m_UniqueCounter); llvm::SmallString<size> out(utils::Synthesize::UniquePrefix); llvm::raw_svector_ostream(out) << m_UniqueCounter++;