diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f1ccee2e37250683a485ed982d0330e012761e4d..b0205426750e130e992f7ba79e41c018b909aac7 100644 --- a/include/clang/AST/ASTContext.h +++ b/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/include/clang/AST/ASTLambda.h b/include/clang/AST/ASTLambda.h new file mode 100644 index 0000000000000000000000000000000000000000..814beb34e177b9812f69aa8c1ff8f5c601c3161d --- /dev/null +++ b/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/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index f8f2e41fe62966048075adcf442ac56a765100c8..3c970059eb556de6a798636aa789f2e21cb62c7d 100644 --- a/include/clang/AST/DeclCXX.h +++ b/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/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index c39d29f80e1e88177d8d6cbc9fa4749ba1835d3f..a8949fe18b1c88f60f126022e2c05399015eec4c 100644 --- a/include/clang/AST/ExprCXX.h +++ b/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/include/clang/AST/Type.h b/include/clang/AST/Type.h index 8df030c842f51c7e82ae9d212d985f408242f660..fb829e4d41039a95ef9a83b095a44bdb6050e050 100644 --- a/include/clang/AST/Type.h +++ b/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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2ac197fd520610f67b5c1cac74ab09d6ba16151b..82a36c690c669eeed55c9a42633e68459d94b8c5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 5924a15b7e4ff793cfc9917ed1e7f0eae2fb3ae4..dfb79325f251b5b6b480a43fcb80106f5888fd28 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/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/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index bc49dcda66d1ba8f476dd72cbc28b01e676620b4..4853f46f5f8615c4286935324f4c10b8c79ad3b6 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/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/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f54561528d5c6d0f7c3434ca9821f393b0e22aa7..56988b1d5704c7fa71dbdac961f5ac205501c72d 100644 --- a/include/clang/Sema/Sema.h +++ b/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/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 1f9a4dce55ba278534e9655ffd0ef2146754c1f4..bdadbeddbafddbc69e631d35bf64ad4d5ccd2263 100644 --- a/lib/AST/ASTDumper.cpp +++ b/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/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 922172701f0a2d42223d3ecc2649cec0b38e7ffa..c6edc7712036655d59855954b3833ac5826ec7ed 100644 --- a/lib/AST/ASTImporter.cpp +++ b/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/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 337ca6629c9aa5814ad9f0168b56703fe69f5d71..09ab8c916abd7dedec4dccdd52a190f1bb744476 100644 --- a/lib/AST/DeclCXX.cpp +++ b/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/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 55589e6d21f92d32146ad8fa6457a1b615a68046..7478678bf0b13f685d66d2ca3831c6dcd18f7661 100644 --- a/lib/AST/ExprCXX.cpp +++ b/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/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index c9279a27f1170f783f5c3cf01ee99e67b7994f77..b66a849284042c4d5df2bcef7010eef7d39e0701 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a1a796de4140072d6280e6f1d807a7abc13525b1..b71cced3536b30e43b704e3aaf4cb91cd4e297c7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 9ac6d435067566749fdf9194e4d32e0ba6028c29..2eace9fc74fcb2750fa9491c1c8c287405b8abfe 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 00f38bfa8c6b70f577aab193a01d7d8da6ccd903..6f2b30953260f081ef835398dd7f404de9fff05c 100644 --- a/lib/Sema/Sema.cpp +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fa51aa4c09fd5b2b599915411506145e28de38e6..5997abe029636b27e18b66ada248f10bb7bca377 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index d5c0e7a570805c082158b8a751f77ced372fbb22..6e1751aebd931df993730c8a5b850c7f529df7a0 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/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/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index ec69ef8ed0afa6f81bc7b45b9b8286ee1485dd81..569bfdfce22173527933f1699d950bd2d2f24729 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/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/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 13d19b6cb98524cf3c2858355ffdcf01b543ca6e..6905ff1464c6df67c9b16838fe6e75b3f95fde7b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/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/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 1d52709341ec07a9157cb17230bcbaa346a5221f..5510bc2040b7f2e8a3ab04f42615596cf67f67c7 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 1f40eb8d1dbef031f8185c6befd83ddf5f281134..839ca7eca7c5a08c0960c1ae5cd2fb6dc3ea5449 100644 --- a/lib/Sema/SemaType.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5d080f9efb780b82052e64df1287c34fae69e263..6559dede1c9415a514e7394278e8ed06246ae5e9 100644 --- a/lib/Sema/TreeTransform.h +++ b/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/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 0d8e05711eedf482152142b3bfd384a5f93534d9..eaa5c5500bedfc61708843bcfc6a85d6fa6cbcab 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/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/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 409c9a18a50920f3dd64c141ee78370ca051e21f..1826ad8312f49519c3a0fffe57201f0f9107e3ac 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/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/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65b085bcec13fc65bf1341224811ea5b69fde2fd --- /dev/null +++ b/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/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd773b427812b3c35ab7196c3e7221926c4c274a --- /dev/null +++ b/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/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44656a37e31d3448adf7be242e022874078b4361 --- /dev/null +++ b/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/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp index 79ee76f02582675c3facd2c57c9bceb5e9f8f4da..f8461335b76896ecfee15a240cf3a8926caa8ed5 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp +++ b/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/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp index c69aa115beb5e710d8dd2b460c4feaf9e2029d0e..1016cb1d3056c8c2337d24d177606f18414368be 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/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/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1311617efb78d2cf8683bbb33e43d3ce38679bd --- /dev/null +++ b/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); + } +} +