summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/ASTContext.h2
-rw-r--r--clang/include/clang/AST/ASTLambda.h49
-rw-r--r--clang/include/clang/AST/DeclCXX.h40
-rw-r--r--clang/include/clang/AST/ExprCXX.h7
-rw-r--r--clang/include/clang/AST/Type.h10
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td9
-rw-r--r--clang/include/clang/Sema/DeclSpec.h10
-rw-r--r--clang/include/clang/Sema/ScopeInfo.h31
-rw-r--r--clang/include/clang/Sema/Sema.h37
-rw-r--r--clang/lib/AST/ASTDumper.cpp4
-rw-r--r--clang/lib/AST/ASTImporter.cpp3
-rw-r--r--clang/lib/AST/DeclCXX.cpp46
-rw-r--r--clang/lib/AST/ExprCXX.cpp14
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp2
-rw-r--r--clang/lib/Parse/ParseDecl.cpp35
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp18
-rw-r--r--clang/lib/Sema/Sema.cpp25
-rw-r--r--clang/lib/Sema/SemaDecl.cpp36
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp16
-rw-r--r--clang/lib/Sema/SemaLambda.cpp110
-rw-r--r--clang/lib/Sema/SemaOverload.cpp4
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp12
-rw-r--r--clang/lib/Sema/SemaType.cpp70
-rw-r--r--clang/lib/Sema/TreeTransform.h23
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp1
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp74
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp51
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp23
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp57
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp4
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp135
32 files changed, 843 insertions, 116 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index f1ccee2e372..b0205426750 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1130,7 +1130,7 @@ public:
/// \brief C++11 deduced auto type.
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
- bool IsDependent = false) const;
+ bool IsDependent) const;
/// \brief C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
diff --git a/clang/include/clang/AST/ASTLambda.h b/clang/include/clang/AST/ASTLambda.h
new file mode 100644
index 00000000000..814beb34e17
--- /dev/null
+++ b/clang/include/clang/AST/ASTLambda.h
@@ -0,0 +1,49 @@
+//===--- ASTLambda.h - Lambda Helper Functions --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides some common utility functions for processing
+/// Lambda related AST Constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_LAMBDA_H
+#define LLVM_CLANG_AST_LAMBDA_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+
+namespace clang {
+inline StringRef getLambdaStaticInvokerName() {
+ return "__invoke";
+}
+// This function returns true if M is a specialization, a template,
+// or a non-generic lambda call operator.
+inline bool isLambdaCallOperator(const CXXMethodDecl *MD) {
+ const CXXRecordDecl *LambdaClass = MD->getParent();
+ if (!LambdaClass || !LambdaClass->isLambda()) return false;
+ return MD->getOverloadedOperator() == OO_Call;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
+ CXXRecordDecl *LambdaClass = MD->getParent();
+ if (LambdaClass && LambdaClass->isGenericLambda())
+ return isLambdaCallOperator(MD) &&
+ MD->isFunctionTemplateSpecialization();
+ return false;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(Decl *D) {
+ if (!D || !isa<CXXMethodDecl>(D)) return false;
+ return isGenericLambdaCallOperatorSpecialization(
+ cast<CXXMethodDecl>(D));
+}
+} // clang
+
+#endif // LLVM_CLANG_AST_LAMBDA_H
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index f8f2e41fe62..3c970059eb5 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -516,8 +516,8 @@ class CXXRecordDecl : public RecordDecl {
LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent)
: DefinitionData(D), Dependent(Dependent), NumCaptures(0),
- NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0),
- MethodTyInfo(Info)
+ NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0),
+ Captures(0), MethodTyInfo(Info), TheLambdaExpr(0)
{
IsLambda = true;
}
@@ -529,7 +529,7 @@ class CXXRecordDecl : public RecordDecl {
/// within the default argument of a function template, because the
/// lambda will have been created with the enclosing context as its
/// declaration context, rather than function. This is an unfortunate
- /// artifact of having to parse the default arguments before
+ /// artifact of having to parse the default arguments before.
unsigned Dependent : 1;
/// \brief The number of captures in this lambda.
@@ -554,6 +554,10 @@ class CXXRecordDecl : public RecordDecl {
/// \brief The type of the call method.
TypeSourceInfo *MethodTyInfo;
+
+ /// \brief The AST node of the lambda expression.
+ LambdaExpr *TheLambdaExpr;
+
};
struct DefinitionData &data() {
@@ -989,6 +993,36 @@ public:
/// \brief Determine whether this class describes a lambda function object.
bool isLambda() const { return hasDefinition() && data().IsLambda; }
+ /// \brief Determine whether this class describes a generic
+ /// lambda function object (i.e. function call operator is
+ /// a template).
+ bool isGenericLambda() const;
+
+ /// \brief Retrieve the lambda call operator of the closure type
+ /// if this is a closure type.
+ CXXMethodDecl *getLambdaCallOperator() const;
+
+ /// \brief Retrieve the lambda static invoker, the address of which
+ /// is returned by the conversion operator, and the body of which
+ /// is forwarded to the lambda call operator.
+ CXXMethodDecl *getLambdaStaticInvoker() const;
+
+ /// \brief Retrieve the generic lambda's template parameter list.
+ /// Returns null if the class does not represent a lambda or a generic
+ /// lambda.
+ TemplateParameterList *getGenericLambdaTemplateParameterList() const;
+
+ /// \brief Assign the member call operator of the lambda.
+ void setLambdaExpr(LambdaExpr *E) {
+ getLambdaData().TheLambdaExpr = E;
+ }
+
+ /// \brief Retrieve the parent lambda expression.
+ LambdaExpr *getLambdaExpr() const {
+ return isLambda() ? getLambdaData().TheLambdaExpr : 0;
+ }
+
+
/// \brief For a closure type, retrieve the mapping from captured
/// variables and \c this to the non-static data members that store the
/// values or references of the captures.
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index c39d29f80e1..a8949fe18b1 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -1606,6 +1606,13 @@ public:
/// lambda expression.
CXXMethodDecl *getCallOperator() const;
+ /// \brief If this is a generic lambda expression, retrieve the template
+ /// parameter list associated with it, or else return null.
+ TemplateParameterList *getTemplateParameterList() const;
+
+ /// \brief Whether this is a generic lambda.
+ bool isGenericLambda() const { return getTemplateParameterList(); }
+
/// \brief Retrieve the body of the lambda.
CompoundStmt *getBody() const;
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 8df030c842f..fb829e4d410 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -3630,10 +3630,13 @@ public:
/// is no deduced type and an auto type is canonical. In the latter case, it is
/// also a dependent type.
class AutoType : public Type, public llvm::FoldingSetNode {
- AutoType(QualType DeducedType, bool IsDecltypeAuto, bool IsDependent)
+ AutoType(QualType DeducedType, bool IsDecltypeAuto,
+ bool IsDependent)
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
- /*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
+ /*VariablyModified=*/false,
+ /*ContainsParameterPack=*/DeducedType.isNull()
+ ? false : DeducedType->containsUnexpandedParameterPack()) {
assert((DeducedType.isNull() || !IsDependent) &&
"auto deduced to dependent type");
AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
@@ -3657,7 +3660,8 @@ public:
}
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDeducedType(), isDecltypeAuto(), isDependentType());
+ Profile(ID, getDeducedType(), isDecltypeAuto(),
+ isDependentType());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2ac197fd520..82a36c690c6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1470,11 +1470,12 @@ def err_illegal_decl_array_of_auto : Error<
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "'auto' not allowed %select{in function prototype|in non-static struct member"
+ "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype"
+ "|in non-static struct member"
"|in non-static union member|in non-static class member|in interface member"
"|in exception declaration|in template parameter|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
- "|in conversion function type|here}0">;
+ "|in conversion function type|here|in lambda parameter}1">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
@@ -5078,6 +5079,10 @@ let CategoryName = "Lambda Issue" in {
"cannot deduce type for lambda capture %0 from initializer list">;
}
+// C++1y Generic Lambdas
+def err_glambda_not_fully_implemented : Error<
+ "unimplemented generic lambda feature: %0">;
+
def err_return_in_captured_stmt : Error<
"cannot return from %0">;
def err_capture_block_variable : Error<
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 5924a15b7e4..dfb79325f25 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1502,6 +1502,7 @@ public:
ObjCCatchContext, // Objective-C catch exception-declaration
BlockLiteralContext, // Block literal declarator.
LambdaExprContext, // Lambda-expression declarator.
+ LambdaExprParameterContext, // Lambda-expression parameter declarator.
ConversionIdContext, // C++ conversion-type-id.
TrailingReturnContext, // C++11 trailing-type-specifier.
TemplateTypeArgContext, // Template type argument.
@@ -1577,7 +1578,6 @@ public:
~Declarator() {
clear();
}
-
/// getDeclSpec - Return the declaration-specifier that this declarator was
/// declared with.
const DeclSpec &getDeclSpec() const { return DS; }
@@ -1606,7 +1606,8 @@ public:
bool isPrototypeContext() const {
return (Context == PrototypeContext ||
Context == ObjCParameterContext ||
- Context == ObjCResultContext);
+ Context == ObjCResultContext ||
+ Context == LambdaExprParameterContext);
}
/// \brief Get the source range that spans this declarator.
@@ -1670,6 +1671,7 @@ public:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case ObjCParameterContext:
case ObjCResultContext:
case TemplateParamContext:
@@ -1698,6 +1700,7 @@ public:
case ForContext:
case ConditionContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case TemplateParamContext:
case CXXCatchContext:
case ObjCCatchContext:
@@ -1730,6 +1733,7 @@ public:
case ForContext:
case ConditionContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case TemplateParamContext:
case CXXCatchContext:
case ObjCCatchContext:
@@ -1782,6 +1786,7 @@ public:
case KNRTypeListContext:
case MemberContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case ObjCParameterContext:
case ObjCResultContext:
case TemplateParamContext:
@@ -1968,6 +1973,7 @@ public:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
+ case LambdaExprParameterContext:
case ObjCParameterContext:
case ObjCResultContext:
case TemplateParamContext:
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index bc49dcda66d..4853f46f5f8 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -35,6 +35,8 @@ class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
+class TemplateTypeParmDecl;
+class TemplateParameterList;
class VarDecl;
class DeclRefExpr;
class ObjCIvarRefExpr;
@@ -615,12 +617,29 @@ public:
/// \brief Offsets into the ArrayIndexVars array at which each capture starts
/// its list of array index variables.
SmallVector<unsigned, 4> ArrayIndexStarts;
-
- LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
- CXXMethodDecl *CallOperator)
- : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
- CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
- ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false)
+
+ /// \brief If this is a generic lambda, use this as the depth of
+ /// each 'auto' parameter, during initial AST construction.
+ unsigned AutoTemplateParameterDepth;
+
+ /// \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
+ /// parameter list, during initial AST construction.
+ SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
+
+ /// 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).
+ TemplateParameterList *GLTemplateParameterList;
+
+ LambdaScopeInfo(DiagnosticsEngine &Diag)
+ : CapturingScopeInfo(Diag, ImpCap_None), Lambda(0),
+ CallOperator(0), NumExplicitCaptures(0), Mutable(false),
+ ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),
+ AutoTemplateParameterDepth(0),
+ GLTemplateParameterList(0)
{
Kind = SK_Lambda;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f54561528d5..56988b1d570 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -965,7 +965,13 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
- void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator);
+ void PushLambdaScope();
+
+ /// \brief This is used to inform Sema what the current TemplateParameterDepth
+ /// is during Parsing. Currently it is used to pass on the depth
+ /// when parsing generic lambda 'auto' parameters.
+ void RecordParsingTemplateParameterDepth(unsigned Depth);
+
void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD,
RecordDecl *RD,
CapturedRegionKind K);
@@ -992,9 +998,12 @@ public:
/// \brief Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
- /// \brief Retrieve the current lambda expression, if any.
+ /// \brief Retrieve the current lambda scope info, if any.
sema::LambdaScopeInfo *getCurLambda();
+ /// \brief Retrieve the current generic lambda info, if any.
+ sema::LambdaScopeInfo *getCurGenericLambda();
+
/// \brief Retrieve the current captured region, if any.
sema::CapturedRegionScopeInfo *getCurCapturedRegion();
@@ -4427,14 +4436,15 @@ public:
SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params);
- /// \brief Introduce the scope for a lambda expression.
- sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
- SourceRange IntroducerRange,
- LambdaCaptureDefault CaptureDefault,
- SourceLocation CaptureDefaultLoc,
- bool ExplicitParams,
- bool ExplicitResultType,
- bool Mutable);
+ /// \brief Endow the lambda scope info with the relevant properties.
+ void buildLambdaScope(sema::LambdaScopeInfo *LSI,
+ CXXMethodDecl *CallOperator,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ bool Mutable);
/// \brief Check and build an init-capture with the specified name and
/// initializer.
@@ -5819,6 +5829,12 @@ public:
sema::TemplateDeductionInfo &Info,
bool InOverloadResolution = false);
+ /// \brief Substitute Replacement for \p auto in \p TypeWithAuto
+ QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
+ /// \brief Substitute Replacement for auto in TypeWithAuto
+ TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
+ QualType Replacement);
+
/// \brief Result type of DeduceAutoType.
enum DeduceAutoResult {
DAR_Succeeded,
@@ -5830,7 +5846,6 @@ public:
QualType &Result);
DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer,
QualType &Result);
- QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 1f9a4dce55b..bdadbeddbaf 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -286,6 +286,10 @@ namespace {
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
void dumpCXXTemporary(const CXXTemporary *Temporary);
+ void VisitLambdaExpr(const LambdaExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getLambdaClass());
+ }
// ObjC
void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 922172701f0..c6edc771203 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1709,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto());
+ return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
+ /*IsDependent*/false);
}
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 337ca6629c9..09ab8c916ab 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -10,9 +10,9 @@
// This file implements the C++ related Decl classes.
//
//===----------------------------------------------------------------------===//
-
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
@@ -943,6 +943,40 @@ bool CXXRecordDecl::isCLike() const {
return isPOD() && data().HasOnlyCMembers;
}
+bool CXXRecordDecl::isGenericLambda() const {
+ return isLambda() &&
+ getLambdaCallOperator()->getDescribedFunctionTemplate();
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_result Calls = lookup(Name);
+
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+
+ NamedDecl *CallOp = Calls.front();
+ if (FunctionTemplateDecl *CallOpTmpl =
+ dyn_cast<FunctionTemplateDecl>(CallOp))
+ return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(CallOp);
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ &getASTContext().Idents.get(getLambdaStaticInvokerName());
+ DeclContext::lookup_const_result Invoker = lookup(Name);
+ if (Invoker.empty()) return 0;
+ assert(Invoker.size() == 1 && "More than one static invoker operator!");
+ CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front());
+ return Result;
+
+}
+
void CXXRecordDecl::getCaptureFields(
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
FieldDecl *&ThisCapture) const {
@@ -960,6 +994,14 @@ void CXXRecordDecl::getCaptureFields(
}
}
+TemplateParameterList *
+CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
+ if (!isLambda()) return 0;
+ CXXMethodDecl *CallOp = getLambdaCallOperator();
+ if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
+ return Tmpl->getTemplateParameters();
+ return 0;
+}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
@@ -1510,7 +1552,7 @@ bool CXXMethodDecl::hasInlineBody() const {
bool CXXMethodDecl::isLambdaStaticInvoker() const {
return getParent()->isLambda() &&
- getIdentifier() && getIdentifier()->getName() == "__invoke";
+ getParent()->getLambdaStaticInvoker() == this;
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 55589e6d21f..7478678bf0b 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1076,13 +1076,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const {
CXXMethodDecl *LambdaExpr::getCallOperator() const {
CXXRecordDecl *Record = getLambdaClass();
- DeclarationName Name
- = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(!Calls.empty() && "Missing lambda call operator!");
- assert(Calls.size() == 1 && "More than one lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
- return Result;
+ return Record->getLambdaCallOperator();
+}
+
+TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getGenericLambdaTemplateParameterList();
+
}
CompoundStmt *LambdaExpr::getBody() const {
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index c9279a27f11..b66a8492840 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -698,7 +698,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitLambdaToBlockPointerBody(Args);
} else if (isa<CXXMethodDecl>(FD) &&
cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
- // The lambda "__invoke" function is special, because it forwards or
+ // The lambda static invoker function is special, because it forwards or
// clones the body of the function call operator (but is actually static).
EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
} else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index a1a796de414..b71cced3536 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4677,6 +4677,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// as part of the parameter-declaration-clause.
if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
!((D.getContext() == Declarator::PrototypeContext ||
+ D.getContext() == Declarator::LambdaExprParameterContext ||
D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) &&
!D.hasGroupingParens() &&
@@ -5002,7 +5003,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
TypeResult TrailingReturnType;
Actions.ActOnStartFunctionDeclarator();
-
/* LocalEndLoc is the end location for the local FunctionTypeLoc.
EndLoc is the end location for the function declarator.
They differ for trailing return types. */
@@ -5023,7 +5023,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
EndLoc = RParenLoc;
} else {
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
+ ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
+ EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -5254,7 +5255,6 @@ void Parser::ParseParameterDeclarationClause(
ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) {
-
while (1) {
if (Tok.is(tok::ellipsis)) {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
@@ -5284,16 +5284,21 @@ void Parser::ParseParameterDeclarationClause(
ParseDeclarationSpecifiers(DS);
- // Parse the declarator. This is "PrototypeContext", because we must
- // accept either 'declarator' or 'abstract-declarator' here.
- Declarator ParmDecl(DS, Declarator::PrototypeContext);
- ParseDeclarator(ParmDecl);
+
+ // Parse the declarator. This is "PrototypeContext" or
+ // "LambdaExprParameterContext", because we must accept either
+ // 'declarator' or 'abstract-declarator' here.
+ Declarator ParmDeclarator(DS,
+ D.getContext() == Declarator::LambdaExprContext ?
+ Declarator::LambdaExprParameterContext :
+ Declarator::PrototypeContext);
+ ParseDeclarator(ParmDeclarator);
// Parse GNU attributes, if present.
- MaybeParseGNUAttributes(ParmDecl);
+ MaybeParseGNUAttributes(ParmDeclarator);
// Remember this parsed parameter in ParamInfo.
- IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+ IdentifierInfo *ParmII = ParmDeclarator.getIdentifier();
// DefArgToks is used when the parsing of default arguments needs
// to be delayed.
@@ -5301,8 +5306,8 @@ void Parser::ParseParameterDeclarationClause(
// If no parameter was specified, verify that *something* was specified,
// otherwise we have a missing type and identifier.
- if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 &&
- ParmDecl.getNumTypeObjects() == 0) {
+ if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 &&
+ ParmDeclarator.getNumTypeObjects() == 0) {
// Completely missing, emit error.
Diag(DSStart, diag::err_missing_param);
} else {
@@ -5311,8 +5316,8 @@ void Parser::ParseParameterDeclarationClause(
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
- Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
-
+ Decl *Param = Actions.ActOnParamDeclarator(getCurScope(),
+ ParmDeclarator);
// Parse the default argument, if any. We parse the default
// arguments in all dialects; the semantic analysis in
// ActOnParamDefaultArgument will reject the default argument in
@@ -5371,8 +5376,8 @@ void Parser::ParseParameterDeclarationClause(
}
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
- ParmDecl.getIdentifierLoc(), Param,
- DefArgToks));
+ ParmDeclarator.getIdentifierLoc(),
+ Param, DefArgToks));
}
// If the next token is a comma, consume it and keep reading arguments.
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 9ac6d435067..2eace9fc74f 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -10,7 +10,7 @@
// This file implements the Expression parsing implementation for C++.
//
//===----------------------------------------------------------------------===//
-
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Basic/PrettyStackTrace.h"
@@ -21,6 +21,7 @@
#include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h"
+
using namespace clang;
static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
@@ -908,12 +909,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
"lambda expression parsing");
+
+
// FIXME: Call into Actions to add any init-capture declarations to the
// scope while parsing the lambda-declarator and compound-statement.
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
Declarator D(DS, Declarator::LambdaExprContext);
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+ Actions.PushLambdaScope();
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@@ -931,9 +936,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
- if (Tok.isNot(tok::r_paren))
+
+ if (Tok.isNot(tok::r_paren)) {
+ sema::LambdaScopeInfo *LSI = Actions.getCurLambda();
+ Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
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();
DeclEndLoc = RParenLoc;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 00f38bfa8c6..6f2b3095326 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1023,10 +1023,17 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
-void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
- CXXMethodDecl *CallOperator) {
- FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda,
- CallOperator));
+void Sema::PushLambdaScope() {
+ FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics()));
+}
+
+void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
+ if (LambdaScopeInfo *const LSI = getCurLambda()) {
+ LSI->AutoTemplateParameterDepth = Depth;
+ return;
+ }
+ llvm_unreachable(
+ "Remove assertion if intentionally called in a non-lambda context.");
}
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
@@ -1082,6 +1089,16 @@ LambdaScopeInfo *Sema::getCurLambda() {
return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
}
+// We have a generic lambda if we parsed auto parameters, or we have
+// an associated template parameter list.
+LambdaScopeInfo *Sema::getCurGenericLambda() {
+ if (LambdaScopeInfo *LSI = getCurLambda()) {
+ return (LSI->AutoTemplateParams.size() ||
+ LSI->GLTemplateParameterList) ? LSI : 0;
+ }
+ return 0;
+}
+
void Sema::ActOnComment(SourceRange Comment) {
if (!LangOpts.RetainCommentsFromSystemHeaders &&
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fa51aa4c09f..5997abe0296 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15,6 +15,7 @@
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CommentDiagnostic.h"
@@ -8975,6 +8976,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+
// C++03 [dcl.stc]p2 also permits 'auto'.
VarDecl::StorageClass StorageClass = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
@@ -9334,9 +9336,37 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
FD = FunTmpl->getTemplatedDecl();
else
FD = cast<FunctionDecl>(D);
-
- // Enter a new function scope
- PushFunctionScope();
+ // If we are instantiating a generic lambda call operator, push
+ // a LambdaScopeInfo onto the function stack. But use the information
+ // that's already been calculated (ActOnLambdaExpr) when analyzing the
+ // template version, to prime the current LambdaScopeInfo.
+ if (isGenericLambdaCallOperatorSpecialization(D)) {
+ CXXMethodDecl *CallOperator = cast<CXXMethodDecl>(D);
+ CXXRecordDecl *LambdaClass = CallOperator->getParent();
+ LambdaExpr *LE = LambdaClass->getLambdaExpr();
+ assert(LE &&
+ "No LambdaExpr of closure class when instantiating a generic lambda!");
+ assert(ActiveTemplateInstantiations.size() &&
+ "There should be an active template instantiation on the stack "
+ "when instantiating a generic lambda!");
+ PushLambdaScope();
+ LambdaScopeInfo *LSI = getCurLambda();
+ LSI->CallOperator = CallOperator;
+ LSI->Lambda = LambdaClass;
+ LSI->ReturnType = CallOperator->getResultType();
+
+ if (LE->getCaptureDefault() == LCD_None)
+ LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_None;
+ else if (LE->getCaptureDefault() == LCD_ByCopy)
+ LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByval;
+ else if (LE->getCaptureDefault() == LCD_ByRef)
+ LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref;
+
+ LSI->IntroducerRange = LE->getIntroducerRange();
+ }
+ else
+ // Enter a new function scope
+ PushFunctionScope();
// See if this is a redefinition.
if (!FD->isLateTemplateParsed())
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d5c0e7a5708..6e1751aebd9 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
@@ -10364,10 +10365,10 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
- CXXRecordDecl *Lambda = Conv->getParent();
+ CXXRecordDecl *LambdaClass = Conv->getParent();
// Make sure that the lambda call operator is marked used.
- markLambdaCallOperatorUsed(*this, Lambda);
+ markLambdaCallOperatorUsed(*this, LambdaClass);
Conv->markUsed(Context);
@@ -10375,19 +10376,18 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
DiagnosticErrorTrap Trap(Diags);
// Return the address of the __invoke function.
- DeclarationName InvokeName = &Context.Idents.get("__invoke");
- CXXMethodDecl *Invoke
- = cast<CXXMethodDecl>(Lambda->lookup(InvokeName).front());
+
+ CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();
Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
VK_LValue, Conv->getLocation()).take();
- assert(FunctionRef && "Can't refer to __invoke function?");
+ assert(FunctionRef && "Can't refer to lambda static invoker function?");
Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
Conv->setBody(new (Context) CompoundStmt(Context, Return,
Conv->getLocation(),
Conv->getLocation()));
- // Fill in the __invoke function with a dummy implementation. IR generation
- // will fill in the actual details.
+ // Fill in the static invoker function with a dummy implementation.
+ // IR generation will fill in the actual details.
Invoke->markUsed(Context);
Invoke->setReferenced();
Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index ec69ef8ed0a..569bfdfce22 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -130,17 +131,37 @@ Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
return *MangleNumbering;
}
+static inline TemplateParameterList *
+getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
+ if (LSI->GLTemplateParameterList)
+ return LSI->GLTemplateParameterList;
+ else if (LSI->AutoTemplateParams.size()) {
+ SourceRange IntroRange = LSI->IntroducerRange;
+ SourceLocation LAngleLoc = IntroRange.getBegin();
+ SourceLocation RAngleLoc = IntroRange.getEnd();
+ LSI->GLTemplateParameterList =
+ TemplateParameterList::Create(SemaRef.Context,
+ /* Template kw loc */ SourceLocation(),
+ LAngleLoc,
+ (NamedDecl**)LSI->AutoTemplateParams.data(),
+ LSI->AutoTemplateParams.size(), RAngleLoc);
+ }
+ return LSI->GLTemplateParameterList;
+}
+
+
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodTypeInfo,
SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params) {
QualType MethodType = MethodTypeInfo->getType();
-
- // If a lambda appears in a dependent context and has an 'auto' return type,
- // deduce it to a dependent type.
- // FIXME: Generic lambda call operators should also get this treatment.
- if (Class->isDependentContext()) {
+ TemplateParameterList *TemplateParams =
+ getGenericLambdaTemplateParameterList(getCurLambda(), *this);
+ // If a lambda appears in a dependent context or is a generic lambda (has
+ // template parameters) and has an 'auto' return type, deduce it to a
+ // dependent type.
+ if (Class->isDependentContext() || TemplateParams) {
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
QualType Result = FPT->getResultType();
if (Result->isUndeducedType()) {
@@ -177,6 +198,17 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// Temporarily set the lexical declaration context to the current
// context, so that the Scope stack matches the lexical nesting.
Method->setLexicalDeclContext(CurContext);
+ // Create a function template if we have a template parameter list
+ FunctionTemplateDecl *const TemplateMethod = TemplateParams ?
+ FunctionTemplateDecl::Create(Context, Class,
+ Method->getLocation(), MethodName,
+ TemplateParams,
+ Method) : 0;
+ if (TemplateMethod) {
+ TemplateMethod->setLexicalDeclContext(CurContext);
+ TemplateMethod->setAccess(AS_public);
+ Method->setDescribedFunctionTemplate(TemplateMethod);
+ }
// Add parameters.
if (!Params.empty()) {
@@ -202,15 +234,16 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
return Method;
}
-LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
+void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
+ CXXMethodDecl *CallOperator,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc,
bool ExplicitParams,
bool ExplicitResultType,
bool Mutable) {
- PushLambdaScope(CallOperator->getParent(), CallOperator);
- LambdaScopeInfo *LSI = getCurLambda();
+ LSI->CallOperator = CallOperator;
+ LSI->Lambda = CallOperator->getParent();
if (CaptureDefault == LCD_ByCopy)
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
else if (CaptureDefault == LCD_ByRef)
@@ -233,8 +266,6 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
} else {
LSI->HasImplicitReturnType = true;
}
-
- return LSI;
}
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
@@ -384,6 +415,8 @@ static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
+ // If it was ever a placeholder, it had to been deduced to DependentTy.
+ assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType());
// C++ Core Issue #975, proposed resolution:
// If a lambda-expression does not include a trailing-return-type,
@@ -544,15 +577,25 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
- Declarator &ParamInfo,
- Scope *CurScope) {
+ 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;
- if (Scope *TmplScope = CurScope->getTemplateParamParent())
- if (!TmplScope->decl_empty())
+ LambdaScopeInfo *const LSI = getCurLambda();
+ assert(LSI && "LambdaScopeInfo should be on stack!");
+ TemplateParameterList *TemplateParams =
+ getGenericLambdaTemplateParameterList(LSI, *this);
+
+ if (Scope *TmplScope = CurScope->getTemplateParamParent()) {
+ // Since we have our own TemplateParams, so check if an outer scope
+ // has template params, only then are we in a dependent scope.
+ if (TemplateParams) {
+ TmplScope = TmplScope->getParent();
+ TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : 0;
+ }
+ if (TmplScope && !TmplScope->decl_empty())
KnownDependent = true;
-
+ }
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
@@ -621,7 +664,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
-
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -631,9 +673,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method);
- // Introduce the lambda scope.
- LambdaScopeInfo *LSI
- = enterLambdaScope(Method,
+ // Build the lambda scope.
+ buildLambdaScope(LSI, Method,
Intro.Range,
Intro.Default, Intro.DefaultLoc,
ExplicitParams,
@@ -845,6 +886,8 @@ static void addFunctionPointerConversion(Sema &S,
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
+ // FIXME: The conversion operator needs to be fixed for generic lambdas.
+ if (Class->isGenericLambda()) return;
// Add the conversion to function pointer.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
@@ -885,10 +928,9 @@ static void addFunctionPointerConversion(Sema &S,
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Class->addDecl(Conversion);
-
- // Add a non-static member function "__invoke" that will be the result of
- // the conversion.
- Name = &S.Context.Idents.get("__invoke");
+ // Add a non-static member function that will be the result of
+ // the conversion with a certain unique ID.
+ Name = &S.Context.Idents.get(getLambdaStaticInvokerName());
CXXMethodDecl *Invoke
= CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy,
@@ -1060,13 +1102,19 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
LSI->ReturnType, Proto->getArgTypes(), Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
-
// C++ [expr.prim.lambda]p7:
// The lambda-expression's compound-statement yields the
// function-body (8.4) of the function call operator [...].
ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
CallOperator->setLexicalDeclContext(Class);
- Class->addDecl(CallOperator);
+ Decl *TemplateOrNonTemplateCallOperatorDecl =
+ CallOperator->getDescribedFunctionTemplate()
+ ? CallOperator->getDescribedFunctionTemplate()
+ : cast<Decl>(CallOperator);
+
+ TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
+ Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
+
PopExpressionEvaluationContext();
// C++11 [expr.prim.lambda]p6:
@@ -1106,7 +1154,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
CaptureInits, ArrayIndexVars,
ArrayIndexStarts, Body->getLocEnd(),
ContainsUnexpandedParameterPack);
-
+ Class->setLambdaExpr(Lambda);
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
// (Clause 5).
@@ -1126,7 +1174,15 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
break;
}
}
-
+ // TODO: Implement capturing.
+ if (Lambda->isGenericLambda()) {
+ if (Lambda->getCaptureDefault() != LCD_None) {
+ Diag(Lambda->getIntroducerRange().getBegin(),
+ diag::err_glambda_not_fully_implemented)
+ << " capturing not implemented yet";
+ return ExprError();
+ }
+ }
return MaybeBindToTemporary(Lambda);
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 13d19b6cb98..6905ff1464c 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -8682,6 +8682,10 @@ void DiagnoseBadDeduction(Sema &S, Decl *Templated,
}
}
}
+ // FIXME: For generic lambda parameters, check if the function is a lambda
+ // call operator, and if so, emit a prettier and more informative
+ // diagnostic that mentions 'auto' and lambda in addition to
+ // (or instead of?) the canonical template type parameters.
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch)
<< FirstTA << SecondTA;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1d52709341e..5510bc2040b 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3913,8 +3913,16 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
return DAR_Succeeded;
}
-QualType Sema::SubstAutoType(QualType Type, QualType Deduced) {
- return SubstituteAutoTransform(*this, Deduced).TransformType(Type);
+QualType Sema::SubstAutoType(QualType TypeWithAuto,
+ QualType TypeToReplaceAuto) {
+ return SubstituteAutoTransform(*this, TypeToReplaceAuto).
+ TransformType(TypeWithAuto);
+}
+
+TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
+ QualType TypeToReplaceAuto) {
+ return SubstituteAutoTransform(*this, TypeToReplaceAuto).
+ TransformType(TypeWithAuto);
}
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 1f40eb8d1db..839ca7eca7c 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -994,11 +994,54 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TST_auto:
// TypeQuals handled by caller.
- Result = Context.getAutoType(QualType(), /*decltype(auto)*/false);
+ // If auto is mentioned in a lambda parameter context, convert it to a
+ // template parameter type immediately, with the appropriate depth and
+ // index, and update sema's state (LambdaScopeInfo) for the current lambda
+ // being analyzed (which tracks the invented type template parameter).
+ if (declarator.getContext() == Declarator::LambdaExprParameterContext) {
+ sema::LambdaScopeInfo *LSI = S.getCurLambda();
+ assert(LSI && "No LambdaScopeInfo on the stack!");
+ const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
+ const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+ const bool IsParameterPack = declarator.hasEllipsis();
+
+ // Create a name for the invented template parameter type.
+ std::string InventedTemplateParamName = "$auto-";
+ llvm::raw_string_ostream ss(InventedTemplateParamName);
+ ss << TemplateParameterDepth;
+ ss << "-" << AutoParameterPosition;
+ ss.flush();
+
+ IdentifierInfo& TemplateParamII = Context.Idents.get(
+ InventedTemplateParamName.c_str());
+ // Turns out we must create the TemplateTypeParmDecl here to
+ // retrieve the corresponding template parameter type.
+ TemplateTypeParmDecl *CorrespondingTemplateParam =
+ TemplateTypeParmDecl::Create(Context,
+ // Temporarily add to the TranslationUnit DeclContext. When the
+ // associated TemplateParameterList is attached to a template
+ // declaration (such as FunctionTemplateDecl), the DeclContext
+ // for each template parameter gets updated appropriately via
+ // a call to AdoptTemplateParameterList.
+ Context.getTranslationUnitDecl(),
+ /*KeyLoc*/ SourceLocation(),
+ /*NameLoc*/ declarator.getLocStart(),
+ TemplateParameterDepth,
+ AutoParameterPosition, // our template param index
+ /* Identifier*/ &TemplateParamII, false, IsParameterPack);
+ LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ // Replace the 'auto' in the function parameter with this invented
+ // template type parameter.
+ Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
+ } else {
+ Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false);
+ }
break;
case DeclSpec::TST_decltype_auto:
- Result = Context.getAutoType(QualType(), /*decltype(auto)*/true);
+ Result = Context.getAutoType(QualType(),
+ /*decltype(auto)*/true,
+ /*IsDependent*/ false);
break;
case DeclSpec::TST_unknown_anytype:
@@ -1545,7 +1588,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
ASM = ArrayType::Normal;
}
} else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
- !T->isIncompleteType()) {
+ !T->isIncompleteType() && !T->isUndeducedType()) {
// Is the array too large?
unsigned ActiveSizeBits
= ConstantArrayType::getNumAddressingBits(Context, T, ConstVal);
@@ -2087,6 +2130,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// In C++11, a function declarator using 'auto' must have a trailing return
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
+ // C++14 In generic lambdas allow 'auto' in their parameters.
if (ContainsPlaceholderType &&
(!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1;
@@ -2099,7 +2143,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::PrototypeContext:
- Error = 0; // Function prototype
+ Error = 0;
+ break;
+ case Declarator::LambdaExprParameterContext:
+ if (!(SemaRef.getLangOpts().CPlusPlus1y
+ && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
+ Error = 14;
break;
case Declarator::MemberContext:
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
@@ -2179,8 +2228,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
AutoRange = D.getName().getSourceRange();
if (Error != -1) {
+ const bool IsDeclTypeAuto =
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto;
SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed)
- << Error << AutoRange;
+ << IsDeclTypeAuto << Error << AutoRange;
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
} else
@@ -2230,6 +2281,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType(true);
break;
case Declarator::PrototypeContext:
+ case Declarator::LambdaExprParameterContext:
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::KNRTypeListContext:
@@ -2651,8 +2703,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
}
-
- if (const AutoType *AT = T->getContainedAutoType()) {
+ const AutoType *AT = T->getContainedAutoType();
+ // Allow arrays of auto if we are a generic lambda parameter.
+ // i.e. [](auto (&array)[5]) { return array[0]; }; OK
+ if (AT && D.getContext() != Declarator::LambdaExprParameterContext) {
// We've already diagnosed this for decltype(auto).
if (!AT->isDecltypeAuto())
S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
@@ -3151,6 +3205,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// is a parameter pack (14.5.3). [...]
switch (D.getContext()) {
case Declarator::PrototypeContext:
+ case Declarator::LambdaExprParameterContext:
// C++0x [dcl.fct]p13:
// [...] When it is part of a parameter-declaration-clause, the
// parameter pack is a function parameter pack (14.5.3). The type T
@@ -3169,7 +3224,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getPackExpansionType(T, None);
}
break;
-
case Declarator::TemplateParamContext:
// C++0x [temp.param]p15:
// If a template-parameter is a [...] is a parameter-declaration that
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5d080f9efb7..6559dede1c9 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -787,7 +787,8 @@ public:
// Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation.
- return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto);
+ return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto,
+ /*IsDependent*/ false);
}
/// \brief Build a new template specialization type.
@@ -3514,7 +3515,8 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
Qs.removeObjCLifetime();
Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
Qs);
- Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto());
+ Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(),
+ AutoTy->isDependentType());
TLB.TypeWasModifiedSafely(Result);
} else {
// Otherwise, complain about the addition of a qualifier to an
@@ -8249,6 +8251,14 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
+
+ // FIXME: Implement nested generic lambda transformations.
+ if (E->isGenericLambda()) {
+ getSema().Diag(E->getIntroducerRange().getBegin(),
+ diag::err_glambda_not_fully_implemented)
+ << " template transformation of generic lambdas not implemented yet";
+ return ExprError();
+ }
// Transform the type of the lambda parameters and start the definition of
// the lambda itself.
TypeSourceInfo *MethodTy
@@ -8271,7 +8281,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->param_size(),
0, ParamTypes, &Params))
return ExprError();
-
+ getSema().PushLambdaScope();
+ LambdaScopeInfo *LSI = getSema().getCurLambda();
+ // TODO: Fix for nested lambdas
+ LSI->GLTemplateParameterList = 0;
// Build the call operator.
CXXMethodDecl *CallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
@@ -8306,9 +8319,9 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), CallOperator);
+ LambdaScopeInfo *const LSI = getSema().getCurLambda();
// Enter the scope of the lambda.
- sema::LambdaScopeInfo *LSI
- = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
+ getSema().buildLambdaScope(LSI, CallOperator, E->getIntroducerRange(),
E->getCaptureDefault(),
E->getCaptureDefaultLoc(),
E->hasExplicitParameters(),
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 0d8e05711ee..eaa5c5500be 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1213,6 +1213,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
= (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx);
+ Lambda.TheLambdaExpr = cast<LambdaExpr>(Reader.ReadExpr(F));
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
SourceLocation Loc = ReadSourceLocation(Record, Idx);
bool IsImplicit = Record[Idx++];
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 409c9a18a50..1826ad8312f 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5134,6 +5134,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Lambda.ManglingNumber);
AddDeclRef(Lambda.ContextDecl, Record);
AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
+ AddStmt(Lambda.TheLambdaExpr);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
LambdaExpr::Capture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record);
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
new file mode 100644
index 00000000000..65b085bcec1
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+//FIXME: These tests were written when return type deduction had not been implemented
+// for generic lambdas, hence
+template<class T> T id(T t);
+template<class ... Ts> int vfoo(Ts&& ... ts);
+auto GL1 = [](auto a, int i) -> int { return id(a); };
+
+auto GL2 = [](auto ... As) -> int { return vfoo(As...); };
+auto GL3 = [](int i, char c, auto* ... As) -> int { return vfoo(As...); };
+
+auto GL4 = [](int i, char c, auto* ... As) -> int { return vfoo(As...); };
+
+
+void foo() {
+ auto GL1 = [](auto a, int i) -> int { return id(a); };
+
+ auto GL2 = [](auto ... As) -> int { return vfoo(As...); };
+}
+
+int main()
+{
+ auto l1 = [](auto a) -> int { return a + 5; };
+ auto l2 = [](auto *p) -> int { return p + 5; };
+
+ struct A { int i; char f(int) { return 'c'; } };
+ auto l3 = [](auto &&ur,
+ auto &lr,
+ auto v,
+ int i,
+ auto* p,
+ auto A::*memvar,
+ auto (A::*memfun)(int),
+ char c,
+ decltype (v)* pv
+ , auto (&array)[5]
+ ) -> int { return v + i + c
+ + array[0];
+ };
+ int arr[5] = {0, 1, 2, 3, 4 };
+ int lval = 0;
+ double d = 3.14;
+ l3(3, lval, d, lval, &lval, &A::i, &A::f, 'c', &d, arr);
+ auto l4 = [](decltype(auto) a) -> int { return 0; }; //expected-error{{decltype(auto)}}
+ {
+ struct Local {
+ static int ifi(int i) { return i; }
+ static char cfi(int) { return 'a'; }
+ static double dfi(int i) { return i + 3.14; }
+ static Local localfi(int) { return Local{}; }
+ };
+ auto l4 = [](auto (*fp)(int)) -> int { return fp(3); }; //expected-error{{no viable conversion from 'Local' to 'int'}}
+ l4(&Local::ifi);
+ l4(&Local::cfi);
+ l4(&Local::dfi);
+ l4(&Local::localfi); //expected-note{{in instantiation of function template specialization}}
+ }
+ {
+ auto unnamed_parameter = [](auto, auto) -> void { };
+ unnamed_parameter(3, '4');
+ }
+ {
+ auto l = [](auto
+ (*)(auto)) { }; //expected-error{{'auto' not allowed}}
+ //FIXME: These diagnostics might need some work.
+ auto l2 = [](char auto::*pm) { }; //expected-error{{cannot combine with previous}}\
+ expected-error{{'pm' does not point into a class}}
+ auto l3 = [](char (auto::*pmf)()) { }; //expected-error{{'auto' not allowed}}\
+ expected-error{{'pmf' does not point into a class}}\
+ expected-error{{function cannot return function type 'char ()'}}
+ }
+}
+
+
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
new file mode 100644
index 00000000000..cd773b42781
--- /dev/null
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -emit-llvm
+namespace return_type_deduction_ok {
+ auto l = [](auto a) ->auto { return a; }(2);
+ auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
+ auto l3 = [](auto a) { return a; }(2);
+
+}
+
+namespace lambda_capturing {
+// FIXME: Once return type deduction is implemented for generic lambdas
+// this will need to be updated.
+void test() {
+ int i = 10;
+ auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+}
+
+}
+
+namespace nested_generic_lambdas {
+void test() {
+ auto L = [](auto a) -> int {
+ auto M = [](auto b, decltype(a) b2) -> int { //expected-error{{unimplemented}}
+ return 1;
+ };
+ M(a, a);
+ };
+ L(3); //expected-note{{in instantiation of}}
+}
+template<class T> void foo(T) {
+ auto L = [](auto a) { return a; }; //expected-error{{unimplemented}}
+}
+template void foo(int); //expected-note{{in instantiation of}}
+}
+
+namespace conversion_operator {
+void test() {
+ auto L = [](auto a) -> int { return a; };
+ int (*fp)(int) = L; //expected-error{{no viable conversion}}
+ }
+}
+
+namespace generic_lambda_as_default_argument_ok {
+ void test(int i = [](auto a)->int { return a; }(3)) {
+
+ }
+
+}
+
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
new file mode 100644
index 00000000000..44656a37e31
--- /dev/null
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+// prvalue
+void prvalue() {
+ auto&& x = [](auto a)->void { };
+ auto& y = [](auto *a)->void { }; // expected-error{{cannot bind to a temporary of type}}
+}
+
+namespace std {
+ class type_info;
+}
+
+struct P {
+ virtual ~P();
+};
+
+void unevaluated_operand(P &p, int i) {
+ // FIXME: this should only emit one error.
+ int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \
+ // expected-error{{invalid application of 'sizeof'}}
+ const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));
+ const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}
+}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
index 79ee76f0258..f8461335b76 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
@@ -7,3 +7,60 @@ int &d = [] (int &r) -> auto & { return r; } (a);
int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}}
int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}}
int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}}
+
+
+int test_explicit_auto_return()
+{
+ struct X {};
+ auto L = [](auto F, auto a) { return F(a); };
+ auto M = [](auto a) -> auto { return a; }; // OK
+ auto MRef = [](auto b) -> auto& { return b; }; //expected-warning{{reference to stack}}
+ auto MPtr = [](auto c) -> auto* { return &c; }; //expected-warning{{address of stack}}
+ auto MDeclType = [](auto&& d) -> decltype(auto) { return static_cast<decltype(d)>(d); }; //OK
+ M(3);
+
+ auto &&x = MDeclType(X{});
+ auto &&x1 = M(X{});
+ auto &&x2 = MRef(X{});//expected-note{{in instantiation of}}
+ auto &&x3 = MPtr(X{}); //expected-note{{in instantiation of}}
+ return 0;
+}
+
+int test_implicit_auto_return()
+{
+ {
+ auto M = [](auto a) { return a; };
+ struct X {};
+ X x = M(X{});
+
+ }
+}
+
+int test_multiple_returns() {
+ auto M = [](auto a) {
+ bool k;
+ if (k)
+ return a;
+ else
+ return 5; //expected-error{{deduced as 'int' here}}
+ };
+ M(3); // OK
+ M('a'); //expected-note{{in instantiation of}}
+ return 0;
+}
+int test_no_parameter_list()
+{
+ static int si = 0;
+ auto M = [] { return 5; }; // OK
+ auto M2 = [] -> auto&& { return si; }; // expected-error{{lambda requires '()'}}
+ M();
+}
+
+int test_conditional_in_return() {
+ auto Fac = [](auto f, auto n) {
+ return n <= 0 ? n : f(f, n - 1) * n;
+ };
+ // FIXME: this test causes a recursive limit - need to error more gracefully.
+ //Fac(Fac, 3);
+
+} \ No newline at end of file
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index c69aa115beb..1016cb1d305 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -DCPP1Y
void missing_lambda_declarator() {
[](){}();
@@ -18,7 +18,7 @@ void infer_void_return_type(int i) {
switch (x) {
case 0: return get<void>();
case 1: return;
- case 2: return { 1, 2.0 }; // expected-error{{cannot deduce lambda return type from initializer list}}
+ case 2: return { 1, 2.0 }; //expected-error{{cannot deduce}}
}
}(7);
}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
new file mode 100644
index 00000000000..c1311617efb
--- /dev/null
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y -emit-llvm
+
+namespace test_factorial {
+
+auto Fact = [](auto Self, unsigned n) -> unsigned {
+ return !n ? 1 : Self(Self, n - 1) * n;
+};
+
+auto six = Fact(Fact, 3);
+
+}
+
+namespace overload_generic_lambda {
+ template <class F1, class F2> struct overload : F1, F2 {
+ using F1::operator();
+ using F2::operator();
+ overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
+ };
+
+ auto NumParams = [](auto Self, auto h, auto ... rest) -> unsigned {
+ return 1 + Self(Self, rest...);
+ };
+ auto Base = [](auto Self, auto h) -> unsigned {
+ return 1;
+ };
+ overload<decltype(Base), decltype(NumParams)> O(Base, NumParams);
+ int num_params = O(O, 5, 3, "abc", 3.14, 'a');
+}
+
+
+namespace overload_generic_lambda_return_type_deduction {
+ template <class F1, class F2> struct overload : F1, F2 {
+ using F1::operator();
+ using F2::operator();
+ overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
+ };
+
+ auto NumParams = [](auto Self, auto h, auto ... rest) {
+ return 1 + Self(Self, rest...);
+ };
+ auto Base = [](auto Self, auto h) {
+ return 1;
+ };
+ overload<decltype(Base), decltype(NumParams)> O(Base, NumParams);
+ int num_params = O(O, 5, 3, "abc", 3.14, 'a');
+}
+
+namespace test_standard_p5 {
+// FIXME: This test should eventually compile without an explicit trailing return type
+auto glambda = [](auto a, auto&& b) ->bool { return a < b; };
+bool b = glambda(3, 3.14); // OK
+
+}
+namespace test_deduction_failure {
+ int test() {
+ auto g = [](auto *a) { //expected-note{{candidate template ignored}}
+ return a;
+ };
+ struct X { };
+ X *x;
+ g(x);
+ g(3); //expected-error{{no matching function}}
+ return 0;
+ }
+
+}
+
+namespace test_instantiation_or_sfinae_failure {
+int test2() {
+ {
+ auto L = [](auto *a) {
+ return (*a)(a); }; //expected-error{{called object type 'double' is not a function}}
+ //l(&l);
+ double d;
+ L(&d); //expected-note{{in instantiation of}}
+ auto M = [](auto b) { return b; };
+ L(&M); // ok
+ }
+ {
+ auto L = [](auto *a) ->decltype (a->foo()) { //expected-note2{{candidate template ignored:}}
+ return (*a)(a); };
+ //l(&l);
+ double d;
+ L(&d); //expected-error{{no matching function for call}}
+ auto M = [](auto b) { return b; };
+ L(&M); //expected-error{{no matching function for call}}
+
+ }
+ return 0;
+}
+
+
+}
+
+namespace test_misc {
+auto GL = [](auto a, decltype(a) b) //expected-note{{candidate function}}
+ -> int { return a + b; };
+
+void test() {
+ struct X { };
+ GL(3, X{}); //expected-error{{no matching function}}
+}
+
+void test2() {
+ auto l = [](auto *a) -> int {
+ (*a)(a); return 0; }; //expected-error{{called object type 'double' is not a function}}
+ l(&l);
+ double d;
+ l(&d); //expected-note{{in instantiation of}}
+}
+
+}
+
+namespace nested_lambdas {
+ int test() {
+ auto L = [](auto a) {
+ return [=](auto b) { //expected-error{{unimplemented}}
+ return a + b;
+ };
+ };
+ // auto M = L(3.14);
+ // return M('4');
+ }
+ auto get_lambda() {
+ return [](auto a) {
+ return a;
+ };
+ };
+
+ int test2() {
+ auto L = get_lambda();
+ L(3);
+ }
+}
+
OpenPOWER on IntegriCloud