HighCommander4 wrote:

> I suspect it won't work with the present `TemplateTypeParm{Type,Decl}` 
> models. `TemplateTypeParmDecl` per se is not tied to any `CXXRecordDecl` nor 
> `FunctionDecl` that the template parameter is declaring with. (For the most 
> seemingly-relevant part, i.e. the `DeclContext` it records, is the scope that 
> the template defines.)

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.

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.

I also discovered some complications related to nested templates, and I have 
some thoughts on how to resolve them, but I'm going to suggest that we start 
with getting a simple case (e.g. just one level of templates, no nested 
templates) to work, and then tackle nested templates as a next step.

> > If so, find the argument type substituted for this template parameter, and 
> > replace the template parameter with this type.
> 
> I was thinking this way before getting into the details :-). Soon I realized 
> that we had to tackle synthesized types e.g.
> 
> ```c++
> template <template <class, int> typename C, typename D, int E>
> void work() {
>   C<D, E> complicated_type;
>   // ^ Shall we perform the type substitution once again? ;)
> }
> ```

I'm not too concerned about this. The idea behind `HeuristicResolver` is to 
perform name lookups in the primary template as a heuristic.

So, to give an example:

```c++
template <typename T>
void work() {
  std::vector<T> a;
  a.pop_back();
}
```

here, `pop_back` is looked up in the primary template scope of `std::vector`; 
information from the argument list `<T>` is not used.

Now, applying this to your example:

```c++
template <template <typename> class A, typename T>
void work() {
  A<T> a;
  a.pop_back();
}

// work() has one instantiation, with [A = std::vector, T = bar] 
```

applying the "only instantiation" heuristic will tell us that `A = 
std::vector`, and then we can look up `pop_back` in the primary template scope 
of `std::vector`; we still don't use information from the argument list `<T>`.

We could potentially envision future enhancements to make use of information 
from the "only instantiation" to make lookup inside template specialization 
types more accurate than just "use the primary template" (which could then 
apply to the `std::vector<T>` case as well, and e.g. return a more accurate 
result if the "only instantiation" is `T = bool`), but that seems like more of 
an edge case and I'd rather leave it to a future change.

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