lime updated this revision to Diff 464465.
lime added a comment.
I rearranged the error messages. But after I rebased this patch on D126907
<https://reviews.llvm.org/D126907>, the file `p3-2a.cpp` no longer passed. So I
did some investigations there <https://reviews.llvm.org/D134128#3813708>. The
problem has not been solved yet.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D134128/new/
https://reviews.llvm.org/D134128
Files:
clang/lib/Parse/ParseTemplate.cpp
clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
clang/test/SemaTemplate/concepts.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -912,11 +912,7 @@
</tr>
<tr> <!-- from Albuquerque -->
<td><a href="https://wg21.link/p0857r0">P0857R0</a></td>
- <td class="partial" align="center">
- <details><summary>Partial</summary>
- Constraining template template parameters is not yet supported.
- </details>
- </td>
+ <td class="unreleased" align="center">Clang 16</td>
</tr>
<tr> <!-- from San Diego -->
<td><a href="https://wg21.link/p1084r2">P1084R2</a></td>
Index: clang/test/SemaTemplate/concepts.cpp
===================================================================
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -59,11 +59,10 @@
x.operator()<false>(); // expected-error {{no matching member function}}
}
- // FIXME: This is valid under P0857R0.
template<typename T> concept C = true;
- template<template<typename T> requires C<T> typename U> struct X {}; // expected-error {{requires 'class'}} expected-error 0+{{}}
+ template<template<typename T> requires C<T> typename U> struct X {};
template<typename T> requires C<T> struct Y {};
- X<Y> xy; // expected-error {{no template named 'X'}}
+ X<Y> xy;
}
namespace PR50306 {
Index: clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
===================================================================
--- clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
+++ clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
@@ -1,22 +1,27 @@
// RUN: %clang_cc1 -std=c++2a -frelaxed-template-template-args -verify %s
-template<typename T> concept C = T::f();
-// expected-note@-1{{similar constraint}}
+template<typename T> concept C = T::f(); // #C
template<typename T> concept D = C<T> && T::g();
-template<typename T> concept F = T::f();
-// expected-note@-1{{similar constraint expressions not considered equivalent}}
-template<template<C> class P> struct S1 { }; // expected-note 2{{'P' declared here}}
+template<typename T> concept F = T::f(); // #F
+template<template<C> class P> struct S1 { }; // #S1
template<C> struct X { };
-
-template<D> struct Y { }; // expected-note{{'Y' declared here}}
+template<D> struct Y { }; // #Y
template<typename T> struct Z { };
-template<F> struct W { }; // expected-note{{'W' declared here}}
+template<F> struct W { }; // #W
S1<X> s11;
-S1<Y> s12; // expected-error{{template template argument 'Y' is more constrained than template template parameter 'P'}}
+S1<Y> s12;
+// expected-error@-1 {{template template argument 'Y' is more constrained than template template parameter 'P'}}
+// expected-note@#S1 {{'P' declared here}}
+// expected-note@#Y {{'Y' declared here}}
S1<Z> s13;
-S1<W> s14; // expected-error{{template template argument 'W' is more constrained than template template parameter 'P'}}
+S1<W> s14;
+// expected-error@-1 {{template template argument 'W' is more constrained than template template parameter 'P'}}
+// expected-note@#S1 {{'P' declared here}}
+// expected-note@#W {{'W' declared here}}
+// expected-note@#F {{similar constraint expressions not considered equivalent}}
+// expected-note@#C {{similar constraint}}
template<template<typename> class P> struct S2 { };
@@ -32,3 +37,27 @@
using s31 = S3<N>;
using s32 = S3<Z>;
+
+template<template<typename T> requires C<T> class P> struct S4 { }; // #S4
+
+S4<X> s41;
+S4<Y> s42;
+// expected-error@-1 {{template template argument 'Y' is more constrained than template template parameter 'P'}}
+// expected-note@#S4 {{'P' declared here}}
+// expected-note@#Y {{'Y' declared here}}
+S4<Z> s43;
+S4<W> s44;
+// expected-error@-1 {{template template argument 'W' is more constrained than template template parameter 'P'}}
+// expected-note@#S4 {{'P' declared here}}
+// expected-note@#W {{'W' declared here}}
+// expected-note@#F {{similar constraint expressions not considered equivalent}}
+// expected-note@#C {{similar constraint}}
+
+template<template<typename T> requires C<T> typename U> struct S5 {
+ template<typename T> static U<T> V;
+};
+
+struct Nothing {};
+
+// FIXME: Wait the standard to clarify the intent.
+template<> template<> Z<Nothing> S5<Z>::V<Nothing>;
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -874,27 +874,39 @@
/// template parameters.
///
/// type-parameter: [C++ temp.param]
-/// 'template' '<' template-parameter-list '>' type-parameter-key
-/// ...[opt] identifier[opt]
-/// 'template' '<' template-parameter-list '>' type-parameter-key
-/// identifier[opt] = id-expression
+/// template-head type-parameter-key ...[opt] identifier[opt]
+/// template-head type-parameter-key identifier[opt] = id-expression
/// type-parameter-key:
/// 'class'
/// 'typename' [C++1z]
-NamedDecl *
-Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
+/// template-head: [C++2a]
+/// 'template' '<' template-parameter-list '>'
+/// requires-clause[opt]
+NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
+ unsigned Position) {
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
// Handle the template <...> part.
SourceLocation TemplateLoc = ConsumeToken();
SmallVector<NamedDecl*,8> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
+ ExprResult OptionalRequiresClauseConstraintER;
{
MultiParseScope TemplateParmScope(*this);
if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
LAngleLoc, RAngleLoc)) {
return nullptr;
}
+ if (TryConsumeToken(tok::kw_requires)) {
+ OptionalRequiresClauseConstraintER =
+ Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression(
+ /*IsTrailingRequiresClause=*/false));
+ if (!OptionalRequiresClauseConstraintER.isUsable()) {
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
+ return nullptr;
+ }
+ }
}
// Provide an ExtWarn if the C++1z feature of using 'typename' here is used.
@@ -956,11 +968,9 @@
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true);
- TemplateParameterList *ParamList =
- Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
- TemplateLoc, LAngleLoc,
- TemplateParams,
- RAngleLoc, nullptr);
+ TemplateParameterList *ParamList = Actions.ActOnTemplateParameterList(
+ Depth, SourceLocation(), TemplateLoc, LAngleLoc, TemplateParams,
+ RAngleLoc, OptionalRequiresClauseConstraintER.get());
// Grab a default argument (if available).
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits