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