llvm / llvm-project

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

[Clang][C++23] `<` not parsed as the start of a template list in type-only contexts #102502

Open MitalAshok opened 3 months ago

MitalAshok commented 3 months ago

https://eel.is/c++draft/temp.names#3

A < is interpreted as the delimiter of a template-argument-list if it follows a name [...] that is [...] in a type-only context other than a nested-name-specifier.

This wording was added by P1787R6 for C++23

https://godbolt.org/z/GanbhKTh1

template<typename T>
struct X : T::type<void> {};

template<typename T, typename = typename T::type<void>>
int Y = sizeof(typename T::type<void>);

// CWG2806
template<typename T>
concept C = requires {
  typename T::type<void>;
};

// CWG2903
template<typename T>
struct Z : T::type<void>::type {};

Last two are valid after https://cplusplus.github.io/CWG/issues/2806.html and https://cplusplus.github.io/CWG/issues/2903.html

<source>:2:15: error: use 'template' keyword to treat 'type' as a dependent template name
    2 | struct X : T::type<void> {};
      |               ^
      |               template 
<source>:4:45: error: use 'template' keyword to treat 'type' as a dependent template name
    4 | template<typename T, typename = typename T::type<void>>
      |                                             ^
      |                                             template 
<source>:5:28: error: use 'template' keyword to treat 'type' as a dependent template name
    5 | int Y = sizeof(typename T::type<void>);
      |                            ^
      |                            template 
<source>:10:15: error: use 'template' keyword to treat 'type' as a dependent template name
   10 |   typename T::type<void>;
      |               ^
      |               template 
<source>:15:15: error: use 'template' keyword to treat 'type' as a dependent template name
   15 | struct Z : T::type<void>::type {};
      |               ^
      |               template 

This compiles with -fms-extensions.

MSVC only compiles this with /permissive (not /permissive-):

template<typename T, typename = typename T::type<void>>
int Y = sizeof(typename T::type<void>);

GCC compiles it all.

llvmbot commented 3 months ago

@llvm/issue-subscribers-clang-frontend

Author: Mital Ashok (MitalAshok)

https://eel.is/c++draft/temp.names#3 > A `<` is interpreted as the delimiter of a *template-argument-list* if it follows a name [...] that is [...] in a type-only context other than a *nested-name-specifier*. This wording was added by [P1787R6](https://wg21.link/P1787R6) for C++23 https://godbolt.org/z/GanbhKTh1 ```c++ template<typename T> struct X : T::type<void> {}; template<typename T, typename = typename T::type<void>> int Y = sizeof(typename T::type<void>); // CWG2806 template<typename T> concept C = requires { typename T::type<void>; }; // CWG2903 template<typename T> struct Z : T::type<void>::type {}; ``` Last two are valid after https://cplusplus.github.io/CWG/issues/2806.html and https://cplusplus.github.io/CWG/issues/2903.html ``` <source>:2:15: error: use 'template' keyword to treat 'type' as a dependent template name 2 | struct X : T::type<void> {}; | ^ | template <source>:4:45: error: use 'template' keyword to treat 'type' as a dependent template name 4 | template<typename T, typename = typename T::type<void>> | ^ | template <source>:5:28: error: use 'template' keyword to treat 'type' as a dependent template name 5 | int Y = sizeof(typename T::type<void>); | ^ | template <source>:10:15: error: use 'template' keyword to treat 'type' as a dependent template name 10 | typename T::type<void>; | ^ | template <source>:15:15: error: use 'template' keyword to treat 'type' as a dependent template name 15 | struct Z : T::type<void>::type {}; | ^ | template ``` This compiles with `-fms-extensions`. MSVC only compiles this with `/permissive` (not `/permissive-`): ```c++ template<typename T, typename = typename T::type<void>> int Y = sizeof(typename T::type<void>); ``` GCC compiles it all.
frederick-vs-ja commented 3 months ago

https://eel.is/c++draft/temp.names#3

A < is interpreted as the delimiter of a template-argument-list if it follows a name [...] that is [...] in a type-only context other than a nested-name-specifier.

This wording was added by P1787R6 for C++23

These parts of changes seem to be the resolution of CWG1478 but touch more things than the original issue.

Edit: Is this already tracked in #54150?

MitalAshok commented 3 months ago

@frederick-vs-ja I don't think this is related to CWG1478 because that's specifically about when there isn't a <.

Reading P1787P6§Parsing makes it seem like type-only contexts (previously: type-id-only contexts, in Clang as ImplicitTypenameContext) were extended to include "implicit template" that doesn't seem to be mentioned in #54150.

MitalAshok commented 3 months ago

This might be a dup of #95447

shafik commented 2 months ago

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