<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/57853>57853</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Clang doesn't diagnose missing template keyword in nested-name-specifiers
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:frontend
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          alanzhao1
      </td>
    </tr>
</table>

<pre>
    Copied from [this comment](https://reviews.llvm.org/D53847?id=200440#inline-553532) by @zygoloid referencing [this line](https://github.com/llvm/llvm-project/blob/daedea39d182c7cac3cf9699ec1f58b471398c3b/clang/lib/Sema/SemaTemplate.cpp#L4021-L4024) :

The example would be something like this:

```cpp
template<typename T> struct X {
  template<typename U> struct Y { Y(); using V = int; };
  template<typename U> typename Y<U>::V f();
};
template<typename T> template<typename U>
X<T>::Y<U>::V X<T>::f() {}
```

Clang trunk today points out that the typename keyword is missing on the final line, but fails to point out that the template keyword is also missing. The reason is that in the case where that construct is valid:

```cpp
template<typename T> template<typename U>
X<T>::Y<U>::Y() {}
```

... we are "entering the context" of the nested-name-specifier, which means we don't need a template keyword.

If the FIXME is fixed, then we should diagnose the missing template in the above program.

Also, because we don't rebuild the nested-name-specifier as a dependent nested name specifier in this case, we fail to match it against the declaration in the class, so in my example above, we also produce an "out-of-line definition does not match" error.

A closely-related issue can be seen in an example such as:

```cpp
template<typename T> struct X {
  template<typename U> struct Y { Y(); typedef void V; }; 
  template<typename U> typename Y<U>::V::W f();
};
template<typename T> template<typename U>
X<T>::template Y<U>::V::W X<T>::f() { return 0; }
```
Here, we produce a completely bogus error:

```
<stdin>:6:13: error: 'X::Y::V' (aka 'void') is not a class, namespace, or enumeration
X<T>::template Y<U>::V::W X<T>::f() { return 0; } 
            ^
```
... because we parse this in "entering context" mode and so resolve X<T>::Y<U>::V to the type in the primary template (that is, void). That's wrong: we should defer resolving this name to a type until we know what T and U are, or until we know that we're *actually* entering the context. Specifically, the above program can be extended as follows:

```cpp
template<> template<> struct X<int>::Y<int> {
  struct V { using W = int; };
};
void call(X<int> x) { x.f<int>(); } // OK, f returns int
```


</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzFV0tz2zYQ_jXUBSMNHxJJHXRw7HiaaTs9xHXsI0gsJdQgoQFAy8qv7y5AUbRjtU1mMtVIpAAu9vnhW7DS4ri51nsJgjVGtyxafXA7aVmt2xY6F61uorTcObe3UXYVpbf4NfAs4WAXSj23C222OHWzysplEWW3UkTZTRrHy2UcpZnslOxgvlplqyyN0jWrjixaxl-PW620FMxAAwa6Wnbb0TCteM_qVrpdXy3QLxyQ6eE23xv9F9QOh5XSFd4EBwE8W4ukTOui5nVWN-t8vYY6aVZltSySbF3WGYnWinfkv5I0-gwtH2530O4Vd7Co93sM5LdlnCZzui4pDHIqvoni4Xq3AwYvHFcAO-heCVYBs7oFDAgjU_IJGMX2ZlmUx-FLNvyMG6xG2bU77qHjLbC7KPvIrDN97dgDi4oPQZSx94T_nAg_kjB7xESiy1H2gfWWvLlH72-YxNLiVFTc4O1fNY6jR3xEMxRJdnXPmlH7ENJE38VgLpkJyx5w-m408dbg66eDeZ8VtPw6q9NUX1OdGeale2JOC35ke40psEz3DkvD6QLnMJ_geNBGMIRjK61Pm-68SCM7rgJG02tW4eqGS2VRadD4RuEQ6VQhV1aftC4YQccAt6gen_mFMliquUU07XB_hOlad0NhUfCZK9ppPwqnH6_A43_N-GKxYAdgHN2P0hSZBAyl0UemcfSCGzZluvEzHVgHYk5-zO0eatlIMJTgw07WO9YC7yxpE7qL0sKhPNIV_ya9i6kDn4Lq208Pv3-klDXyBQTpxNmOlNmd36pC8m2nLXjpU7VHzUMxeKWfgSHTbA1vX5m5wnJ6KEDNe6rY2UsDVS_RwsUIGUc4MAFYAYEZGoSYL8dZyLtAjIyA8DkBjzmCXMsdpkc6xrdcIjy8KQHIaoY7SZgasKS4tbQWoYdT7XGkKx_YoNUjE2MUfY2DjuqGaJ7rZk54R70IfunVCg2WddoFB6iQYIw2rxODVjGt6jg3QKkk8NuecN15egTw7uHo5IvtMRj-f7MkSWGo7Jka1P2ZJNkPs2S4ffn5ZDmi9oIDF8kToep607H4FO57-_oXpKIBKSNI6JiApXNYZlbpbW8DEC6VcBhm19YJ2QVPcvwlGV7GpQi84mEknxBBWuBsyZ84PaTS4I2clwGH_AxxypDd89r7qg2Drm8hbIefmrMRH-dPtPr4bgKIGyd8sefGhgMCbYgpW06YstWCNqWgLWzAaoV89M-tEvnh1NROPLA3suXmeKY3DCf0HJ-6kNc1dSWORgvkXKPxfIQlmfAlndkGFwKjUw0IlmiQB3N955CgcM1Tpw9I4mjhzjv_JzWEoTCvhbwbB3xW-I5xxWvXc6WO-Je91z0W7HNgyDpIXX_L0yeqQWkiWEF022il9OG7OObNLpwSDQ79QWpSgTCeMtAgfO9BE85gXy6dwab_PQFRdFiksyX2csLfy6I52x_pyyPRH5jZH79SWpoBqNbbu9ywZ7BJ8jzL10W-Smdik4l1tuYzJ52CTTg_Ee2H1jY2zW8a5njS6d7veXbWG7X57qO97x0I0ttVUa6y2W6TrSEv05jHaZEkVS5KUZTpqoZECB6XZT5TvAJlN_hagdsnnPNx_xpCT4coT_EdYyY3aZym8TqNkzJZJsmi4vU6KZd5VeRpUeQZvqzgy4BU47vOzGy8Z1W_tfhQSevOL0IzpCC5xcOJt4r6ee922mw4Wv-64zqZ-TA2Poa_AT3LHmU">