Skip to content

[clang] [clangd] Missing information about explicit instantiation of function template #115418

@16bit-ykiko

Description

@16bit-ykiko
namespace test {
template <typename T>
void foo() {}
}

struct X {};

template void test::f^oo<X>();

Currently, if trigger go-to-definition at the location of ^, clangd will give no response. And the tokens in the explicit instantiation are also not highlighted. After some investigation, I found that the underlying cause is that the Clang frontend doesn't store the information about explicit instantiation of function templates.

Dump the AST of above code

|-NamespaceDecl 0xd083678 <<source>:1:1, line:4:1> line:1:11 test
| `-FunctionTemplateDecl 0xd0838e8 <line:2:1, line:3:13> col:6 foo
|   |-TemplateTypeParmDecl 0xd083708 <line:2:11, col:20> col:20 typename depth 0 index 0 T
|   |-FunctionDecl 0xd083838 <line:3:1, col:13> col:6 foo 'void ()'
|   | `-CompoundStmt 0xd0839c8 <col:12, col:13>
|   `-FunctionDecl 0xd083d18 <col:1, col:13> col:6 foo 'void ()' explicit_instantiation_definition
|     |-TemplateArgument type 'X'
|     | `-RecordType 0xd083aa0 'X'
|     |   `-CXXRecord 0xd0839f8 'X'
|     `-CompoundStmt 0xd0839c8 <col:12, col:13>
`-CXXRecordDecl 0xd0839f8 <line:6:1, col:11> col:8 referenced struct X definition

As you can see, the decl from explicit instantiation is only added to its semantic context but not to its lexical context.

If use a visitor to further explore:

bool VisitFunctionTemplateDecl(clang::FunctionTemplateDecl* decl) {
    for(auto spec: decl->specializations()) {
        spec->getLocation().dump(srcMgr);
        spec->getFunctionTypeLoc().getReturnLoc().getLocalSourceRange().dump(srcMgr)
        spec->getQualifierLoc().getSourceRange().dump(srcMgr);
        auto info = spec->getTemplateSpecializationInfo();
        info->PointOfInstantiation.dump(srcMgr);
        llvm::outs() << info->TemplateArguments << "\n";
        llvm::outs() << info->TemplateArgumentsAsWritten << "\n";
    }
    return true;
}

The output is

test.cpp:3:6
<test.cpp:3:1>
<<invalid sloc>>
test.cpp:8:21
0x564cf04d7560
0x0

Only instantiation point is recorded correctly, all other information is from primary template.

But for explicit specializations, the information is recorded properly.

namespace test {
template <typename T>
void foo() {}
}

struct X {};

template <>
void test::foo<X>() {}

The output is

test.cpp:9:12
<test.cpp:9:1>
<test.cpp:9:6, col:10>
<invalid loc>
0x56162dc7f6f8
0x56162dc7f718

Explicit instantiation of variable template has the same problem.

And I unexpectedly discovered that the location of TypeAliasTemplate incorrectly uses the position of the using keyword instead of the position of the identifier."

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"clangd

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions