Cling: Implementing Dynamic Scopes with clang
Current Progress
This document is mostly here for historical reasons. Dynamic scopes are in cling; they are used in production in ROOT.
So here goes the history:
Step 1:
One of the major concerns was: Is it possible to make LLVM and particularly Sema skip the diagnostic errors and build a pseudo-valid abstract syntax tree (AST). Pseudo-valid AST, in the terms of Cling, means that there is an AST which is build successfully but LLVM cannot generate code from it.
According to the advice of the Sebastian Redl (from the clang dev team), we needed to mark all unknown symbols as of dependent type.
In order to mark an unknown symbol as dependent we need to watch clang::Sema’s lookup facilities. We were able to patch Sema in less intrusive way than we did before. We provide last resort lookup, when a lookup fails in Sema. The patch was accepted in clang r126387 and r126648. Now we don’t even need to patch clang, we just provide implementation for the existing hook in Sema!
Step 2:
Next step is to transform the artificially dependent (marked by us) nodes in valid C++ code
to make Sema happy. We substitute h->Draw
with specific template instantiation of:
where T is the expected type of the dependent expression. For example the case with
h->Draw();
will become EvaluateProxyT("h->Draw", {}, CurDC);
CurDC
is the declaration
context in which the expression is used.
This can be seen by running cling with:
text.cxx contains:
Imagine we have more complex use-case
This will end up as:
The return type of EvaluateProxy is bool, because the expressions that are in if statement are implicitly converted to bool. Note that we still don’t know the runtime addresses of a and b, so we need an array of their addresses, which are going to be known at runtime.
Step 3: (Work in progress)
During runtime h->Draw will not fail in lookup, because it will be provided by ROOT, all
we need to do is to get the result and its type from the execution engine and return it
through EvaluateProxy
.
For that we need to create a wrapper during runtime and evaluate the expression.
It is not easy to evaluate this expression, because we need the hint what type is expected.
In the example with h->Draw()
and if (h->Draw(a,b))
we have hints, but there are few
cases that we don’t. They need to be investigated in details.
In order to get the result of the runtime execution of h->Draw()
, we need to create a
wrapper in the declaration context, in which the expression is used and execute it and return
the result and get the type.