cling/test/Interfaces/evaluate.C
2023-12-11 08:59:21 +01:00

237 lines
8.1 KiB
C

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// 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.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling -Xclang -verify | FileCheck %s
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"
#include <cmath>
cling::Value V;
V // CHECK: (cling::Value &) <<<invalid>>> @0x{{.*}}
gCling->evaluate("return 1;", V);
V // CHECK: (cling::Value &) boxes [(int) 1]
gCling->evaluate("(void)V", V);
V // CHECK-NEXT: (cling::Value &) boxes [(void) ]
// Returns must put the result in the Value.
bool cond = true;
gCling->evaluate("if (cond) return \"true\"; else return 0;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(const char[5]) "true"]
gCling->evaluate("if (cond) return; else return 12;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(void) ]
gCling->evaluate("if (cond) return; int aa = 12;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(void) ]
gCling->evaluate("cond = false; if (cond) return \"true\"; else return 0;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(int) 0]
gCling->evaluate("bool a = [](){return true;};", V);
V // CHECK-NEXT: (cling::Value &) boxes [(bool) true]
gCling->evaluate("auto a = 12.3; a;", V);
V // CHECK: (cling::Value &) boxes [(double) 12.300000]
long LongV = 17;
gCling->evaluate("LongV;", V);
V // CHECK: (cling::Value &) boxes [(long) 17]
int* IntP = (int*)0x12;
gCling->evaluate("IntP;", V);
V // CHECK: (cling::Value &) boxes [(int *) 0x12 <invalid memory address>]
cling::Value Result;
gCling->evaluate("V", Result);
// 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 <invalid memory address>]]
V // CHECK: (cling::Value &) boxes [(int *) 0x12 <invalid memory address>]
// Savannah #96277
gCling->evaluate("gCling->declare(\"double sin(double);\"); double one = sin(3.1416/2);", V);
V // CHECK: (cling::Value &) boxes [(double) 1.0000000]
gCling->process("double one = sin(3.1416/2); // expected-note {{previous definition is here}}", &V);
V // CHECK: (cling::Value &) boxes [(double) 1.0000000]
one // CHECK: (double) 1
int one; // expected-error {{redefinition of 'one' with a different type: 'int' vs 'double'}}
// Make sure that PR#98434 doesn't get reintroduced.
.rawInput
void f(int) { return; }
.rawInput
gCling->evaluate("f", V);
V.isValid() //CHECK: {{\([_]B|b}}ool) true
// end PR#98434
// Multi-dim arrays (ROOT-7016)
gCling->evaluate("int multiDimArray[2][3][4]{{{1,2,3,4},{11,12,13,14},{21,22,23,24}},"
"{{101,102,103,104},{111,112,113,114},{121,122,123,124}}};", V);
V // CHECK-NEXT: (cling::Value &) boxes [(int[2][3][4]) { { { 1, 2, 3, 4 }, { 11, 12, 13, 14 }, { 21, 22, 23, 24 } }, { { 101, 102, 103, 104 }, { 111, 112, 113, 114 }, { 121, 122, 123, 124 } } }]
// Check lifetime of objects in Value
.rawInput 1
struct WithDtor {
char mem = 0;
static int fgCount;
WithDtor() { ++fgCount; }
WithDtor(const WithDtor&) { ++fgCount; }
~WithDtor() { --fgCount; }
};
int WithDtor::fgCount = 0;
WithDtor getWithDtor() { return WithDtor(); }
#include <vector>
std::vector<WithDtor> getWithDtorVec() { std::vector<WithDtor> ret; ret.resize(7); return ret; }
.rawInput 0
cling::Value* VOnHeap = new cling::Value();
gCling->evaluate("getWithDtor()", *VOnHeap);
*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::Value();
gCling->evaluate("getWithDtorVec()", *VOnHeap);
*VOnHeap //CHECK: (cling::Value &) boxes [(std::vector<WithDtor>) {{{ (@0x.*, )*@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::Value &) boxes [(long double) 17.42{{[0-9]*}}L]
// Test references, temporaries
.rawInput 1
extern "C" int printf(const char*,...);
struct Tracer {
std::string Content;
int Instance;
static int InstanceCount;
Tracer(const char* str): Content(str), Instance(++InstanceCount) {
dump("ctor");
}
Tracer(const Tracer& o): Content(o.Content + "+"), Instance(++InstanceCount) {
dump("copy");
}
~Tracer() { dump("dtor");}
std::string asStr() const {
return Content + "{" + std::to_string(Instance) + "}";
}
void dump(const char* tag) { printf("%s:%s\n", asStr().c_str(), tag); }
};
int Tracer::InstanceCount = 0;
Tracer ObjMaker() { return Tracer("MADE"); }
Tracer& RefMaker() { static Tracer R("REF"); return R; }
const Tracer& ConstRefMaker() {static Tracer R("CONSTREF"); return R;}
namespace cling {
// FIXME: inline printValue is not used by PrintClingValue()!
std::string printValue(const Tracer* const p, const Tracer* const u,
const Value& V) {
return p->asStr();
}
}
void dumpTracerSVR(cling::Value& svr) {
((Tracer*)svr.castAs<void*>())->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
// ~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::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
// destruction.
// Create a temporary. Copies it into V through placement-new and copy
// construction. The latter is elided; the temporary *is* what's stored in V.
// Thus all we see is the construction of the temporary.
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::Value &) boxes [(Tracer) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: MADE{2}:dump
// Creating a variable:
Tracer RT("VAR"); // CHECK-NEXT: VAR{3}:ctor
// The following is a declRefExpr of lvalue type. We explicitly treat this as
// a reference; i.e. the cling::Value will claim to store a Tracer&. No extra
// construction, no extra allocation should happen.
//
// Setting a new value should destruct the old:
// 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::Value &) boxes [(Tracer &) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: VAR{3}:dump
// The following creates a copy, explicitly. This temporary object is then put
// into the Value.
//
gCling->evaluate("(Tracer)RT", V);
// Copies RT:
//CHECK-NEXT: VAR+{4}:copy
printf("(Tracer)RT done\n"); //CHECK-NEXT: RT done
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: VAR+{4}:dump
// Check eval of array var
Tracer arrV[] = {ObjMaker(), ObjMaker(), ObjMaker()};
// The array is built:
//CHECK-NEXT: MADE{5}:ctor
//CHECK-NEXT: MADE{6}:ctor
//CHECK-NEXT: MADE{7}:ctor
gCling->evaluate("arrV", V);
// Now V gets destructed...
//CHECK-NEXT: VAR+{4}:dtor
// ...and the elements are copied:
//CHECK-NEXT: MADE+{8}:copy
//CHECK-NEXT: MADE+{9}:copy
//CHECK-NEXT: MADE+{10}:copy
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer[3]) { @{{.*}}, @{{.*}}, @{{.*}} }]
// Explicitly destory the copies
V = cling::Value()
//CHECK-NEXT: MADE+{10}:dtor
//CHECK-NEXT: MADE+{9}:dtor
//CHECK-NEXT: MADE+{8}:dtor
//CHECK-NEXT: (cling::Value &) <<<invalid>>> @0x{{.*}}
gCling->evaluate("arrV", V);
//CHECK-NEXT: MADE+{11}:copy
//CHECK-NEXT: MADE+{12}:copy
//CHECK-NEXT: MADE+{13}:copy
// Destruct the variables with static storage:
// Destruct arrV:
//CHECK-NEXT: MADE{7}:dtor
//CHECK-NEXT: MADE{6}:dtor
//CHECK-NEXT: MADE{5}:dtor
// CHECK-NEXT: VAR{3}:dtor
// CHECK-NEXT: REF{1}:dtor
// V going out of scope
//CHECK-NEXT: MADE+{13}:dtor
//CHECK-NEXT: MADE+{12}:dtor
//CHECK-NEXT: MADE+{11}:dtor