hamzasood created this revision.
This patch provides an implementation for P0428R2 <http://wg21.link/p0428r2>.
https://reviews.llvm.org/D36527
Files:
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaType.cpp
test/Parser/cxx2a-template-lambdas.cpp
test/SemaCXX/cxx2a-template-lambdas.cpp
www/cxx_status.html
Index: www/cxx_status.html
===================================================================
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -777,13 +777,12 @@
<h2 id="cxx20">C++2a implementation status</h2>
-<p>Clang does not yet support any of the proposed features of
-<!--<p>Clang has <b>experimental</b> support for some proposed features of-->
+<p>Clang has <b>experimental</b> support for some proposed features of
the C++ standard following C++17, provisionally named C++2a.
Note that support for these features may change or be removed without notice,
as the draft C++2a standard evolves.
-<!--<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>-->
+<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>
<details open>
<summary>List of features and minimum Clang version with support</summary>
@@ -823,7 +822,7 @@
<tr>
<td><i>template-parameter-list</i> for generic lambdas</td>
<td><a href="http://wg21.link/p0428r2">P0428R2</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Initializer list constructors in class template argument deduction</td>
Index: test/SemaCXX/cxx2a-template-lambdas.cpp
===================================================================
--- test/SemaCXX/cxx2a-template-lambdas.cpp
+++ test/SemaCXX/cxx2a-template-lambdas.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+template<typename, typename>
+constexpr bool is_same = false;
+
+template<typename T>
+constexpr bool is_same<T, T> = true;
+
+template<typename T>
+struct DummyTemplate { };
+
+void func() {
+ auto L0 = []<typename T>(T arg) {
+ static_assert(is_same<T, int>);
+ };
+ L0(0);
+
+ auto L1 = []<int I> {
+ static_assert(I == 5);
+ };
+ L1.operator()<5>();
+
+ auto L2 = []<template<typename> class T, class U>(T<U> &&arg) {
+ static_assert(is_same<T<U>, DummyTemplate<float>>);
+ };
+ L2(DummyTemplate<float>());
+}
+
+template<typename T> // expected-note {{declared here}}
+struct ShadowMe {
+ void member_func() {
+ auto L = []<typename T> { }; // expected-error {{'T' shadows template parameter}}
+ }
+};
Index: test/Parser/cxx2a-template-lambdas.cpp
===================================================================
--- test/Parser/cxx2a-template-lambdas.cpp
+++ test/Parser/cxx2a-template-lambdas.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+auto L0 = []<> { }; //expected-error {{expected template parameter list}}
+
+auto L1 = []<typename T1, typename T2> { };
+auto L2 = []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { };
+auto L3 = []<typename T>(auto arg) { T t; };
+auto L4 = []<int I>() { };
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -2789,8 +2789,8 @@
// template parameter type.
sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
assert(LSI && "No LambdaScopeInfo on the stack!");
- const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+ const unsigned TemplateParameterDepth = LSI->TemplateParameterDepth;
+ const unsigned AutoParameterPosition = LSI->TemplateParams.size();
const bool IsParameterPack = D.hasEllipsis();
// Create the TemplateTypeParmDecl here to retrieve the corresponding
@@ -2802,7 +2802,7 @@
/*KeyLoc*/SourceLocation(), /*NameLoc*/D.getLocStart(),
TemplateParameterDepth, AutoParameterPosition,
/*Identifier*/nullptr, false, IsParameterPack);
- LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ LSI->TemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
// template type parameter.
// FIXME: Retain some type sugar to indicate that this was written
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -229,15 +229,17 @@
if (LSI->GLTemplateParameterList)
return LSI->GLTemplateParameterList;
- if (!LSI->AutoTemplateParams.empty()) {
- SourceRange IntroRange = LSI->IntroducerRange;
- SourceLocation LAngleLoc = IntroRange.getBegin();
- SourceLocation RAngleLoc = IntroRange.getEnd();
+ if (!LSI->TemplateParams.empty()) {
+ SourceRange ListRange = LSI->ExplicitTemplateParamsRange.isValid()
+ ? LSI->ExplicitTemplateParamsRange
+ : LSI->IntroducerRange;
+ SourceLocation LAngleLoc = ListRange.getBegin();
+ SourceLocation RAngleLoc = ListRange.getEnd();
LSI->GLTemplateParameterList = TemplateParameterList::Create(
SemaRef.Context,
/*Template kw loc*/ SourceLocation(), LAngleLoc,
- llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
- LSI->AutoTemplateParams.size()),
+ llvm::makeArrayRef((NamedDecl *const *)LSI->TemplateParams.data(),
+ LSI->TemplateParams.size()),
RAngleLoc, nullptr);
}
return LSI->GLTemplateParameterList;
@@ -479,6 +481,44 @@
LSI->finishedExplicitCaptures();
}
+TemplateParameterList *
+Sema::ActOnLambdaTemplateParameterList(unsigned Depth,
+ SourceLocation LAngleLoc,
+ ArrayRef<Decl *> TParams,
+ SourceLocation RAngleLoc) {
+ LambdaScopeInfo *LSI = getCurLambda();
+ assert(LSI && "Expected a lambda scope");
+
+ assert(LSI->NumExplicitTemplateParams == 0
+ && "Already acted on explicit template parameters");
+ assert(LSI->TemplateParams.size() == 0
+ && "Explicit template parameters should come before invented ones");
+
+ TemplateParameterList *ret = ActOnTemplateParameterList(
+ Depth,
+ /*ExportLoc=*/SourceLocation(), /*TemplateLoc=*/SourceLocation(),
+ LAngleLoc, TParams, RAngleLoc,
+ /*RequiresClause=*/nullptr);
+
+ LSI->TemplateParams.append(TParams.begin(), TParams.end());
+ LSI->NumExplicitTemplateParams = TParams.size();
+ LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
+
+ return ret;
+}
+
+void Sema::addLambdaExplicitTemplateParameters(ArrayRef<Decl*> TParams,
+ Scope *CurScope) {
+ for (Decl *T : TParams) {
+ NamedDecl *NT = dyn_cast<NamedDecl>(T);
+ assert(NT && "Template parameter should be convertable to NamedDecl");
+
+ // If this has an identifier, add it to the scope stack.
+ if (CurScope && NT->getIdentifier())
+ PushOnScopeChains(NT, CurScope);
+ }
+}
+
void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = CallOperator->getNumParams();
@@ -1123,6 +1163,10 @@
LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+ // Add explicit template parameters into scope.
+ addLambdaExplicitTemplateParameters(LSI->getExplicitTemplateParams(),
+ CurScope);
+
// Add lambda parameters into scope.
addLambdaParameters(Method, CurScope);
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -1292,7 +1292,7 @@
void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
if (LambdaScopeInfo *const LSI = getCurLambda()) {
- LSI->AutoTemplateParameterDepth = Depth;
+ LSI->TemplateParameterDepth = Depth;
return;
}
llvm_unreachable(
@@ -1376,7 +1376,7 @@
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
if (LambdaScopeInfo *LSI = getCurLambda()) {
- return (LSI->AutoTemplateParams.size() ||
+ return (LSI->TemplateParams.size() ||
LSI->GLTemplateParameterList) ? LSI : nullptr;
}
return nullptr;
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -635,6 +635,8 @@
///
/// lambda-expression:
/// lambda-introducer lambda-declarator[opt] compound-statement
+/// lambda-introducer <template-parameter-list> lambda-declarator[opt]
+/// compound-statement
///
/// lambda-introducer:
/// '[' lambda-capture[opt] ']'
@@ -1082,9 +1084,11 @@
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
Declarator D(DS, Declarator::LambdaExprContext);
- TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
Actions.PushLambdaScope();
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+ Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+
ParsedAttributes Attr(AttrFactory);
SourceLocation DeclLoc = Tok.getLocation();
if (getLangOpts().CUDA) {
@@ -1105,6 +1109,26 @@
<< A->getName()->getName();
};
+ ParseScope TemplateParamScope(this, Scope::TemplateParamScope);
+ if (getLangOpts().CPlusPlus2a && Tok.is(tok::less)) {
+ SmallVector<Decl*, 4> TemplateParams;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+ TemplateParams, LAngleLoc, RAngleLoc)) {
+ return ExprError();
+ }
+
+ if (TemplateParams.empty()) {
+ Diag(RAngleLoc,
+ diag::err_expected_lambda_template_parameter_list);
+ }
+ else {
+ Actions.ActOnLambdaTemplateParameterList(
+ CurTemplateDepthTracker.getDepth(),
+ LAngleLoc, TemplateParams, RAngleLoc);
+ }
+ }
+
TypeResult TrailingReturnType;
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@@ -1120,14 +1144,9 @@
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
- if (Tok.isNot(tok::r_paren)) {
- Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+ if (Tok.isNot(tok::r_paren))
ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
- // For a generic lambda, each 'auto' within the parameter declaration
- // clause creates a template type parameter, so increment the depth.
- if (Actions.getCurGenericLambda())
- ++CurTemplateDepthTracker;
- }
+
T.consumeClose();
SourceLocation RParenLoc = T.getCloseLocation();
SourceLocation DeclEndLoc = RParenLoc;
@@ -1278,6 +1297,12 @@
TrailingReturnType),
Attr, DeclEndLoc);
}
+ TemplateParamScope.Exit();
+
+ // getCurGenericLambda is used to see if we've added any template parameters.
+ // If so, the template depth needs to be increased.
+ if (Actions.getCurGenericLambda())
+ ++CurTemplateDepthTracker;
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
// it.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5463,6 +5463,18 @@
/// given lambda.
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
+ /// ActOnLambdaTemplateParameterList - This is called after parsing
+ /// the explicit template parameter list (if it exists) in C++2a.
+ TemplateParameterList *
+ ActOnLambdaTemplateParameterList(unsigned Depth,
+ SourceLocation LAngleLoc,
+ ArrayRef<Decl *> TParams,
+ SourceLocation RAngleLoc);
+
+ /// \brief Introduce the explicit lambda template parameters into scope.
+ void addLambdaExplicitTemplateParameters(ArrayRef<Decl*> TParams,
+ Scope *CurScope);
+
/// \brief Introduce the lambda parameters into scope.
void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -767,18 +767,27 @@
bool ContainsUnexpandedParameterPack;
/// \brief If this is a generic lambda, use this as the depth of
- /// each 'auto' parameter, during initial AST construction.
- unsigned AutoTemplateParameterDepth;
+ /// each template parameter, during initial AST construction.
+ unsigned TemplateParameterDepth;
- /// \brief Store the list of the auto parameters for a generic lambda.
- /// If this is a generic lambda, store the list of the auto
- /// parameters converted into TemplateTypeParmDecls into a vector
- /// that can be used to construct the generic lambda's template
+ /// \brief The number of parameters in the template parameter list that were
+ /// explicitely specified by the user, as opposed to being invented by use
+ /// of an auto parameter.
+ unsigned NumExplicitTemplateParams;
+
+ /// \brief Source range covering the explicit template parameter list
+ /// (if it exists).
+ SourceRange ExplicitTemplateParamsRange;
+
+ /// \brief Store the list of the template parameters for a generic lambda.
+ /// If this is a generic lambda, this holds the explicit template parameters
+ /// followed by the auto parameters converted into TemplateTypeParmDecls.
+ /// It can be used to construct the generic lambda's template
/// parameter list, during initial AST construction.
- SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
+ SmallVector<Decl*, 4> TemplateParams;
/// If this is a generic lambda, and the template parameter
- /// list has been created (from the AutoTemplateParams) then
+ /// list has been created (from the TemplateParams) then
/// store a reference to it (cache it to avoid reconstructing it).
TemplateParameterList *GLTemplateParameterList;
@@ -819,8 +828,8 @@
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr),
CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false),
ExplicitParams(false), Cleanup{},
- ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0),
- GLTemplateParameterList(nullptr) {
+ ContainsUnexpandedParameterPack(false), TemplateParameterDepth(0),
+ NumExplicitTemplateParams(0), GLTemplateParameterList(nullptr) {
Kind = SK_Lambda;
}
@@ -932,6 +941,12 @@
PotentialThisCaptureLocation.isValid();
}
+ llvm::ArrayRef<Decl*> getExplicitTemplateParams() const {
+ // Explicit template parameters should always be first in the list.
+ return llvm::makeArrayRef(TemplateParams)
+ .slice(0, NumExplicitTemplateParams);
+ }
+
// When passed the index, returns the VarDecl and Expr associated
// with the index.
void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -822,6 +822,10 @@
def ext_constexpr_on_lambda_cxx1z : ExtWarn<
"'constexpr' on lambda expressions is a C++1z extension">, InGroup<CXX1z>;
+// C++2a template lambdas
+def err_expected_lambda_template_parameter_list : Error<
+ "expected template parameter list">;
+
// Availability attribute
def err_expected_version : Error<
"expected a version of the form 'major[.minor[.subminor]]'">;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits