compiler-research / CppInterOp

A Clang-based C++ Interoperability Library
Other
38 stars 20 forks source link

[WIP] Converters not created for templated method arguments #211

Closed maximusron closed 2 months ago

maximusron commented 3 months ago

Fails the vectorcall from TemplateProxies when calling the corresponding Executor (in CPyCppyy/Executors.cxx). Reproducible example:

cppyy.cppdef('''class MyTemplatedMethodClass {
public:
template<class A>
long get_size(A) {
    return sizeof(A)+1;
}
''')

m = cppyy.gbl.MyTemplatedMethodClass()
m.get_size(1)

there are two issues here: 1 is not a priority which is the GetSmartPtrInfo interface which is missing but when we create converters for normal C++ classes it returns false anyway so most tests/usecases it will still work.

the second is the interesting bug. The converter creation for args relies on a loop over args that sets up the dispatch cache. where we do fullType = GetMethodArgType(fMethod, iarg) The cling implementation does

TFunction* f = m2f(method);
TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
std::string ft = arg->GetFullTypeName();

which will always return the C++ type of the arg with which we call the function.

For example if we do

m = cppyy.gbl.MyTemplatedMethodClass()
m.get_size(1)

it will be

arg->GetTypeNormalizedName()
$22 = "int"

but with m.get_size('A')

p fullType
$2 = "std::string"

But with clang this returns theParmVarDeclwhich for a templated parameter is ‘A’ in the case of

template<class A>
long get_size(A) {

    return sizeof(A)+1;
}

And we cannot create a converter passing a string type 'A' I did think of one way to approach this. We look for the Clang::DeclStmt that should be created when the python side cppyy.obj.function(arg)is called. Then we traverse the AST which should contain the CXXMemberCallExpr for theMemberExpr which is our bound member function get_size and the nodes would contain the types of the literals passed. We get the normalised type and go from there. This should even work for multiple template parameters:

template<class A, class B>
long get_size(A, B) {
    return sizeof(A)+sizeof(B);
}|
long res = a.get_size(1.5, 'A');

CallExpr node will contain:

|-FloatingLiteral <col:27> 'double' 1.500000e+00
`-CharacterLiteral <col:32> 'char' 65 (edited) 
maximusron commented 2 months ago

Closing as this is fixed with: