No template specialization in the AST if a header is missing

Observation: Clang AST don’t contain any template specialisation if a header file is missing. It is true even when the template got nothing to do with the header file.

For example,

#include "unknown_header.h"

template<class T>
T add(T x, T y) {return x + y;}

void sum(void)
  add<double>(5.0, 6.0);

generate the FunctionTemplateDecl instance, which doesn’t contain specialisation for type double.

But if we get rid of “unknown_header.h”, resulting in successful compilation, we can see the specialisation using type double. The specialisation can be seen below after removing the header.

|-FunctionTemplateDecl 0x55ec327d83e8 <tmp.cpp:1:1, line:2:31> col:3 add
| |-TemplateTypeParmDecl 0x55ec327d80f0 <line:1:10, col:16> col:16 referenced class depth 0 index 0 T
| |-FunctionDecl 0x55ec327d8348 <line:2:1, col:31> col:3 add 'T (T, T)'
| | |-ParmVarDecl 0x55ec327d81c0 <col:7, col:9> col:9 referenced x 'T'
| | |-ParmVarDecl 0x55ec327d8238 <col:12, col:14> col:14 referenced y 'T'
| | `-CompoundStmt 0x55ec327d8580 <col:17, col:31>
| |   `-ReturnStmt 0x55ec327d8570 <col:18, col:29>
| |     `-BinaryOperator 0x55ec327d8550 <col:25, col:29> '<dependent type>' '+'
| |       |-DeclRefExpr 0x55ec327d8510 <col:25> 'T' lvalue ParmVar 0x55ec327d81c0 'x' 'T'
| |       `-DeclRefExpr 0x55ec327d8530 <col:29> 'T' lvalue ParmVar 0x55ec327d8238 'y' 'T'
| `-FunctionDecl 0x55ec327d8ae8 <col:1, col:31> col:3 used add 'double (double, double)'
|   |-TemplateArgument type 'double'
|   | `-BuiltinType 0x55ec327923c0 'double'
|   |-ParmVarDecl 0x55ec327d8960 <col:7, col:9> col:9 used x 'double':'double'
|   |-ParmVarDecl 0x55ec327d89d8 <col:12, col:14> col:14 used y 'double':'double'
|   `-CompoundStmt 0x55ec327d8da8 <col:17, col:31>
|     `-ReturnStmt 0x55ec327d8d98 <col:18, col:29>
|       `-BinaryOperator 0x55ec327d8d78 <col:25, col:29> 'double' '+'
|         |-ImplicitCastExpr 0x55ec327d8d48 <col:25> 'double':'double' <LValueToRValue>
|         | `-DeclRefExpr 0x55ec327d8d08 <col:25> 'double':'double' lvalue ParmVar 0x55ec327d8960 'x' 'double':'double'
|         `-ImplicitCastExpr 0x55ec327d8d60 <col:29> 'double':'double' <LValueToRValue>
|           `-DeclRefExpr 0x55ec327d8d28 <col:29> 'double':'double' lvalue ParmVar 0x55ec327d89d8 'y' 'double':'double'

Question: What stops clang from generating the template specialisation if the header is missing?

I haven’t confirmed, but I think definitions for implicitly instantiated function template specializations are instantiated during end of TU processing, but that processing is skipped if a fatal error is reported earlier.

Thanks for the response.

Can you point to any file/location (in the clang source code) to understand this further? I am trying to figure out if there is a way to make the clang (or ask it to try) to generate specialisation.

I just learnt that adding an empty header file generates the specialisation. It even works if there are other compilation errors that are unrelated to the template.

It will still be nice to understand the following:

Why does missing a header file stop the generation of the template specialisation, but an empty file doesn’t have the same outcome?

See Sema:: ActOnEndOfTranslationUnit () at llvm-project/Sema.cpp at main · llvm/llvm-project · GitHub.

A missing header file is an error, an empty header file is not.

1 Like