forked from OSchip/llvm-project
[c++20] Implement P0428R2 - Familiar template syntax for generic lambdas
Differential Revision: https://reviews.llvm.org/D36527 llvm-svn: 359967
This commit is contained in:
parent
9c32fa1b1f
commit
8205a814a6
|
@ -1221,6 +1221,9 @@ public:
|
|||
/// lambda.
|
||||
TemplateParameterList *getGenericLambdaTemplateParameterList() const;
|
||||
|
||||
/// Retrieve the lambda template parameters that were specified explicitly.
|
||||
ArrayRef<NamedDecl *> getLambdaExplicitTemplateParameters() const;
|
||||
|
||||
LambdaCaptureDefault getLambdaCaptureDefault() const {
|
||||
assert(isLambda());
|
||||
return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault);
|
||||
|
|
|
@ -176,6 +176,11 @@ public:
|
|||
return SourceRange(TemplateLoc, RAngleLoc);
|
||||
}
|
||||
|
||||
void print(raw_ostream &Out, const ASTContext &Context,
|
||||
bool OmitTemplateKW = false) const;
|
||||
void print(raw_ostream &Out, const ASTContext &Context,
|
||||
const PrintingPolicy &Policy, bool OmitTemplateKW = false) const;
|
||||
|
||||
public:
|
||||
// FIXME: workaround for MSVC 2013; remove when no longer needed
|
||||
using FixedSizeStorageOwner = TrailingObjects::FixedSizeStorageOwner;
|
||||
|
|
|
@ -1899,6 +1899,10 @@ public:
|
|||
/// parameter list associated with it, or else return null.
|
||||
TemplateParameterList *getTemplateParameterList() const;
|
||||
|
||||
/// Get the template parameters were explicitly specified (as opposed to being
|
||||
/// invented by use of an auto parameter).
|
||||
ArrayRef<NamedDecl *> getExplicitTemplateParameters() const;
|
||||
|
||||
/// Whether this is a generic lambda.
|
||||
bool isGenericLambda() const { return getTemplateParameterList(); }
|
||||
|
||||
|
|
|
@ -2423,6 +2423,10 @@ DEF_TRAVERSE_STMT(LambdaExpr, {
|
|||
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
||||
FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
|
||||
|
||||
for (Decl *D : S->getExplicitTemplateParameters()) {
|
||||
// Visit explicit template parameters.
|
||||
TRY_TO(TraverseDecl(D));
|
||||
}
|
||||
if (S->hasExplicitParameters()) {
|
||||
// Visit parameters.
|
||||
for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I)
|
||||
|
|
|
@ -886,6 +886,16 @@ def warn_cxx14_compat_constexpr_on_lambda : Warning<
|
|||
def ext_constexpr_on_lambda_cxx17 : ExtWarn<
|
||||
"'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
|
||||
|
||||
// C++2a template lambdas
|
||||
def ext_lambda_template_parameter_list: ExtWarn<
|
||||
"explicit template parameter list for lambdas is a C++2a extension">,
|
||||
InGroup<CXX2a>;
|
||||
def warn_cxx17_compat_lambda_template_parameter_list: Warning<
|
||||
"explicit template parameter list for lambdas is incompatible with "
|
||||
"C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
|
||||
def err_lambda_template_parameter_list_empty : Error<
|
||||
"lambda template parameter list cannot be empty">;
|
||||
|
||||
// Availability attribute
|
||||
def err_expected_version : Error<
|
||||
"expected a version of the form 'major[.minor[.subminor]]'">;
|
||||
|
|
|
@ -250,7 +250,13 @@ class Parser : public CodeCompletionHandler {
|
|||
Depth += D;
|
||||
AddedLevels += D;
|
||||
}
|
||||
void setAddedDepth(unsigned D) {
|
||||
Depth = Depth - AddedLevels + D;
|
||||
AddedLevels = D;
|
||||
}
|
||||
|
||||
unsigned getDepth() const { return Depth; }
|
||||
unsigned getOriginalDepth() const { return Depth - AddedLevels; }
|
||||
};
|
||||
|
||||
/// Factory object for creating ParsedAttr objects.
|
||||
|
|
|
@ -816,16 +816,24 @@ public:
|
|||
/// each 'auto' parameter, during initial AST construction.
|
||||
unsigned AutoTemplateParameterDepth = 0;
|
||||
|
||||
/// 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
|
||||
/// parameter list, during initial AST construction.
|
||||
SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
|
||||
/// The number of parameters in the template parameter list that were
|
||||
/// explicitly specified by the user, as opposed to being invented by use
|
||||
/// of an auto parameter.
|
||||
unsigned NumExplicitTemplateParams = 0;
|
||||
|
||||
/// Source range covering the explicit template parameter list (if it exists).
|
||||
SourceRange ExplicitTemplateParamsRange;
|
||||
|
||||
/// 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<NamedDecl*, 4> TemplateParams;
|
||||
|
||||
/// If this is a generic lambda, and the template parameter
|
||||
/// list has been created (from the AutoTemplateParams) then
|
||||
/// store a reference to it (cache it to avoid reconstructing it).
|
||||
/// list has been created (from the TemplateParams) then store
|
||||
/// a reference to it (cache it to avoid reconstructing it).
|
||||
TemplateParameterList *GLTemplateParameterList = nullptr;
|
||||
|
||||
/// Contains all variable-referring-expressions (i.e. DeclRefExprs
|
||||
|
@ -878,9 +886,9 @@ public:
|
|||
}
|
||||
|
||||
/// Is this scope known to be for a generic lambda? (This will be false until
|
||||
/// we parse the first 'auto'-typed parameter.
|
||||
/// we parse a template parameter list or the first 'auto'-typed parameter).
|
||||
bool isGenericLambda() const {
|
||||
return !AutoTemplateParams.empty() || GLTemplateParameterList;
|
||||
return !TemplateParams.empty() || GLTemplateParameterList;
|
||||
}
|
||||
|
||||
/// Add a variable that might potentially be captured by the
|
||||
|
|
|
@ -5723,6 +5723,12 @@ public:
|
|||
/// given lambda.
|
||||
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
|
||||
|
||||
/// \brief This is called after parsing the explicit template parameter list
|
||||
/// on a lambda (if it exists) in C++2a.
|
||||
void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
|
||||
ArrayRef<NamedDecl *> TParams,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
/// Introduce the lambda parameters into scope.
|
||||
void addLambdaParameters(
|
||||
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -213,8 +213,10 @@ namespace PackExpansionWithinLambda {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
// - in a template parameter pack that is a pack expansion
|
||||
// FIXME: We do not support any way to reach this case yet.
|
||||
swallow([]<T *...v, template<T *> typename ...W>(W<v> ...wv) { });
|
||||
#endif
|
||||
|
||||
// - in an initializer-list
|
||||
int arr[] = {T().x...};
|
||||
|
@ -279,11 +281,6 @@ namespace PackExpansionWithinLambda {
|
|||
struct T { int x; using U = int; };
|
||||
void g() { f<T>(1, 2, 3); }
|
||||
|
||||
template<typename ...T, typename ...U> void pack_in_lambda(U ...u) { // expected-note {{here}}
|
||||
// FIXME: Move this test into 'f' above once we support this syntax.
|
||||
[]<T *...v, template<T *> typename ...U>(U<v> ...uv) {}; // expected-error {{expected body of lambda}} expected-error {{does not refer to a value}}
|
||||
}
|
||||
|
||||
template<typename ...T> void pack_expand_attr() {
|
||||
// FIXME: Move this test into 'f' above once we support this.
|
||||
[[gnu::aligned(alignof(T))...]] int x; // expected-error {{cannot be used as an attribute pack}} expected-error {{unexpanded}}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -triple %itanium_abi_triple -emit-llvm -o - %s -w | FileCheck %s
|
||||
|
||||
template<class, int, class>
|
||||
struct DummyType { };
|
||||
|
||||
inline void inline_func() {
|
||||
// CHECK: UlvE
|
||||
[]{}();
|
||||
|
||||
// CHECK: UlTyvE
|
||||
[]<class>{}.operator()<int>();
|
||||
|
||||
// CHECK: UlTyT_E
|
||||
[]<class T>(T){}(1);
|
||||
|
||||
// CHECK: UlTyTyT_T0_E
|
||||
[]<class T1, class T2>(T1, T2){}(1, 2);
|
||||
|
||||
// CHECK: UlTyTyT0_T_E
|
||||
[]<class T1, class T2>(T2, T1){}(2, 1);
|
||||
|
||||
// CHECK: UlTniTyTnjT0_E
|
||||
[]<int I, class T, unsigned U>(T){}.operator()<1, int, 2>(3);
|
||||
|
||||
// CHECK: UlTyTtTyTniTyETniTyvE
|
||||
[]<class,
|
||||
template<class, int, class> class,
|
||||
int,
|
||||
class>{}.operator()<unsigned, DummyType, 5, int>();
|
||||
}
|
||||
|
||||
void call_inline_func() {
|
||||
inline_func();
|
||||
}
|
|
@ -20,7 +20,7 @@ template<> void g<int>(ClassTmpl<int, int>);
|
|||
// DISPLAY_NAME: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl<int, int>):13:17 [Specialization of g:11:6]
|
||||
|
||||
// RUN: env CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT=1 c-index-test -test-load-source all-pretty %s | FileCheck %s --check-prefix=PRETTY
|
||||
// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename > class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20]
|
||||
// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename> class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20]
|
||||
// PRETTY: print-display-names.cpp:4:13: TypedefDecl=typedef int Integer:4:13 (Definition) Extent=[4:1 - 4:20]
|
||||
// PRETTY: print-display-names.cpp:6:16: ClassDecl=template<> class ClassTmpl<int, int> {}:6:16 (Definition) [Specialization of ClassTmpl:2:7] Extent=[6:1 - 6:43]
|
||||
// PRETTY: print-display-names.cpp:8:6: FunctionDecl=void f(ClassTmpl<float, Integer> p):8:6 Extent=[8:1 - 8:36]
|
||||
|
|
|
@ -54,7 +54,7 @@ int add(int x, int y) {
|
|||
}
|
||||
|
||||
// CHECK-PRINT: inline int add_int_slowly_twice
|
||||
// CHECK-PRINT: lambda = [&] (int z)
|
||||
// CHECK-PRINT: lambda = [&](int z)
|
||||
|
||||
// CHECK-PRINT: init_capture
|
||||
// CHECK-PRINT: [&, x(t)]
|
||||
|
|
|
@ -50,7 +50,7 @@ int add(int x, int y) {
|
|||
}
|
||||
|
||||
// CHECK-PRINT: inline int add_int_slowly_twice
|
||||
// CHECK-PRINT: lambda = [] (type-parameter-0-0 z
|
||||
// CHECK-PRINT: lambda = [](auto z
|
||||
|
||||
// CHECK-PRINT: init_capture
|
||||
// CHECK-PRINT: [&, x(t)]
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
|
||||
// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
auto l1 = []<int I>() constexpr -> int {
|
||||
return I;
|
||||
};
|
||||
|
||||
auto l2 = []<auto I>() constexpr -> decltype(I) {
|
||||
return I;
|
||||
};
|
||||
|
||||
auto l3 = []<class T>(auto i) constexpr -> T {
|
||||
return T(i);
|
||||
};
|
||||
|
||||
auto l4 = []<template<class> class T, class U>(T<U>, auto i) constexpr -> U {
|
||||
return U(i);
|
||||
};
|
||||
|
||||
#else /*included pch*/
|
||||
|
||||
static_assert(l1.operator()<5>() == 5);
|
||||
static_assert(l1.operator()<6>() == 6);
|
||||
|
||||
static_assert(l2.operator()<7>() == 7);
|
||||
static_assert(l2.operator()<nullptr>() == nullptr);
|
||||
|
||||
static_assert(l3.operator()<int>(8.4) == 8);
|
||||
static_assert(l3.operator()<int>(9.9) == 9);
|
||||
|
||||
template<typename T>
|
||||
struct DummyTemplate { };
|
||||
|
||||
static_assert(l4(DummyTemplate<float>(), 12) == 12.0);
|
||||
static_assert(l4(DummyTemplate<int>(), 19.8) == 19);
|
||||
|
||||
#endif // HEADER
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: %clang_cc1 -std=c++2a %s -verify
|
||||
|
||||
auto L0 = []<> { }; //expected-error {{cannot be empty}}
|
||||
|
||||
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>() { };
|
|
@ -0,0 +1,45 @@
|
|||
// 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>); // expected-error {{static_assert failed}}
|
||||
};
|
||||
L0(0);
|
||||
L0(0.0); // expected-note {{in instantiation}}
|
||||
|
||||
auto L1 = []<int I> {
|
||||
static_assert(I == 5); // expected-error {{static_assert failed}}
|
||||
};
|
||||
L1.operator()<5>();
|
||||
L1.operator()<6>(); // expected-note {{in instantiation}}
|
||||
|
||||
auto L2 = []<template<typename> class T, class U>(T<U> &&arg) {
|
||||
static_assert(is_same<T<U>, DummyTemplate<float>>); // // expected-error {{static_assert failed}}
|
||||
};
|
||||
L2(DummyTemplate<float>());
|
||||
L2(DummyTemplate<double>()); // expected-note {{in instantiation}}
|
||||
}
|
||||
|
||||
template<typename T> // expected-note {{declared here}}
|
||||
struct ShadowMe {
|
||||
void member_func() {
|
||||
auto L = []<typename T> { }; // expected-error {{'T' shadows template parameter}}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr T outer() {
|
||||
return []<T x>() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \
|
||||
expected-note {{candidate template ignored}}
|
||||
}
|
||||
static_assert(outer<int>() == 123);
|
||||
template int *outer<int *>(); // expected-note {{in instantiation}}
|
|
@ -157,6 +157,43 @@ TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
|
|||
// WRONG; Should be: (a & b).operator void *()
|
||||
}
|
||||
|
||||
TEST(StmtPrinter, TestCXXLamda) {
|
||||
ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
|
||||
"void A() {"
|
||||
" auto l = [] { };"
|
||||
"}",
|
||||
lambdaExpr(anything()).bind("id"),
|
||||
"[] {\n"
|
||||
"}"));
|
||||
|
||||
ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
|
||||
"void A() {"
|
||||
" int a = 0, b = 1;"
|
||||
" auto l = [a,b](int c, float d) { };"
|
||||
"}",
|
||||
lambdaExpr(anything()).bind("id"),
|
||||
"[a, b](int c, float d) {\n"
|
||||
"}"));
|
||||
|
||||
ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14,
|
||||
"void A() {"
|
||||
" auto l = [](auto a, int b, auto c, int, auto) { };"
|
||||
"}",
|
||||
lambdaExpr(anything()).bind("id"),
|
||||
"[](auto a, int b, auto c, int, auto) {\n"
|
||||
"}"));
|
||||
|
||||
ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX2a,
|
||||
"void A() {"
|
||||
" auto l = []<typename T1, class T2, int I,"
|
||||
" template<class, typename> class T3>"
|
||||
" (int a, auto, int, auto d) { };"
|
||||
"}",
|
||||
lambdaExpr(anything()).bind("id"),
|
||||
"[]<typename T1, class T2, int I, template <class, typename> class T3>(int a, auto, int, auto d) {\n"
|
||||
"}"));
|
||||
}
|
||||
|
||||
TEST(StmtPrinter, TestNoImplicitBases) {
|
||||
const char *CPPSource = R"(
|
||||
class A {
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TestVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
// Matches (optional) explicit template parameters.
|
||||
class LambdaTemplateParametersVisitor
|
||||
: public ExpectedLocationVisitor<LambdaTemplateParametersVisitor> {
|
||||
public:
|
||||
bool shouldVisitImplicitCode() const { return false; }
|
||||
|
||||
bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
|
||||
EXPECT_FALSE(D->isImplicit());
|
||||
Match(D->getName(), D->getLocStart());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
||||
EXPECT_FALSE(D->isImplicit());
|
||||
Match(D->getName(), D->getLocStart());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
|
||||
EXPECT_FALSE(D->isImplicit());
|
||||
Match(D->getName(), D->getLocStart());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(RecursiveASTVisitor, VisitsLambdaExplicitTemplateParameters) {
|
||||
LambdaTemplateParametersVisitor Visitor;
|
||||
Visitor.ExpectMatch("T", 2, 15);
|
||||
Visitor.ExpectMatch("I", 2, 24);
|
||||
Visitor.ExpectMatch("TT", 2, 31);
|
||||
EXPECT_TRUE(Visitor.runOver(
|
||||
"void f() { \n"
|
||||
" auto l = []<class T, int I, template<class> class TT>(auto p) { }; \n"
|
||||
"}",
|
||||
LambdaTemplateParametersVisitor::Lang_CXX2a));
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
|
@ -868,7 +868,7 @@ as the draft C++2a standard evolves.
|
|||
<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 id="p0734">
|
||||
<td rowspan="4">Concepts</td>
|
||||
|
|
Loading…
Reference in New Issue