Getting HLSL templates working for basic things was the first step in finding all the more complicated cases that didn’t work.

The next set of issues we found related to HLSL features that, by design, didn’t work with templates because HLSL had no support for templates.

Template Instantiation

In my previous changes to support templates I scratched the surface of template instantiation looking at how template arguments are deduced and matched. Exploring issue 4003 took me right into the core of instantiation.

As one of the steps of compilation Clang generates an AST from the source code. The AST for a C++ template is broken into two key pieces. The TemplateDecl and the TemplateSpecializationDecl.

The TemplateDecl is the AST for the code as it is written in source. Where template parameters are unresolved. In C++, template dependent code is syntactically and partially semantically verified in a first pass. Then a second pass lazily instantiates the templates and performs the remaining semantic validation (see: lex.phases in the ISO C++ specification).

In Clang, semantic analysis is performed during AST construction. As a result, instantiating a template is implemented as an AST traversal of the TemplateDecl building out a new TemplateSpecializationDecl. This occurs through Clang’s TreeTransform utilities.

HLSL Annotations

HLSL has a bunch of custom annotations used for marking semantics, bindings, offsets, type information and more. All those annotations are captured in HLSL-specific AST nodes. Since HLSL never had user-defined templates, the HLSL-specific AST nodes were never added to Clang’s template instantiation code.

This resulted in a variety of different errors, a few of which aren’t yet fixed. The simple cases like the bugs fixed in PR 4007 and 4089 required updating template instantiation to deal with HLSL-specific AST nodes.

This Isn’t a Pointer…

The gnarliest case of Clang’s template instantiation not handling HLSL was instantiating the this object. In C++, this is a pointer, but in HLSL it is a reference.

Because template instantiation re-creates AST nodes, the changes in HLSL to generate explicit this objects as a reference were’t replicated on the re-created AST nodes. This resulted in a bunch of odd errors like the one reported in issue 3732.

It was surprisingly easy to update Clang to generate this as a reference. The two fixes are in 4112 and 4123.

The Issues Keep Coming

Jumping along the chronology here, we are still fighting issues with HLSL-specific features not being compatible with templates. Two notable ones are the globallycoherent and matrix orientation (row_major and column_major) keywords. The later of these is still not fixed…

The inability to use globallycoherent on template dependent types was reported in issue 4583. The problem here was that the globallycoherent keyword’s semantic analysis was performed early during the first phase of parsing. Because the type globallycoherent was applied to was a dependent type, the analysis was always producing an error since it wasn’t the expected instantiated UAV type.

To make matters worse, globallycoherent had an additional validation phase during code generation because the initial analysis sometimes didn’t trigger. The fix for globallycoherent under template contexts was merged in 4718.

If you think all this is a lot… just wait. The rabbit hole gets deeper.