llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.6k stars 11.82k forks source link

Clang requires `template` keyword in places it should not (P0634, P1787) #95447

Open zygoloid opened 4 months ago

zygoloid commented 4 months ago

Testcase:

template<typename T> void F() {
  // Clang requires `typename` and `template`. As discussed later in this
  // issue, should require only `typename`.
  T::X<int> f();
}

template<typename T> class C {
  // Should require neither; clang requires `template` but not `typename`.
  T::X<int> g();
};

template<typename T>
// Should require neither; clang requires `template` but not `typename`.
T::X<int> h();

Under P1787 (DR against C++20), per [temp.names]/3, the template keyword is not required before X in g and h, following the same rules that P0634 established for type-only contexts. But Clang (and GCC) seems to not implement this, and still requires template in g and h.

llvmbot commented 4 months ago

@llvm/issue-subscribers-c-20

Author: Richard Smith (zygoloid)

Testcase: ```c++ template<typename T> void F() { T::X<int> f(); } template<typename T> class C { T::X<int> g(); }; template<typename T> T::X<int> h(); ``` Under P1787 (DR against C++20), per [temp.names]/3, the `template` keyword is not required before `X` in `g` and `h`, following the same rules that P0634 established for type-only contexts. But Clang (and GCC) seems to not implement this, and still requires `template` in `g` and `h`.
llvmbot commented 4 months ago

@llvm/issue-subscribers-clang-frontend

Author: Richard Smith (zygoloid)

Testcase: ```c++ template<typename T> void F() { T::X<int> f(); } template<typename T> class C { T::X<int> g(); }; template<typename T> T::X<int> h(); ``` Under P1787 (DR against C++20), per [temp.names]/3, the `template` keyword is not required before `X` in `g` and `h`, following the same rules that P0634 established for type-only contexts. But Clang (and GCC) seems to not implement this, and still requires `template` in `g` and `h`.
zygoloid commented 4 months ago

Another case where Clang misses some of the P1787 changes for the handling of template:

template<template<typename> typename> struct X {};

template<typename T> void f() {
  X<T::R>(); // #1
  X<typename T::R>(); // #2
  X<T::template R>(); // #3
  X<typename T::template R>(); // #4
}

struct D { template<typename> class R {}; };
void g() { f<D>(); }

Under P1787: #1 is valid, and is interpreted as naming the template D::R in the instantiation of f. (Prior to P1787 it was not valid. Clang incorrectly rejects.) #2 is ill-formed; typename T::R unambiguously names a type, not a template. (Clang correctly rejects.) #3 is valid but deprecated by P1787. (Prior to P1787, it was the only way to pass the member template as a template argument; Clang accepts without a deprecation warning.) #4 is presumably ill-formed; T::R cannot be both a template and a type. (Clang rejects.)

Unlike the previous case (which should be applied only in the language modes with implicit typename / P0634), this one should presumably be applied retroactively across all C++ standards.

shafik commented 4 months ago

CC @Endilll

opensdh commented 4 months ago

One more place is in typename T::template X<0>, as made optional by CWG1710, which is a DR presumably against all versions.

shafik commented 2 months ago

Also see: https://github.com/llvm/llvm-project/issues/81731