How to find the AST node for conversion operator for a NTTP


I have the following C++ code:

struct X {
  constexpr operator int() { return 5; }

template<int I>
void foo() {}

void test()

What I’m looking for is to see the conversion vom X{} to int with X{}.operator int() in the AST. Looking at the template arguments for foo<X{}> I can see the argument as an expression with the contents:

CXXFunctionalCastExpr 0x7fa739850968 'struct X' functional cast to struct X <NoOp>
`-InitListExpr 0x7fa7398507f0 'struct X'

This expression only shows the creation of an instance of X. I haven’t found a way to see how X gets converted to an int in the AST. Can someone point me to what I have to do? Thanks!


I see it in the bottom of this AST dump, perhaps you were just looking in the wrong place?

I think because it is a constexpr function, it gets evaluated during semantic analysis and folded into its result immediately, thus it will not be part of the AST.

Indeed, the AST only contains the resulting value 5:

`-FunctionDecl <col:1, col:13> col:6 used foo 'void ()'
  |-TemplateArgument integral 5
  `-CompoundStmt <col:12, col:13>

A curious thing about the AST dumps is that they do not show the Type dimension, only the Decl and Stmt dimensions. However, Type nodes also have a dump() method and we can “trick” clang-query into showing us the trees for type nodes. But the problem is that in f<5>, the type only contains the 5 which is shown in the dump.

I had a hunch that maybe Templight (clang++ [...] -Xclang -templight-dump) can give an answer, but no. Your code only shows this when tried.

name:            foo
kind:            ExplicitTemplateArgumentSubstitution
event:           Begin
orig:            '<source>:6:6'
poi:             '<source>:10:3'
name:            X
kind:            Memoization
event:           Begin
orig:            '<source>:1:8'
poi:             '<source>:10:7'


name:            foo
kind:            DeducedTemplateArgumentSubstitution
event:           End
orig:            '<source>:6:6'
poi:             '<source>:10:3'
name:            'foo<5>'
kind:            TemplateInstantiation
event:           Begin
orig:            '<source>:6:6'
poi:             '<source>:10:3'

At this point, I would say it is a drawback of the current implementation… similar to overload resolution where only the final decision is placed in the AST, this information is lost in translation… Unfortunately, I do not know the ins and outs of Sema well enough to point you to where exactly this evaluation takes place.

Okay, I still don’t see the conversion operator. At the bottom I see

DeclRefExpr 0x556084b6e978 <col:3, col:10> 'void ()' lvalue Function 0x556084b6e880 'foo' 'void ()' 

This is the call to foo. Where do you see the conversion operator?

Thanks! That matches what I thought.

I wondered whether I could restore the information by looking at the NTTP’s type and building my own way to a potential conversion operator. But so far, I have failed with that approach.