diff --git a/Module.mk b/Module.mk index eb61d771..a04c9ffa 100644 --- a/Module.mk +++ b/Module.mk @@ -20,7 +20,7 @@ CLINGDEP := $(CLINGO:.o=.d) CLINGETC_CLING := DynamicExprInfo.h DynamicLookupRuntimeUniverse.h \ DynamicLookupLifetimeHandler.h Interpreter.h InvocationOptions.h \ - RuntimeUniverse.h StoredValueRef.h Value.h \ + RuntimeUniverse.h Value.h \ ValuePrinter.h ValuePrinterInfo.h RuntimeException.h CLINGETC_LLVM := llvm/ADT/IntrusiveRefCntPtr.h \ diff --git a/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h b/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h index e132ebdf..f75db953 100644 --- a/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h +++ b/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h @@ -16,7 +16,7 @@ #include "cling/Interpreter/Interpreter.h" #include "cling/Interpreter/DynamicExprInfo.h" #include "cling/Interpreter/DynamicLookupLifetimeHandler.h" -#include "cling/Interpreter/StoredValueRef.h" +#include "cling/Interpreter/Value.h" namespace cling { @@ -45,7 +45,7 @@ namespace runtime { /// evaluated at runtime. template T EvaluateT(DynamicExprInfo* ExprInfo, clang::DeclContext* DC ) { - StoredValueRef result( + Value result( cling::runtime::gCling->Evaluate(ExprInfo->getExpr(), DC, ExprInfo->isValuePrinterRequested()) ); @@ -53,7 +53,7 @@ namespace runtime { // Check whether the expected return type and the actual return type are // compatible with Sema::CheckAssingmentConstraints or // ASTContext::typesAreCompatible. - return result.get().getAs(); + return result.simplisticCastAs(); return T(); } diff --git a/include/cling/Interpreter/RuntimeUniverse.h b/include/cling/Interpreter/RuntimeUniverse.h index ce1c5866..01816b35 100644 --- a/include/cling/Interpreter/RuntimeUniverse.h +++ b/include/cling/Interpreter/RuntimeUniverse.h @@ -56,69 +56,69 @@ namespace cling { ///\brief Set the value of the GenericValue for the expression /// evaluated at the prompt. - ///\param [in] vpI - The cling::Interpreter for StoredValueRef. + ///\param [in] vpI - The cling::Interpreter for Value. ///\param [in] vpQT - The opaque ptr for the clang::QualType of value. ///\param [in] value - The float value of the assignment to be stored /// in GenericValue. - ///\param [out] vpSVR - The StoredValueRef that is created. + ///\param [out] vpSVR - The Value that is created. /// - void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, float value); + void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, float value); ///\brief Set the value of the GenericValue for the expression /// evaluated at the prompt. - ///\param [in] vpI - The cling::Interpreter for StoredValueRef. + ///\param [in] vpI - The cling::Interpreter for Value. ///\param [in] vpQT - The opaque ptr for the clang::QualType of value. ///\param [in] value - The double value of the assignment to be stored /// in GenericValue. - ///\param [out] vpSVR - The StoredValueRef that is created. + ///\param [out] vpSVR - The Value that is created. /// - void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, double value); + void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, double value); ///\brief Set the value of the GenericValue for the expression /// evaluated at the prompt. Extract through /// APFloat(ASTContext::getFloatTypeSemantics(QT), const APInt &) - ///\param [in] vpI - The cling::Interpreter for StoredValueRef. + ///\param [in] vpI - The cling::Interpreter for Value. ///\param [in] vpQT - The opaque ptr for the clang::QualType of value. ///\param [in] value - The value of the assignment to be stored /// in GenericValue. - ///\param [out] vpSVR - The StoredValueRef that is created. + ///\param [out] vpSVR - The Value that is created. /// - void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, + void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, long double value); ///\brief Set the value of the GenericValue for the expression /// evaluated at the prompt. /// We are using unsigned long long instead of uint64, because we don't /// want to #include the header. - ///\param [in] vpI - The cling::Interpreter for StoredValueRef. + ///\param [in] vpI - The cling::Interpreter for Value. ///\param [in] vpQT - The opaque ptr for the clang::QualType of value. ///\param [in] value - The uint64_t value of the assignment to be stored /// in GenericValue. - ///\param [out] vpSVR - The StoredValueRef that is created. + ///\param [out] vpSVR - The Value that is created. /// - void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, + void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, unsigned long long value); ///\brief Set the value of the GenericValue for the expression /// evaluated at the prompt. - ///\param [in] vpI - The cling::Interpreter for StoredValueRef. + ///\param [in] vpI - The cling::Interpreter for Value. ///\param [in] vpQT - The opaque ptr for the clang::QualType of value. ///\param [in] value - The void* value of the assignment to be stored /// in GenericValue. - ///\param [out] vpSVR - The StoredValueRef that is created. + ///\param [out] vpV - The Value that is created. /// - void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, + void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, const void* value); ///\brief Set the value of the Generic value and return the address /// for the allocated storage space. - ///\param [in] vpI - The cling::Interpreter for StoredValueRef. + ///\param [in] vpI - The cling::Interpreter for Value. ///\param [in] vpQT - The opaque ptr for the clang::QualType of value. - ///\param [out] vpSVR - The StoredValueRef that is created. + ///\param [out] vpV - The Value that is created. /// ///\returns the address where the value should be put. /// - void* setValueWithAlloc(void* vpI, void* vpSVR, void* vpQT); + void* setValueWithAlloc(void* vpI, void* vpV, void* vpQT); ///\brief Placement new doesn't work for arrays. It needs to be called on /// each element. For non-PODs we also need to call the *structors. This diff --git a/include/cling/Interpreter/Value.h b/include/cling/Interpreter/Value.h index 61b83c9f..0c514544 100644 --- a/include/cling/Interpreter/Value.h +++ b/include/cling/Interpreter/Value.h @@ -61,10 +61,6 @@ namespace cling { /// \brief Retrieve the underlying, canonical, desugared, unqualified type. EStorageType getStorageType() const; - /// \brief Whether this type needs managed heap, i.e. the storage provided - /// by Storage is insufficient. - bool needsManagedAllocation() const; - /// \brief Allocate storage as needed by the type. void ManagedAllocate(Interpreter* interp); @@ -79,7 +75,7 @@ namespace cling { public: /// \brief Default constructor, creates a value that IsInvalid(). - Value() {} + Value(): m_Type(0) {} /// \brief Copy a value. Value(const Value& other); /// \brief Construct a valid but ininitialized Value. After this call the @@ -93,6 +89,11 @@ namespace cling { clang::QualType getType() const; + /// \brief Whether this type needs managed heap, i.e. the storage provided + /// by the m_Storage member is insufficient, or a non-trivial destructor + /// must be called. + bool needsManagedAllocation() const; + /// \brief Determine whether the Value has been set. // /// Determine whether the Value has been set by checking @@ -100,14 +101,14 @@ namespace cling { bool isValid() const; /// \brief Determine whether the Value is set but void. - bool isVoid(const clang::ASTContext& ASTContext) const; + bool isVoid(const clang::ASTContext& Ctx) const; /// \brief Determine whether the Value is set and not void. // /// Determine whether the Value is set and not void. /// Only in this case can getAs() or simplisticCastAs() be called. - bool hasValue(const clang::ASTContext& ASTContext) const { - return isValid() && !isVoid(ASTContext); } + bool hasValue(const clang::ASTContext& Ctx) const { + return isValid() && !isVoid(Ctx); } /// \brief Get a reference to the value without type checking. /// T *must* correspond to type. Else use simplisticCastAs()! @@ -120,7 +121,7 @@ namespace cling { T getAs() const { return const_cast(this)->getAs(); } template - T* getAs(T**) const { return (T*)getAs((void**)0); } + T*& getAs(T**) const { return (T*&)getAs((void**)0); } void*& getAs(void**) { return m_Storage.m_Ptr; } double& getAs(double*) { return m_Storage.m_Double; } long double& getAs(long double*) { return m_Storage.m_LongDouble; } @@ -128,7 +129,21 @@ namespace cling { long long& getAs(long long*) { return m_Storage.m_LL; } unsigned long long& getAs(unsigned long long*) { return m_Storage.m_ULL; } - /// \brief Get the value. + void*& getPtr() { return m_Storage.m_Ptr; } + double& getDouble() { return m_Storage.m_Double; } + long double& getLongDouble() { return m_Storage.m_LongDouble; } + float& getFloat() { return m_Storage.m_Float; } + long long& getLL() { return m_Storage.m_LL; } + unsigned long long& getULL() { return m_Storage.m_ULL; } + + void* getPtr() const { return m_Storage.m_Ptr; } + double getDouble() const { return m_Storage.m_Double; } + long double getLongDouble() const { return m_Storage.m_LongDouble; } + float getFloat() const { return m_Storage.m_Float; } + long long getLL() const { return m_Storage.m_LL; } + unsigned long long getULL() const { return m_Storage.m_ULL; } + + /// \brief Get the value with cast. // /// Get the value cast to T. This is similar to reinterpret_cast(value), /// casting the value of builtins (except void), enums and pointers. diff --git a/lib/Interpreter/CMakeLists.txt b/lib/Interpreter/CMakeLists.txt index 471e4095..ce547b70 100644 --- a/lib/Interpreter/CMakeLists.txt +++ b/lib/Interpreter/CMakeLists.txt @@ -37,7 +37,6 @@ add_cling_library(clingInterpreter RequiredSymbols.cpp ValueExtractionSynthesizer.cpp RuntimeException.cpp - StoredValueRef.cpp Transaction.cpp TransactionTransformer.cpp TransactionUnloader.cpp diff --git a/lib/Interpreter/Interpreter.cpp b/lib/Interpreter/Interpreter.cpp index e439d183..89228713 100644 --- a/lib/Interpreter/Interpreter.cpp +++ b/lib/Interpreter/Interpreter.cpp @@ -957,10 +957,6 @@ namespace cling { m_Executor->installLazyFunctionCreator(fp); } - void Interpreter::suppressLazyFunctionCreatorDiags(bool suppressed/*=true*/) { - m_Executor->suppressLazyFunctionCreatorDiags(suppressed); - } - Value Interpreter::Evaluate(const char* expr, DeclContext* DC, bool ValuePrinterReq) { Sema& TheSema = getCI()->getSema(); diff --git a/lib/Interpreter/Value.cpp b/lib/Interpreter/Value.cpp index dd777d90..22b0f2d1 100644 --- a/lib/Interpreter/Value.cpp +++ b/lib/Interpreter/Value.cpp @@ -74,7 +74,8 @@ namespace { namespace cling { -Value::Value(const Value& other) : m_Type(other.m_Type) { +Value::Value(const Value& other): + m_Type(other.m_Type), m_Storage(other.m_Storage) { if (needsManagedAllocation()) AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Retain(); } @@ -86,7 +87,13 @@ Value::Value(clang::QualType clangTy, Interpreter* Interp): } Value& Value::operator =(const Value& other) { + // Release old value. + if (needsManagedAllocation()) + AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release(); + + // Retain new one. m_Type = other.m_Type; + m_Storage = other.m_Storage; if (needsManagedAllocation()) AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Retain(); return *this; @@ -103,8 +110,8 @@ clang::QualType Value::getType() const { bool Value::isValid() const { return !getType().isNull(); } -bool Value::isVoid(const clang::ASTContext& ASTContext) const { - return isValid() && ASTContext.hasSameType(getType(), ASTContext.VoidTy); +bool Value::isVoid(const clang::ASTContext& Ctx) const { + return isValid() && Ctx.hasSameType(getType(), Ctx.VoidTy); } Value::EStorageType Value::getStorageType() const { @@ -130,14 +137,16 @@ Value::EStorageType Value::getStorageType() const { } bool Value::needsManagedAllocation() const { - return !getType()->getUnqualifiedDesugaredType()->isBuiltinType(); + if (!isValid()) return false; + const clang::Type* UnqDes = getType()->getUnqualifiedDesugaredType(); + return UnqDes->isRecordType() || UnqDes->isArrayType() + || UnqDes->isMemberPointerType(); } void Value::ManagedAllocate(Interpreter* interp) { assert(interp && "This type requires the interpreter for value allocation"); void* dtorFunc = 0; - if (const clang::RecordType* RTy - = clang::dyn_cast(getType())) + if (const clang::RecordType* RTy = getType()->getAs()) dtorFunc = GetDtorWrapperPtr(RTy->getDecl(), *interp); const clang::ASTContext& ctx = interp->getCI()->getASTContext(); diff --git a/lib/Interpreter/ValueExtractionSynthesizer.h b/lib/Interpreter/ValueExtractionSynthesizer.h index 9caed021..330ae582 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.h +++ b/lib/Interpreter/ValueExtractionSynthesizer.h @@ -73,7 +73,7 @@ public: /// call to cling::runtime::internal::copyArray(...) /// /// We need to synthesize later: - /// Wrapper has signature: void w(cling::StoredValueRef SVR) + /// Wrapper has signature: void w(cling::Value V) /// case 1): /// setValueNoAlloc(gCling, &SVR, lastExprTy, lastExpr()) /// case 2): diff --git a/test/Interfaces/evaluate.C b/test/Interfaces/evaluate.C index 99e26538..db330d30 100644 --- a/test/Interfaces/evaluate.C +++ b/test/Interfaces/evaluate.C @@ -9,44 +9,44 @@ // RUN: cat %s | %cling -Xclang -verify | FileCheck %s #include "cling/Interpreter/Interpreter.h" -#include "cling/Interpreter/StoredValueRef.h" +#include "cling/Interpreter/Value.h" -cling::StoredValueRef V; -V // CHECK: (cling::StoredValueRef) <<>> @0x{{.*}} +cling::Value V; +V // CHECK: (cling::Value) <<>> @0x{{.*}} gCling->evaluate("return 1;", V); -V // CHECK: (cling::StoredValueRef) boxes [(int) 1] +V // CHECK: (cling::Value) boxes [(int) 1] -// Returns must put the result in the StoredValueRef. +// Returns must put the result in the Value. bool cond = true; gCling->evaluate("if (cond) return \"true\"; else return 0;", V); -V // CHECK: (cling::StoredValueRef) boxes [(const char [5]) "true"] +V // CHECK: (cling::Value) boxes [(const char [5]) "true"] gCling->evaluate("cond = false; if (cond) return \"true\"; else return 0;", V); -V // CHECK: (cling::StoredValueRef) boxes [(int) 0] +V // CHECK: (cling::Value) boxes [(int) 0] gCling->evaluate("auto a = 12.3; a;", V); -V // CHECK: (cling::StoredValueRef) boxes [(double) 1.230000e+01] +V // CHECK: (cling::Value) boxes [(double) 1.230000e+01] long LongV = 17; gCling->evaluate("LongV;", V); -V // CHECK: (cling::StoredValueRef) boxes [(long) 17] +V // CHECK: (cling::Value) boxes [(long) 17] int* IntP = (int*)0x12; gCling->evaluate("IntP;", V); -V // CHECK: (cling::StoredValueRef) boxes [(int *) 0x12] +V // CHECK: (cling::Value) boxes [(int *) 0x12] -cling::StoredValueRef Result; +cling::Value Result; gCling->evaluate("V", Result); -// Here we check what happens for record type like cling::StoredValueRef; they are returned by reference. -Result // CHECK: (cling::StoredValueRef) boxes [(cling::StoredValueRef &) boxes [(int *) 0x12]] -V // CHECK: (cling::StoredValueRef) boxes [(int *) 0x12] +// Here we check what happens for record type like cling::Value; they are returned by reference. +Result // CHECK: (cling::Value) boxes [(cling::Value &) boxes [(int *) 0x12]] +V // CHECK: (cling::Value) boxes [(int *) 0x12] // Savannah #96277 gCling->evaluate("gCling->declare(\"double sin(double);\"); double one = sin(3.141/2);", V); -V // CHECK: (cling::StoredValueRef) boxes [(double) 1.000000e+00] +V // CHECK: (cling::Value) boxes [(double) 1.000000e+00] gCling->process("double one = sin(3.141/2);", &V); -V // CHECK: (cling::StoredValueRef) boxes [(double) 1.000000e+00] +V // CHECK: (cling::Value) boxes [(double) 1.000000e+00] one // CHECK: (double) 1.000 int one; // expected-error {{redefinition of 'one' with a different type: 'int' vs 'double'}} expected-note {{previous definition is here}} @@ -59,7 +59,7 @@ gCling->evaluate("f", V); V.isValid() //CHECK: {{\([_]B|b}}ool) true // end PR#98434 -// Check lifetime of objects in StoredValue +// Check lifetime of objects in Value .rawInput 1 struct WithDtor { static int fgCount; @@ -73,25 +73,24 @@ WithDtor getWithDtor() { return WithDtor(); } std::vector getWithDtorVec() { std::vector ret; ret.resize(7); return ret; } .rawInput 0 -cling::StoredValueRef* VOnHeap = new cling::StoredValueRef(); +cling::Value* VOnHeap = new cling::Value(); gCling->evaluate("getWithDtor()", *VOnHeap); -*VOnHeap //CHECK: (cling::StoredValueRef) boxes [(WithDtor) @0x{{.*}}] +*VOnHeap //CHECK: (cling::Value) boxes [(WithDtor) @0x{{.*}}] WithDtor::fgCount //CHECK: (int) 1 delete VOnHeap; WithDtor::fgCount //CHECK: (int) 0 // Check destructor call for templates -VOnHeap = new cling::StoredValueRef(); +VOnHeap = new cling::Value(); gCling->evaluate("getWithDtorVec()", *VOnHeap); -*VOnHeap //CHECK: (cling::StoredValueRef) boxes [(std::vector) @0x{{.*}}] +*VOnHeap //CHECK: (cling::Value) boxes [(std::vector) @0x{{.*}}] WithDtor::fgCount //CHECK: (int) 7 delete VOnHeap; WithDtor::fgCount //CHECK: (int) 0 // long doubles (tricky for the JIT). gCling->evaluate("17.42L", V); -V // CHECK: (cling::StoredValueRef) boxes [(long double) 17.4200000{{[0-9]*}}L] - +V // CHECK: (cling::Value) boxes [(long double) 17.42{{[0-9]*}}L] // Test references, temporaries .rawInput 1 @@ -121,19 +120,19 @@ namespace cling { return p->asStr(); } } -void dumpTracerSVR(cling::StoredValueRef& svr) { - ((Tracer*)svr.get().getAs())->dump("dump"); +void dumpTracerSVR(cling::Value& svr) { + ((Tracer*)svr.getAs())->dump("dump"); } .rawInput 0 // Creating the static in constructs one object. It gets returned by // reference; it should only be destructed by ~JIT, definitely not by -// ~StoredValueRef (which should only store a Tracer&) +// ~Value (which should only store a Tracer&) gCling->evaluate("RefMaker()", V); // This is the local static: // CHECK: REF{1}:ctor printf("RefMaker() done\n"); // CHECK-NEXT: RefMaker() done -V // CHECK-NEXT: (cling::StoredValueRef) boxes [(Tracer &) @{{.*}}] +V // CHECK-NEXT: (cling::Value) boxes [(Tracer &) @{{.*}}] dumpTracerSVR(V); // CHECK-NEXT: REF{1}:dump // Setting a new value should destruct the old - BUT it's a ref thus no @@ -146,7 +145,7 @@ gCling->evaluate("ObjMaker()", V); // The temporary gets created: // CHECK-NEXT:MADE{2}:ctor printf("ObjMaker() done\n"); //CHECK-NEXT: ObjMaker() done -V // CHECK-NEXT: (cling::StoredValueRef) boxes [(Tracer) @{{.*}}] +V // CHECK-NEXT: (cling::Value) boxes [(Tracer) @{{.*}}] dumpTracerSVR(V); // CHECK-NEXT: MADE{2}:dump // Creating a variable: @@ -160,17 +159,17 @@ Tracer RT("VAR"); // CHECK-NEXT: VAR{3}:ctor // CHECK-NEXT: MADE{2}:dtor gCling->evaluate("RT", V); // should not call any ctor! printf("RT done\n"); //CHECK-NEXT: RT done -V // CHECK-NEXT: (cling::StoredValueRef) boxes [(Tracer &) @{{.*}}] +V // CHECK-NEXT: (cling::Value) boxes [(Tracer &) @{{.*}}] dumpTracerSVR(V); // CHECK-NEXT: VAR{2}:dump // The following creates a copy, explicitly. This temporary object is then put -// into the StoredValueRef. +// into the Value. // gCling->evaluate("(Tracer)RT", V); // Copies RT: //CHECK-NEXT: VAR+{3}:copy printf("(Tracer)RT done\n"); //CHECK-NEXT: RT done -V // CHECK-NEXT: (cling::StoredValueRef) boxes [(Tracer) @{{.*}}] +V // CHECK-NEXT: (cling::Value) boxes [(Tracer) @{{.*}}] dumpTracerSVR(V); // CHECK-NEXT: VAR+{3}:dump // Destruct the variables with static storage: diff --git a/test/Prompt/Regression.C b/test/Prompt/Regression.C index 93419872..c608a259 100644 --- a/test/Prompt/Regression.C +++ b/test/Prompt/Regression.C @@ -13,10 +13,10 @@ // PR #96277 #include "cling/Interpreter/Interpreter.h" -#include "cling/Interpreter/StoredValueRef.h" +#include "cling/Interpreter/Value.h" #include gCling->declare("int print() { printf(\"print is run.\\n\"); return 1; }"); -cling::StoredValueRef V; +cling::Value V; gCling->process("int a = print();",&V); //CHECK: print is run. gCling->process("a", &V); @@ -28,7 +28,7 @@ gCling->process("a;", &V); gCling->process("\"Root\"", &V); // CHECK: (const char [5]) "Root" V -// CHECK: (cling::StoredValueRef) boxes [(const char *) "Root"] +// CHECK: (cling::Value) boxes [(const char *) "Root"] // End PR #98146 typedef enum {k1,k2} enumName; enumName var