llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.3k stars 11.69k forks source link

No AST representation created for explicit instantiation declarations of function templates #21040

Open llvmbot opened 10 years ago

llvmbot commented 10 years ago
Bugzilla Link 20666
Version trunk
OS Linux
Reporter LLVM Bugzilla Contributor
CC @DougGregor,@jbytheway,@zygoloid,@steveire

Extended Description

Explicit (extern) template declarations have no representation in the AST:

template int __ostream_insert() { return 0; }

extern template int __ostream_insert();

template<> int __ostream_insert() { return 1; }

Produces:

TranslationUnitDecl 0x3763300 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x3763840 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x37638a0 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x3763c60 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
|-FunctionTemplateDecl 0x3763e50 </tmp/jp.cpp:1:3, line:4:3> line:2:7 __ostream_insert
| |-TemplateTypeParmDecl 0x3763cb0 <line:1:13, col:22> col:22 typename T
| |-FunctionDecl 0x3763db0 <line:2:3, line:4:3> line:2:7 __ostream_insert 'int (void)'
| | `-CompoundStmt 0x3763ed8 <col:26, line:4:3>
| |   `-ReturnStmt 0x3763eb8 <line:3:5, col:12>
| |     `-IntegerLiteral 0x3763e98 <col:12> 'int' 0
| |-FunctionDecl 0x37a4f60 <line:2:3, line:4:3> line:2:7 __ostream_insert 'int (void)'
| | `-TemplateArgument type 'char'
| `-Function 0x37a50a0 '__ostream_insert' 'int (void)'
`-FunctionDecl 0x37a50a0 prev 0x37a51c0 <line:8:3, line:10:3> line:8:18 __ostream_insert 'int (void)'
  |-TemplateArgument type 'long'
  `-CompoundStmt 0x37a5380 <col:43, line:10:3>
    `-ReturnStmt 0x37a5360 <line:9:5, col:12>
      `-IntegerLiteral 0x37a5340 <col:12> 'int' 1

It appears as a child of the FunctionTemplateDecl:

| |-FunctionDecl 0x37a4f60 <line:2:3, line:4:3> line:2:7 __ostream_insert 'int (void)'
| | `-TemplateArgument type 'char'

But the source location is incorrect (points to the parent template, not the extern instantiation.

jbytheway commented 5 years ago

I ran into an aspect of this issue while trying to improve include-what-you-use's handling of arguments to explicit template declarations and similar things.

For example, in the following code:

using my_int = int; constexpr int h(int n) { return n*2; }

template void template_function() {}

template void template_function<my_int[h(7)]>();

the relevant part of the AST is just:

-FunctionTemplateDecl 0x561a3ac05e20 <line:4:1, line:5:27> col:6 template_function |-TemplateTypeParmDecl 0x561a3ac05c78 <line:4:10> col:10 class depth 0 index 0 |-FunctionDecl 0x561a3ac05d80 <line:5:1, col:27> col:6 template_function 'void ()' |-CompoundStmt 0x561a3ac05e70 <col:26, col:27> -FunctionDecl 0x561a3ac06138 <col:1, col:27> col:6 template_function 'void ()' |-TemplateArgument type 'int [14]' -CompoundStmt 0x561a3ac05e70 <col:26, col:27>

To compute uses correctly we need to see that the argument mentioned my_int, rather than int, and that h was called. I'd expect DeclRefExpr entries somewhere in the AST for both my_int and h, but as far as I can see there is nothing. We just get the type int[14].

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 10 years ago

More symptoms of this:

template void f() {} extern template void f(); extern template void f();

... has no declarations on either line 2 or line 3, and only one declaration of 'void f()' in the AST. And:

template void f() {} typedef int Foo; extern template void f();

... has no references to Foo in the AST (defeating rename refactorings and the like).

llvmbot commented 10 years ago

Specifically, the problem we encounter is that its source location is incorrect. It's <line:2:3, line:4:3>, same as the template decl.

llvmbot commented 10 years ago

Isn't FD->getTemplateSpecializationKind() == TSK_ExplicitSpecializationDeclaration?