summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorHamza Sood <hamza_sood@me.com>2019-05-04 10:49:46 +0000
committerHamza Sood <hamza_sood@me.com>2019-05-04 10:49:46 +0000
commit8205a814a691bfa62fed911b58b0a306ab5efe31 (patch)
treecbd4d43e2edb58be4b532986547b842cf2be207c /clang/lib
parent9c32fa1b1f60ea95e627a485b7a8e766ba3e622c (diff)
downloadbcm5719-llvm-8205a814a691bfa62fed911b58b0a306ab5efe31.tar.gz
bcm5719-llvm-8205a814a691bfa62fed911b58b0a306ab5efe31.zip
[c++20] Implement P0428R2 - Familiar template syntax for generic lambdas
Differential Revision: https://reviews.llvm.org/D36527 llvm-svn: 359967
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/DeclCXX.cpp19
-rw-r--r--clang/lib/AST/DeclPrinter.cpp46
-rw-r--r--clang/lib/AST/ExprCXX.cpp4
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp24
-rw-r--r--clang/lib/AST/StmtPrinter.cpp11
-rw-r--r--clang/lib/AST/TypePrinter.cpp14
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp41
-rw-r--r--clang/lib/Sema/Sema.cpp2
-rw-r--r--clang/lib/Sema/SemaLambda.cpp57
-rw-r--r--clang/lib/Sema/SemaType.cpp5
10 files changed, 182 insertions, 41 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 9946d16a858..b9ecdc65720 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1421,13 +1421,30 @@ void CXXRecordDecl::getCaptureFields(
TemplateParameterList *
CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
- if (!isLambda()) return nullptr;
+ if (!isGenericLambda()) return nullptr;
CXXMethodDecl *CallOp = getLambdaCallOperator();
if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
return Tmpl->getTemplateParameters();
return nullptr;
}
+ArrayRef<NamedDecl *>
+CXXRecordDecl::getLambdaExplicitTemplateParameters() const {
+ TemplateParameterList *List = getGenericLambdaTemplateParameterList();
+ if (!List)
+ return {};
+
+ assert(std::is_partitioned(List->begin(), List->end(),
+ [](const NamedDecl *D) { return !D->isImplicit(); })
+ && "Explicit template params should be ordered before implicit ones");
+
+ const auto ExplicitEnd = std::lower_bound(List->begin(), List->end(), false,
+ [](const NamedDecl *D, bool) {
+ return !D->isImplicit();
+ });
+ return llvm::makeArrayRef(List->begin(), ExplicitEnd);
+}
+
Decl *CXXRecordDecl::getLambdaContextDecl() const {
assert(isLambda() && "Not a lambda closure type!");
ExternalASTSource *Source = getParentASTContext().getExternalSource();
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 36c5d10f718..78a7afdbf09 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -105,7 +106,8 @@ namespace {
void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
- void printTemplateParameters(const TemplateParameterList *Params);
+ void printTemplateParameters(const TemplateParameterList *Params,
+ bool OmitTemplateKW = false);
void printTemplateArguments(const TemplateArgumentList &Args,
const TemplateParameterList *Params = nullptr);
void prettyPrintAttributes(Decl *D);
@@ -126,6 +128,18 @@ void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
Printer.Visit(const_cast<Decl*>(this));
}
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+ bool OmitTemplateKW) const {
+ print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW);
+}
+
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+ const PrintingPolicy &Policy,
+ bool OmitTemplateKW) const {
+ DeclPrinter Printer(Out, Policy, Context);
+ Printer.printTemplateParameters(this, OmitTemplateKW);
+}
+
static QualType GetBaseType(QualType T) {
// FIXME: This should be on the Type class!
QualType BaseType = T;
@@ -1002,25 +1016,35 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) {
+void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
+ bool OmitTemplateKW) {
assert(Params);
- Out << "template <";
+ if (!OmitTemplateKW)
+ Out << "template ";
+ Out << '<';
- for (unsigned i = 0, e = Params->size(); i != e; ++i) {
- if (i != 0)
+ bool NeedComma = false;
+ for (const Decl *Param : *Params) {
+ if (Param->isImplicit())
+ continue;
+
+ if (NeedComma)
Out << ", ";
+ else
+ NeedComma = true;
- const Decl *Param = Params->getParam(i);
if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (TTP->wasDeclaredWithTypename())
- Out << "typename ";
+ Out << "typename";
else
- Out << "class ";
+ Out << "class";
if (TTP->isParameterPack())
- Out << "...";
+ Out << " ...";
+ else if (!TTP->getName().empty())
+ Out << ' ';
Out << *TTP;
@@ -1045,7 +1069,9 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) {
}
}
- Out << "> ";
+ Out << '>';
+ if (!OmitTemplateKW)
+ Out << ' ';
}
void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args,
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 5f9d0e7623d..b1ce1674014 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1204,7 +1204,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
CXXRecordDecl *Record = getLambdaClass();
return Record->getGenericLambdaTemplateParameterList();
+}
+ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const {
+ const CXXRecordDecl *Record = getLambdaClass();
+ return Record->getLambdaExplicitTemplateParameters();
}
CompoundStmt *LambdaExpr::getBody() const {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 3357756466f..1eb5460dd61 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -486,6 +486,7 @@ private:
const AbiTagList *AdditionalAbiTags);
void mangleBlockForPrefix(const BlockDecl *Block);
void mangleUnqualifiedBlock(const BlockDecl *Block);
+ void mangleTemplateParamDecl(const NamedDecl *Decl);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
const AbiTagList *AdditionalAbiTags,
@@ -1372,7 +1373,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// <unnamed-type-name> ::= <closure-type-name>
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
- // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
+ // <lambda-sig> ::= <template-param-decl>* <parameter-type>+
+ // # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda() && Record->getLambdaManglingNumber()) {
assert(!AdditionalAbiTags &&
@@ -1678,6 +1680,24 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
Out << '_';
}
+// <template-param-decl>
+// ::= Ty # template type parameter
+// ::= Tn <type> # template non-type parameter
+// ::= Tt <template-param-decl>* E # template template parameter
+void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
+ if (isa<TemplateTypeParmDecl>(Decl)) {
+ Out << "Ty";
+ } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
+ Out << "Tn";
+ mangleType(Tn->getType());
+ } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
+ Out << "Tt";
+ for (auto *Param : *Tt->getTemplateParameters())
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
+}
+
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// If the context of a closure type is an initializer for a class member
// (static or nonstatic), it is encoded in a qualified name with a final
@@ -1705,6 +1725,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}
Out << "Ul";
+ for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
+ mangleTemplateParamDecl(D);
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
getAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index acf19aaaf41..71270220382 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1900,8 +1900,14 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
}
OS << ']';
+ if (!Node->getExplicitTemplateParameters().empty()) {
+ Node->getTemplateParameterList()->print(
+ OS, Node->getLambdaClass()->getASTContext(),
+ /*OmitTemplateKW*/true);
+ }
+
if (Node->hasExplicitParameters()) {
- OS << " (";
+ OS << '(';
CXXMethodDecl *Method = Node->getCallOperator();
NeedComma = false;
for (const auto *P : Method->parameters()) {
@@ -1936,9 +1942,8 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
}
// Print the body.
- CompoundStmt *Body = Node->getBody();
OS << ' ';
- PrintStmt(Body);
+ PrintRawCompoundStmt(Node->getBody());
}
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 82a2fa09c76..85045324974 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1217,8 +1217,18 @@ void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
raw_ostream &OS) {
if (IdentifierInfo *Id = T->getIdentifier())
OS << Id->getName();
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+ else {
+ bool IsLambdaAutoParam = false;
+ if (auto D = T->getDecl()) {
+ if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
+ IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+ }
+
+ if (IsLambdaAutoParam)
+ OS << "auto";
+ else
+ OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+ }
spaceBeforePlaceHolder(OS);
}
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index c3094d69923..87a6b4df8f8 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -638,6 +638,8 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
///
/// lambda-expression:
/// lambda-introducer lambda-declarator[opt] compound-statement
+/// lambda-introducer '<' template-parameter-list '>'
+/// lambda-declarator[opt] compound-statement
///
/// lambda-introducer:
/// '[' lambda-capture[opt] ']'
@@ -1121,6 +1123,33 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
<< A.getName()->getName();
};
+ // FIXME: Consider allowing this as an extension for GCC compatibiblity.
+ const bool HasExplicitTemplateParams = Tok.is(tok::less);
+ ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
+ /*EnteredScope=*/HasExplicitTemplateParams);
+ if (HasExplicitTemplateParams) {
+ Diag(Tok, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_lambda_template_parameter_list
+ : diag::ext_lambda_template_parameter_list);
+
+ SmallVector<NamedDecl*, 4> TemplateParams;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+ TemplateParams, LAngleLoc, RAngleLoc)) {
+ Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
+ return ExprError();
+ }
+
+ if (TemplateParams.empty()) {
+ Diag(RAngleLoc,
+ diag::err_lambda_template_parameter_list_empty);
+ } else {
+ Actions.ActOnLambdaExplicitTemplateParameterList(
+ LAngleLoc, TemplateParams, RAngleLoc);
+ ++CurTemplateDepthTracker;
+ }
+ }
+
TypeResult TrailingReturnType;
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@@ -1137,13 +1166,20 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SourceLocation EllipsisLoc;
if (Tok.isNot(tok::r_paren)) {
- Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+ Actions.RecordParsingTemplateParameterDepth(
+ CurTemplateDepthTracker.getOriginalDepth());
+
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 we've parsed any explicit template parameters, then the depth will
+ // have already been incremented. So we make sure that at most a single
+ // depth level is added.
if (Actions.getCurGenericLambda())
- ++CurTemplateDepthTracker;
+ CurTemplateDepthTracker.setAddedDepth(1);
}
+
T.consumeClose();
SourceLocation RParenLoc = T.getCloseLocation();
SourceLocation DeclEndLoc = RParenLoc;
@@ -1298,6 +1334,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
+ TemplateParamScope.Exit();
if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 0eb967a641b..8984398eae4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1793,7 +1793,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
// 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;
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 7ad39fd73ba..1966e9e0803 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace sema;
@@ -225,19 +226,14 @@ Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
static inline TemplateParameterList *
getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
- if (LSI->GLTemplateParameterList)
- return LSI->GLTemplateParameterList;
-
- if (!LSI->AutoTemplateParams.empty()) {
- SourceRange IntroRange = LSI->IntroducerRange;
- SourceLocation LAngleLoc = IntroRange.getBegin();
- SourceLocation RAngleLoc = IntroRange.getEnd();
+ if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) {
LSI->GLTemplateParameterList = TemplateParameterList::Create(
SemaRef.Context,
- /*Template kw loc*/ SourceLocation(), LAngleLoc,
- llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
- LSI->AutoTemplateParams.size()),
- RAngleLoc, nullptr);
+ /*Template kw loc*/ SourceLocation(),
+ /*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(),
+ LSI->TemplateParams,
+ /*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(),
+ nullptr);
}
return LSI->GLTemplateParameterList;
}
@@ -492,6 +488,23 @@ void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
LSI->finishedExplicitCaptures();
}
+void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+ ArrayRef<NamedDecl *> 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.empty() &&
+ "Explicit template parameters should come "
+ "before invented (auto) ones");
+ assert(!TParams.empty() &&
+ "No template parameters to act on");
+ LSI->TemplateParams.append(TParams.begin(), TParams.end());
+ LSI->NumExplicitTemplateParams = TParams.size();
+ LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
+}
+
void Sema::addLambdaParameters(
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
CXXMethodDecl *CallOperator, Scope *CurScope) {
@@ -832,17 +845,23 @@ FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
- // Determine if we're within a context where we know that the lambda will
- // be dependent, because there are template parameters in scope.
- bool KnownDependent = false;
LambdaScopeInfo *const LSI = getCurLambda();
assert(LSI && "LambdaScopeInfo should be on stack!");
- // The lambda-expression's closure type might be dependent even if its
- // semantic context isn't, if it appears within a default argument of a
- // function template.
- if (CurScope->getTemplateParamParent())
- KnownDependent = true;
+ // Determine if we're within a context where we know that the lambda will
+ // be dependent, because there are template parameters in scope.
+ bool KnownDependent;
+ if (LSI->NumExplicitTemplateParams > 0) {
+ auto *TemplateParamScope = CurScope->getTemplateParamParent();
+ assert(TemplateParamScope &&
+ "Lambda with explicit template param list should establish a "
+ "template param scope");
+ assert(TemplateParamScope->getParent());
+ KnownDependent = TemplateParamScope->getParent()
+ ->getTemplateParamParent() != nullptr;
+ } else {
+ KnownDependent = CurScope->getTemplateParamParent() != nullptr;
+ }
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3b25595a33a..318c6761731 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2935,7 +2935,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 AutoParameterPosition = LSI->TemplateParams.size();
const bool IsParameterPack = D.hasEllipsis();
// Create the TemplateTypeParmDecl here to retrieve the corresponding
@@ -2947,7 +2947,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
/*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
TemplateParameterDepth, AutoParameterPosition,
/*Identifier*/ nullptr, false, IsParameterPack);
- LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ CorrespondingTemplateParam->setImplicit();
+ 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
OpenPOWER on IntegriCloud