zyn0217 wrote:

Thank you again for bothering with this, and sorry for not responding for over 
a week.

Just now, I replicated the experimentation

> I've done some local experimentation, and what I'm seeing is that 
> `TemplateTypeParmDecl::getDeclContext()` does return the FunctionDecl or 
> CXXRecordDecl which owns the template parameter.

 and had to admit that I was wrong previously. Something must be wrong with my 
recollection, but I could clearly remember that I'd run into the same pitfall 
my first time. (I was about to write the comment to highlight this, but soon, I 
gave up taking this approach since it looks more constricted than I thought. 
And here I'm explaining it.)

> One tricky thing I found is that when starting from a template parameter 
> type, it's important to use dyn_cast<TemplateTypeParmType>(T) rather than 
> T->getAs<TemplateTypeParmType>(); the latter does more than just cast, it 
> returns the canonical type whose associated Decl is null.

The contrived example involving template template parameter is one obstruction; 
Another more common example could be such. (Which is simplified from the test 
case):

```cpp
template <typename T>
struct Outer {
  template <typename U>
  void foo(U arg) {
     arg.fo^o();
  }
};

struct Widget {
  void foo();
};

Outer<int>().foo(Widget());
```

Here, we want to find the only instantiation before locating `foo().` Which is 
`Outer<int>::foo<Widget>.` To locate that, we shall find the templated Decl for 
`foo`, which could be done by conducting the `ParmVarDecl -> 
TemplateParmVarDecl -> getDeclContext -> FunctionTemplateDecl` dance. 
Everything goes well until the specialization set for the 
`FunctionTemplateDecl` is **empty**. Hence, our `getOnlyInstantiation` returns 
null, which is crazy!

This is because when clang performs the instantiation for member templates, it 
creates a new `FunctionTemplateDecl` from the primary template (i.e. where we 
start from) and links the instantiation declaration to that new `Decl`.

https://github.com/llvm/llvm-project/blob/1449b349ac4072adb1f593234c1d6f67986d3b6a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp#L2184-L2203

And what makes it worse is, as of now, we don't have any approach to retrieve 
the new templated `Decl` from the primary `Decl`:

https://github.com/llvm/llvm-project/blob/1449b349ac4072adb1f593234c1d6f67986d3b6a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp#L4789-L4803

("// FIXME: New needs a pointer to Tmpl", I was quite frustrated when I read 
it!)

(This patch first walks up the `DeclContext` to collect the very outer `Decl` 
for templates; then, the visitor could access the later-created template decl 
and its instantiation from the enclosing template. Again, I didn't realize the 
visitor resolved this issue this way (by accident), so I'm sorry for not being 
so straightforward.)

> The implementation of "Approach 2" could look similar to the current 
> InstantiatedDeclVisitor in the patch, except the node type we are searching 
> for is not limited to a Decl, it can also be other node types like Stmt etc.

Exactly. And this is why the patch is marked as "Take 1" :)

> However, the entry point to the check can be the same (e.g. for resolving a 
> dependent member expr, we'd want to do the "only instantiation" check in the 
> same cases where we call HeuristicResolver::resolveMemberExpr() from external 
> code), so the functionality could still live in HeuristicResolver for 
> organizational purposes.

Yeah, I'd love to extend the HeuristicResolver to make it more accurate and not 
just dependent on the mere name lookup.

https://github.com/llvm/llvm-project/pull/71279
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to