Implement a rudimentary form of generic lambdas.

Specifically, the following features are not included in this commit:
  - any sort of capturing within generic lambdas 
  - nested lambdas
  - conversion operator for captureless lambdas
  - ensuring all visitors are generic lambda aware


As an example of what compiles:

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 Recursive = [](auto Self, auto h, auto ... rest) {
    return 1 + Self(Self, rest...);
  };
  auto Base = [](auto Self, auto h) {
      return 1;
  };
  overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
  int num_params =  O(O, 5, 3, "abc", 3.14, 'a');

Please see attached tests for more examples.

Some implementation notes:

  - Add a new Declarator context => LambdaExprParameterContext to 
    clang::Declarator to allow the use of 'auto' in declaring generic
    lambda parameters
    
  - Augment AutoType's constructor (similar to how variadic 
    template-type-parameters ala TemplateTypeParmDecl are implemented) to 
    accept an IsParameterPack to encode a generic lambda parameter pack.
  
  - Add various helpers to CXXRecordDecl to facilitate identifying
    and querying a closure class
  
  - LambdaScopeInfo (which maintains the current lambda's Sema state)
    was augmented to house the current depth of the template being
    parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
    so that Sema::ActOnLambdaAutoParameter may use it to create the 
    appropriate list of corresponding TemplateTypeParmDecl for each
    auto parameter identified within the generic lambda (also stored
    within the current LambdaScopeInfo).  Additionally, 
    a TemplateParameterList data-member was added to hold the invented
    TemplateParameterList AST node which will be much more useful
    once we teach TreeTransform how to transform generic lambdas.
    
  - SemaLambda.h was added to hold some common lambda utility
    functions (this file is likely to grow ...)
    
  - Teach Sema::ActOnStartOfFunctionDef to check whether it
    is being called to instantiate a generic lambda's call
    operator, and if so, push an appropriately prepared
    LambdaScopeInfo object on the stack.
    
  - Teach Sema::ActOnStartOfLambdaDefinition to set the
    return type of a lambda without a trailing return type
    to 'auto' in C++1y mode, and teach the return type
    deduction machinery in SemaStmt.cpp to process either
    C++11 and C++14 lambda's correctly depending on the flag.    

  - various tests were added - but much more will be needed.

A greatful thanks to all reviewers including Eli Friedman,  
James Dennett and the ever illuminating Richard Smith.  And 
yet I am certain that I have allowed unidentified bugs to creep in; 
bugs, that I will do my best to slay, once identified!

Thanks!

llvm-svn: 188977
This commit is contained in:
Faisal Vali 2013-08-22 01:49:11 +00:00
parent da68efdb68
commit fd5277c063
36 changed files with 929 additions and 148 deletions

View File

@ -1115,7 +1115,7 @@ public:
/// \brief C++11 deduced auto type. /// \brief C++11 deduced auto type.
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto, QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
bool IsDependent = false) const; bool IsDependent, bool IsParameterPack) const;
/// \brief C++11 deduction pattern for 'auto' type. /// \brief C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const; QualType getAutoDeductType() const;

View File

@ -516,8 +516,8 @@ class CXXRecordDecl : public RecordDecl {
LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent) LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent)
: DefinitionData(D), Dependent(Dependent), NumCaptures(0), : DefinitionData(D), Dependent(Dependent), NumCaptures(0),
NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0), NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0),
MethodTyInfo(Info) Captures(0), MethodTyInfo(Info), TheLambdaExpr(0)
{ {
IsLambda = true; IsLambda = true;
} }
@ -529,7 +529,7 @@ class CXXRecordDecl : public RecordDecl {
/// within the default argument of a function template, because the /// within the default argument of a function template, because the
/// lambda will have been created with the enclosing context as its /// lambda will have been created with the enclosing context as its
/// declaration context, rather than function. This is an unfortunate /// 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; unsigned Dependent : 1;
/// \brief The number of captures in this lambda. /// \brief The number of captures in this lambda.
@ -554,6 +554,10 @@ class CXXRecordDecl : public RecordDecl {
/// \brief The type of the call method. /// \brief The type of the call method.
TypeSourceInfo *MethodTyInfo; TypeSourceInfo *MethodTyInfo;
/// \brief The AST node of the lambda expression.
LambdaExpr *TheLambdaExpr;
}; };
struct DefinitionData &data() { struct DefinitionData &data() {
@ -989,6 +993,36 @@ public:
/// \brief Determine whether this class describes a lambda function object. /// \brief Determine whether this class describes a lambda function object.
bool isLambda() const { return hasDefinition() && data().IsLambda; } 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 /// \brief For a closure type, retrieve the mapping from captured
/// variables and \c this to the non-static data members that store the /// variables and \c this to the non-static data members that store the
/// values or references of the captures. /// values or references of the captures.

View File

@ -1605,6 +1605,13 @@ public:
/// lambda expression. /// lambda expression.
CXXMethodDecl *getCallOperator() const; 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. /// \brief Retrieve the body of the lambda.
CompoundStmt *getBody() const; CompoundStmt *getBody() const;

View File

@ -3614,10 +3614,11 @@ public:
/// is no deduced type and an auto type is canonical. In the latter case, it is /// is no deduced type and an auto type is canonical. In the latter case, it is
/// also a dependent type. /// also a dependent type.
class AutoType : public Type, public llvm::FoldingSetNode { class AutoType : public Type, public llvm::FoldingSetNode {
AutoType(QualType DeducedType, bool IsDecltypeAuto, bool IsDependent) AutoType(QualType DeducedType, bool IsDecltypeAuto,
bool IsDependent, bool IsParameterPack)
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) { /*VariablyModified=*/false, /*ContainsParameterPack=*/IsParameterPack) {
assert((DeducedType.isNull() || !IsDependent) && assert((DeducedType.isNull() || !IsDependent) &&
"auto deduced to dependent type"); "auto deduced to dependent type");
AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto; AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
@ -3641,14 +3642,17 @@ public:
} }
void Profile(llvm::FoldingSetNodeID &ID) { void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getDeducedType(), isDecltypeAuto(), isDependentType()); Profile(ID, getDeducedType(), isDecltypeAuto(),
isDependentType(), containsUnexpandedParameterPack());
} }
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
bool IsDecltypeAuto, bool IsDependent) { bool IsDecltypeAuto, bool IsDependent,
bool IsParameterPack) {
ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddPointer(Deduced.getAsOpaquePtr());
ID.AddBoolean(IsDecltypeAuto); ID.AddBoolean(IsDecltypeAuto);
ID.AddBoolean(IsDependent); ID.AddBoolean(IsDependent);
ID.AddBoolean(IsParameterPack);
} }
static bool classof(const Type *T) { static bool classof(const Type *T) {

View File

@ -5050,6 +5050,10 @@ let CategoryName = "Lambda Issue" in {
"cannot deduce type for lambda capture %0 from initializer list">; "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< def err_return_in_captured_stmt : Error<
"cannot return from %0">; "cannot return from %0">;
def err_capture_block_variable : Error< def err_capture_block_variable : Error<

View File

@ -1502,6 +1502,7 @@ public:
ObjCCatchContext, // Objective-C catch exception-declaration ObjCCatchContext, // Objective-C catch exception-declaration
BlockLiteralContext, // Block literal declarator. BlockLiteralContext, // Block literal declarator.
LambdaExprContext, // Lambda-expression declarator. LambdaExprContext, // Lambda-expression declarator.
LambdaExprParameterContext, // Lambda-expression parameter declarator.
ConversionIdContext, // C++ conversion-type-id. ConversionIdContext, // C++ conversion-type-id.
TrailingReturnContext, // C++11 trailing-type-specifier. TrailingReturnContext, // C++11 trailing-type-specifier.
TemplateTypeArgContext, // Template type argument. TemplateTypeArgContext, // Template type argument.
@ -1577,7 +1578,6 @@ public:
~Declarator() { ~Declarator() {
clear(); clear();
} }
/// getDeclSpec - Return the declaration-specifier that this declarator was /// getDeclSpec - Return the declaration-specifier that this declarator was
/// declared with. /// declared with.
const DeclSpec &getDeclSpec() const { return DS; } const DeclSpec &getDeclSpec() const { return DS; }
@ -1606,7 +1606,8 @@ public:
bool isPrototypeContext() const { bool isPrototypeContext() const {
return (Context == PrototypeContext || return (Context == PrototypeContext ||
Context == ObjCParameterContext || Context == ObjCParameterContext ||
Context == ObjCResultContext); Context == ObjCResultContext ||
Context == LambdaExprParameterContext);
} }
/// \brief Get the source range that spans this declarator. /// \brief Get the source range that spans this declarator.
@ -1670,6 +1671,7 @@ public:
case AliasDeclContext: case AliasDeclContext:
case AliasTemplateContext: case AliasTemplateContext:
case PrototypeContext: case PrototypeContext:
case LambdaExprParameterContext:
case ObjCParameterContext: case ObjCParameterContext:
case ObjCResultContext: case ObjCResultContext:
case TemplateParamContext: case TemplateParamContext:
@ -1698,6 +1700,7 @@ public:
case ForContext: case ForContext:
case ConditionContext: case ConditionContext:
case PrototypeContext: case PrototypeContext:
case LambdaExprParameterContext:
case TemplateParamContext: case TemplateParamContext:
case CXXCatchContext: case CXXCatchContext:
case ObjCCatchContext: case ObjCCatchContext:
@ -1730,6 +1733,7 @@ public:
case ForContext: case ForContext:
case ConditionContext: case ConditionContext:
case PrototypeContext: case PrototypeContext:
case LambdaExprParameterContext:
case TemplateParamContext: case TemplateParamContext:
case CXXCatchContext: case CXXCatchContext:
case ObjCCatchContext: case ObjCCatchContext:
@ -1782,6 +1786,7 @@ public:
case KNRTypeListContext: case KNRTypeListContext:
case MemberContext: case MemberContext:
case PrototypeContext: case PrototypeContext:
case LambdaExprParameterContext:
case ObjCParameterContext: case ObjCParameterContext:
case ObjCResultContext: case ObjCResultContext:
case TemplateParamContext: case TemplateParamContext:
@ -1968,6 +1973,7 @@ public:
case AliasDeclContext: case AliasDeclContext:
case AliasTemplateContext: case AliasTemplateContext:
case PrototypeContext: case PrototypeContext:
case LambdaExprParameterContext:
case ObjCParameterContext: case ObjCParameterContext:
case ObjCResultContext: case ObjCResultContext:
case TemplateParamContext: case TemplateParamContext:

View File

@ -35,6 +35,8 @@ class LabelDecl;
class ReturnStmt; class ReturnStmt;
class Scope; class Scope;
class SwitchStmt; class SwitchStmt;
class TemplateTypeParmDecl;
class TemplateParameterList;
class VarDecl; class VarDecl;
class DeclRefExpr; class DeclRefExpr;
class ObjCIvarRefExpr; class ObjCIvarRefExpr;
@ -613,12 +615,27 @@ public:
/// \brief Offsets into the ArrayIndexVars array at which each capture starts /// \brief Offsets into the ArrayIndexVars array at which each capture starts
/// its list of array index variables. /// its list of array index variables.
SmallVector<unsigned, 4> ArrayIndexStarts; SmallVector<unsigned, 4> ArrayIndexStarts;
/// \brief If this is a generic lambda, use this as the depth of
/// each 'auto' parameter, during initial AST construction.
unsigned AutoTemplateParameterDepth;
LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda, // If this is a generic lambda, store the list of the auto
CXXMethodDecl *CallOperator) // parameters converted into TemplateTypeParmDecls into a vector
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda), // that can be used to construct the generic lambda's template
CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false), // parameter list, during initial AST construction.
ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false) /// \brief Store the list of the auto parameters for a generic lambda.
SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
// If this is a generic lambda, store its template parameter list.
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; Kind = SK_Lambda;
} }
@ -631,8 +648,10 @@ public:
} }
static bool classof(const FunctionScopeInfo *FSI) { static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Lambda; return FSI->Kind == SK_Lambda;
} }
}; };

View File

@ -969,7 +969,13 @@ public:
void PushFunctionScope(); void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block); void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator); void PushLambdaScope();
// 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, void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD,
RecordDecl *RD, RecordDecl *RD,
CapturedRegionKind K); CapturedRegionKind K);
@ -996,9 +1002,12 @@ public:
/// \brief Retrieve the current block, if any. /// \brief Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock(); sema::BlockScopeInfo *getCurBlock();
/// \brief Retrieve the current lambda expression, if any. /// \brief Retrieve the current lambda scope info, if any.
sema::LambdaScopeInfo *getCurLambda(); sema::LambdaScopeInfo *getCurLambda();
/// \brief Retrieve the current generic lambda info, if any.
sema::LambdaScopeInfo *getCurGenericLambda();
/// \brief Retrieve the current captured region, if any. /// \brief Retrieve the current captured region, if any.
sema::CapturedRegionScopeInfo *getCurCapturedRegion(); sema::CapturedRegionScopeInfo *getCurCapturedRegion();
@ -4402,6 +4411,10 @@ public:
/// initializer for the declaration 'Dcl'. /// initializer for the declaration 'Dcl'.
void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl);
/// \brief Invoked when an auto parameter is parsed
/// in a lambda's parameter declaration clause.
ParmVarDecl *ActOnLambdaAutoParameter(ParmVarDecl *P);
/// \brief Create a new lambda closure type. /// \brief Create a new lambda closure type.
CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
TypeSourceInfo *Info, TypeSourceInfo *Info,
@ -4414,14 +4427,15 @@ public:
SourceLocation EndLoc, SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params); ArrayRef<ParmVarDecl *> Params);
/// \brief Introduce the scope for a lambda expression. /// \brief Endow the lambda scope info with the relevant properties.
sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator, void buildLambdaScope(sema::LambdaScopeInfo *LSI,
SourceRange IntroducerRange, CXXMethodDecl *CallOperator,
LambdaCaptureDefault CaptureDefault, SourceRange IntroducerRange,
SourceLocation CaptureDefaultLoc, LambdaCaptureDefault CaptureDefault,
bool ExplicitParams, SourceLocation CaptureDefaultLoc,
bool ExplicitResultType, bool ExplicitParams,
bool Mutable); bool ExplicitResultType,
bool Mutable);
/// \brief Check and build an init-capture with the specified name and /// \brief Check and build an init-capture with the specified name and
/// initializer. /// initializer.
@ -5806,6 +5820,12 @@ public:
sema::TemplateDeductionInfo &Info, sema::TemplateDeductionInfo &Info,
bool InOverloadResolution = false); 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. /// \brief Result type of DeduceAutoType.
enum DeduceAutoResult { enum DeduceAutoResult {
DAR_Succeeded, DAR_Succeeded,
@ -5817,7 +5837,6 @@ public:
QualType &Result); QualType &Result);
DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer,
QualType &Result); QualType &Result);
QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true); bool Diagnose = true);

View File

@ -0,0 +1,44 @@
//===--- SemaLambda.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
/// Lambdas.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_SEMA_LAMBDA_H
#define LLVM_CLANG_SEMA_LAMBDA_H
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Sema/ScopeInfo.h"
namespace clang {
static inline const char *getLambdaStaticInvokerName() {
return "__invoke";
}
static inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
if (MD) {
CXXRecordDecl *LambdaClass = MD->getParent();
if (LambdaClass && LambdaClass->isGenericLambda()) {
return LambdaClass->getLambdaCallOperator()
== MD->getTemplateInstantiationPattern();
}
}
return false;
}
static inline bool isGenericLambdaCallOperatorSpecialization(Decl *D) {
return isGenericLambdaCallOperatorSpecialization(
dyn_cast<CXXMethodDecl>(D));
}
} // clang
#endif // LLVM_CLANG_SEMA_LAMBDA_H

View File

@ -3649,20 +3649,24 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// deduced to the given type, or to the canonical undeduced 'auto' type, or the
/// canonical deduced-but-dependent 'auto' type. /// canonical deduced-but-dependent 'auto' type.
QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto,
bool IsDependent) const { bool IsDependent, bool IsParameterPack) const {
if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent &&
!IsParameterPack)
return getAutoDeductType(); return getAutoDeductType();
assert(!IsParameterPack || DeducedType.isNull()
&& "Auto parameter pack: auto ... a should always be undeduced!");
// Look in the folding set for an existing type. // Look in the folding set for an existing type.
void *InsertPos = 0; void *InsertPos = 0;
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent,
IsParameterPack);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0); return QualType(AT, 0);
AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType,
IsDecltypeAuto, IsDecltypeAuto,
IsDependent); IsDependent,
IsParameterPack);
Types.push_back(AT); Types.push_back(AT);
if (InsertPos) if (InsertPos)
AutoTypes.InsertNode(AT, InsertPos); AutoTypes.InsertNode(AT, InsertPos);
@ -3702,7 +3706,8 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull()) if (AutoDeductTy.isNull())
AutoDeductTy = QualType( AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false,
/*dependent*/false), /*dependent*/false,
/*IsParameterPack*/false),
0); 0);
return AutoDeductTy; return AutoDeductTy;
} }

View File

@ -1709,7 +1709,9 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return QualType(); return QualType();
} }
return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
/*IsDependent*/false,
T->containsUnexpandedParameterPack());
} }
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {

View File

@ -20,6 +20,7 @@
#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/IdentifierTable.h"
#include "clang/Sema/SemaLambda.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
using namespace clang; using namespace clang;
@ -930,6 +931,40 @@ bool CXXRecordDecl::isCLike() const {
return isPOD() && data().HasOnlyCMembers; 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( void CXXRecordDecl::getCaptureFields(
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
FieldDecl *&ThisCapture) const { FieldDecl *&ThisCapture) const {
@ -947,6 +982,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) { static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T; QualType T;
@ -1493,7 +1536,7 @@ bool CXXMethodDecl::hasInlineBody() const {
bool CXXMethodDecl::isLambdaStaticInvoker() const { bool CXXMethodDecl::isLambdaStaticInvoker() const {
return getParent()->isLambda() && return getParent()->isLambda() &&
getIdentifier() && getIdentifier()->getName() == "__invoke"; getParent()->getLambdaStaticInvoker() == this;
} }

View File

@ -1026,13 +1026,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const {
CXXMethodDecl *LambdaExpr::getCallOperator() const { CXXMethodDecl *LambdaExpr::getCallOperator() const {
CXXRecordDecl *Record = getLambdaClass(); CXXRecordDecl *Record = getLambdaClass();
DeclarationName Name return Record->getLambdaCallOperator();
= Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); }
DeclContext::lookup_result Calls = Record->lookup(Name);
assert(!Calls.empty() && "Missing lambda call operator!"); TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
assert(Calls.size() == 1 && "More than one lambda call operator!"); CXXRecordDecl *Record = getLambdaClass();
CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front()); return Record->getGenericLambdaTemplateParameterList();
return Result;
} }
CompoundStmt *LambdaExpr::getBody() const { CompoundStmt *LambdaExpr::getBody() const {

View File

@ -589,6 +589,10 @@ namespace {
AutoType *VisitAttributedType(const AttributedType *T) { AutoType *VisitAttributedType(const AttributedType *T) {
return Visit(T->getModifiedType()); return Visit(T->getModifiedType());
} }
AutoType *VisitPackExpansionType(const PackExpansionType *T) {
return Visit(T->getPattern());
}
}; };
} }

View File

@ -700,7 +700,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitLambdaToBlockPointerBody(Args); EmitLambdaToBlockPointerBody(Args);
} else if (isa<CXXMethodDecl>(FD) && } else if (isa<CXXMethodDecl>(FD) &&
cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) { 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). // clones the body of the function call operator (but is actually static).
EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD)); EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
} else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) && } else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&

View File

@ -4670,6 +4670,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// as part of the parameter-declaration-clause. // as part of the parameter-declaration-clause.
if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
!((D.getContext() == Declarator::PrototypeContext || !((D.getContext() == Declarator::PrototypeContext ||
D.getContext() == Declarator::LambdaExprParameterContext ||
D.getContext() == Declarator::BlockLiteralContext) && D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) && NextToken().is(tok::r_paren) &&
!D.hasGroupingParens() && !D.hasGroupingParens() &&
@ -4988,7 +4989,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
TypeResult TrailingReturnType; TypeResult TrailingReturnType;
Actions.ActOnStartFunctionDeclarator(); Actions.ActOnStartFunctionDeclarator();
/* LocalEndLoc is the end location for the local FunctionTypeLoc. /* LocalEndLoc is the end location for the local FunctionTypeLoc.
EndLoc is the end location for the function declarator. EndLoc is the end location for the function declarator.
They differ for trailing return types. */ They differ for trailing return types. */
@ -5009,7 +5009,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
EndLoc = RParenLoc; EndLoc = RParenLoc;
} else { } else {
if (Tok.isNot(tok::r_paren)) if (Tok.isNot(tok::r_paren))
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
EllipsisLoc);
else if (RequiresArg) else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute); Diag(Tok, diag::err_argument_required_after_attribute);
@ -5240,7 +5241,6 @@ void Parser::ParseParameterDeclarationClause(
ParsedAttributes &FirstArgAttrs, ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) { SourceLocation &EllipsisLoc) {
while (1) { while (1) {
if (Tok.is(tok::ellipsis)) { if (Tok.is(tok::ellipsis)) {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
@ -5270,16 +5270,21 @@ void Parser::ParseParameterDeclarationClause(
ParseDeclarationSpecifiers(DS); ParseDeclarationSpecifiers(DS);
// Parse the declarator. This is "PrototypeContext", because we must
// accept either 'declarator' or 'abstract-declarator' here. // Parse the declarator. This is "PrototypeContext" or
Declarator ParmDecl(DS, Declarator::PrototypeContext); // "LambdaExprParameterContext", because we must accept either
ParseDeclarator(ParmDecl); // 'declarator' or 'abstract-declarator' here.
Declarator ParmDeclarator(DS,
D.getContext() == Declarator::LambdaExprContext ?
Declarator::LambdaExprParameterContext :
Declarator::PrototypeContext);
ParseDeclarator(ParmDeclarator);
// Parse GNU attributes, if present. // Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDecl); MaybeParseGNUAttributes(ParmDeclarator);
// Remember this parsed parameter in ParamInfo. // Remember this parsed parameter in ParamInfo.
IdentifierInfo *ParmII = ParmDecl.getIdentifier(); IdentifierInfo *ParmII = ParmDeclarator.getIdentifier();
// DefArgToks is used when the parsing of default arguments needs // DefArgToks is used when the parsing of default arguments needs
// to be delayed. // to be delayed.
@ -5287,8 +5292,8 @@ void Parser::ParseParameterDeclarationClause(
// If no parameter was specified, verify that *something* was specified, // If no parameter was specified, verify that *something* was specified,
// otherwise we have a missing type and identifier. // otherwise we have a missing type and identifier.
if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 && if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 &&
ParmDecl.getNumTypeObjects() == 0) { ParmDeclarator.getNumTypeObjects() == 0) {
// Completely missing, emit error. // Completely missing, emit error.
Diag(DSStart, diag::err_missing_param); Diag(DSStart, diag::err_missing_param);
} else { } else {
@ -5297,8 +5302,8 @@ void Parser::ParseParameterDeclarationClause(
// Inform the actions module about the parameter declarator, so it gets // Inform the actions module about the parameter declarator, so it gets
// added to the current scope. // 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 // Parse the default argument, if any. We parse the default
// arguments in all dialects; the semantic analysis in // arguments in all dialects; the semantic analysis in
// ActOnParamDefaultArgument will reject the default argument in // ActOnParamDefaultArgument will reject the default argument in
@ -5359,8 +5364,8 @@ void Parser::ParseParameterDeclarationClause(
} }
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
ParmDecl.getIdentifierLoc(), Param, ParmDeclarator.getIdentifierLoc(),
DefArgToks)); Param, DefArgToks));
} }
// If the next token is a comma, consume it and keep reading arguments. // If the next token is a comma, consume it and keep reading arguments.

View File

@ -20,6 +20,7 @@
#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h" #include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "clang/AST/DeclTemplate.h"
using namespace clang; using namespace clang;
@ -908,12 +909,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
"lambda expression parsing"); "lambda expression parsing");
// FIXME: Call into Actions to add any init-capture declarations to the // FIXME: Call into Actions to add any init-capture declarations to the
// scope while parsing the lambda-declarator and compound-statement. // scope while parsing the lambda-declarator and compound-statement.
// Parse lambda-declarator[opt]. // Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory); DeclSpec DS(AttrFactory);
Declarator D(DS, Declarator::LambdaExprContext); Declarator D(DS, Declarator::LambdaExprContext);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
Actions.PushLambdaScope();
if (Tok.is(tok::l_paren)) { if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this, ParseScope PrototypeScope(this,
@ -931,9 +936,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc; SourceLocation EllipsisLoc;
if (Tok.isNot(tok::r_paren))
if (Tok.isNot(tok::r_paren)) {
sema::LambdaScopeInfo *LSI = Actions.getCurLambda();
if (getLangOpts().CPlusPlus1y)
Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); 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 (getLangOpts().CPlusPlus1y && Actions.getCurGenericLambda())
++CurTemplateDepthTracker;
}
T.consumeClose(); T.consumeClose();
SourceLocation RParenLoc = T.getCloseLocation(); SourceLocation RParenLoc = T.getCloseLocation();
DeclEndLoc = RParenLoc; DeclEndLoc = RParenLoc;

View File

@ -1175,7 +1175,6 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Ask the actions module to compute the type for this declarator. // Ask the actions module to compute the type for this declarator.
Decl *Param = Decl *Param =
Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator);
if (Param && if (Param &&
// A missing identifier has already been diagnosed. // A missing identifier has already been diagnosed.
ParmDeclarator.getIdentifier()) { ParmDeclarator.getIdentifier()) {

View File

@ -1007,10 +1007,17 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block)); BlockScope, Block));
} }
void Sema::PushLambdaScope(CXXRecordDecl *Lambda, void Sema::PushLambdaScope() {
CXXMethodDecl *CallOperator) { FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics()));
FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda, }
CallOperator));
void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
if (LambdaScopeInfo *const LSI = getCurLambda()) {
LSI->AutoTemplateParameterDepth = Depth;
return;
}
assert(false &&
"Remove assertion if intentionally called in a non-lambda context.");
} }
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
@ -1066,6 +1073,16 @@ LambdaScopeInfo *Sema::getCurLambda() {
return dyn_cast<LambdaScopeInfo>(FunctionScopes.back()); 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) { void Sema::ActOnComment(SourceRange Comment) {
if (!LangOpts.RetainCommentsFromSystemHeaders && if (!LangOpts.RetainCommentsFromSystemHeaders &&

View File

@ -35,6 +35,7 @@
#include "clang/Sema/DeclSpec.h" #include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h" #include "clang/Sema/Initialization.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/Lookup.h" #include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h" #include "clang/Sema/Scope.h"
@ -8909,6 +8910,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec(); const DeclSpec &DS = D.getDeclSpec();
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
// C++03 [dcl.stc]p2 also permits 'auto'. // C++03 [dcl.stc]p2 also permits 'auto'.
VarDecl::StorageClass StorageClass = SC_None; VarDecl::StorageClass StorageClass = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
@ -9015,6 +9017,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (New->hasAttr<BlocksAttr>()) { if (New->hasAttr<BlocksAttr>()) {
Diag(New->getLocation(), diag::err_block_on_nonlocal); Diag(New->getLocation(), diag::err_block_on_nonlocal);
} }
// Handle 'auto' within a generic lambda.
QualType ParamType = New->getType();
if (getLangOpts().CPlusPlus1y && ParamType->getContainedAutoType()) {
assert(getCurLambda() &&
"'auto' in parameter type only allowed in lambdas!");
New = ActOnLambdaAutoParameter(New);
}
return New; return New;
} }
@ -9268,9 +9278,38 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
FD = FunTmpl->getTemplatedDecl(); FD = FunTmpl->getTemplatedDecl();
else else
FD = cast<FunctionDecl>(D); FD = cast<FunctionDecl>(D);
// 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 (getLangOpts().CPlusPlus1y
&& 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();
// Enter a new function scope if (LE->getCaptureDefault() == LCD_None)
PushFunctionScope(); 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. // See if this is a redefinition.
if (!FD->isLateTemplateParsed()) if (!FD->isLateTemplateParsed())

View File

@ -32,6 +32,7 @@
#include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/DeclSpec.h" #include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h" #include "clang/Sema/Initialization.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/Lookup.h" #include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h" #include "clang/Sema/Scope.h"
@ -10015,29 +10016,27 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SourceLocation CurrentLocation, SourceLocation CurrentLocation,
CXXConversionDecl *Conv) CXXConversionDecl *Conv)
{ {
CXXRecordDecl *Lambda = Conv->getParent(); CXXRecordDecl *LambdaClass = Conv->getParent();
// Make sure that the lambda call operator is marked used. // Make sure that the lambda call operator is marked used.
markLambdaCallOperatorUsed(*this, Lambda); markLambdaCallOperatorUsed(*this, LambdaClass);
Conv->setUsed(); Conv->setUsed();
SynthesizedFunctionScope Scope(*this, Conv); SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags); DiagnosticErrorTrap Trap(Diags);
// Return the address of the __invoke function. CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();
DeclarationName InvokeName = &Context.Idents.get("__invoke");
CXXMethodDecl *Invoke
= cast<CXXMethodDecl>(Lambda->lookup(InvokeName).front());
Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(), Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
VK_LValue, Conv->getLocation()).take(); 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(); Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
Conv->setBody(new (Context) CompoundStmt(Context, Return, Conv->setBody(new (Context) CompoundStmt(Context, Return,
Conv->getLocation(), Conv->getLocation(),
Conv->getLocation())); Conv->getLocation()));
// Fill in the __invoke function with a dummy implementation. IR generation // Fill in the invoke function with a dummy implementation. IR generation
// will fill in the actual details. // will fill in the actual details.
Invoke->setUsed(); Invoke->setUsed();
Invoke->setReferenced(); Invoke->setReferenced();

View File

@ -14,6 +14,7 @@
#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprCXX.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h" #include "clang/Sema/Initialization.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/Lookup.h" #include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h" #include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/ScopeInfo.h"
@ -120,11 +121,69 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
llvm_unreachable("unexpected context"); llvm_unreachable("unexpected context");
} }
ParmVarDecl *Sema::ActOnLambdaAutoParameter(ParmVarDecl *PVD) {
LambdaScopeInfo *LSI = getCurLambda();
assert(LSI && "No LambdaScopeInfo on the stack!");
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
// Invent a template type parameter corresponding to the auto
// containing parameter.
TemplateTypeParmDecl *TemplateParam =
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(),
SourceLocation(),
PVD->getLocation(),
TemplateParameterDepth,
AutoParameterPosition, // our template param index
/* Identifier*/ 0, false, PVD->isParameterPack());
LSI->AutoTemplateParams.push_back(TemplateParam);
QualType AutoTy = PVD->getType();
// Now replace the 'auto' in the function parameter with this invented
// template type parameter.
QualType TemplParamType = QualType(TemplateParam->getTypeForDecl(), 0);
TypeSourceInfo *AutoTSI = PVD->getTypeSourceInfo();
TypeSourceInfo *NewTSI = SubstAutoTypeSourceInfo(AutoTSI, TemplParamType);
PVD->setType(NewTSI->getType());
PVD->setTypeSourceInfo(NewTSI);
return PVD;
}
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, CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange, SourceRange IntroducerRange,
TypeSourceInfo *MethodType, TypeSourceInfo *MethodType,
SourceLocation EndLoc, SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params) { ArrayRef<ParmVarDecl *> Params) {
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
// C++11 [expr.prim.lambda]p5: // C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function // The closure type for a lambda-expression has a public inline function
// call operator (13.5.4) whose parameters and return type are described by // call operator (13.5.4) whose parameters and return type are described by
@ -152,6 +211,17 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// Temporarily set the lexical declaration context to the current // Temporarily set the lexical declaration context to the current
// context, so that the Scope stack matches the lexical nesting. // context, so that the Scope stack matches the lexical nesting.
Method->setLexicalDeclContext(CurContext); 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. // Add parameters.
if (!Params.empty()) { if (!Params.empty()) {
@ -177,15 +247,16 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
return Method; return Method;
} }
LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator, void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
CXXMethodDecl *CallOperator,
SourceRange IntroducerRange, SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault, LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc, SourceLocation CaptureDefaultLoc,
bool ExplicitParams, bool ExplicitParams,
bool ExplicitResultType, bool ExplicitResultType,
bool Mutable) { bool Mutable) {
PushLambdaScope(CallOperator->getParent(), CallOperator); LSI->CallOperator = CallOperator;
LambdaScopeInfo *LSI = getCurLambda(); LSI->Lambda = CallOperator->getParent();
if (CaptureDefault == LCD_ByCopy) if (CaptureDefault == LCD_ByCopy)
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
else if (CaptureDefault == LCD_ByRef) else if (CaptureDefault == LCD_ByRef)
@ -208,8 +279,6 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
} else { } else {
LSI->HasImplicitReturnType = true; LSI->HasImplicitReturnType = true;
} }
return LSI;
} }
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
@ -358,7 +427,7 @@ static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
} }
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType); assert(CSI.HasImplicitReturnType || CSI.ReturnType->isUndeducedType());
// C++ Core Issue #975, proposed resolution: // C++ Core Issue #975, proposed resolution:
// If a lambda-expression does not include a trailing-return-type, // If a lambda-expression does not include a trailing-return-type,
@ -392,7 +461,7 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
// Second case: at least one return statement has dependent type. // Second case: at least one return statement has dependent type.
// Delay type checking until instantiation. // Delay type checking until instantiation.
assert(!CSI.ReturnType.isNull() && "We should have a tentative return type."); assert(!CSI.ReturnType.isNull() && "We should have a tentative return type.");
if (CSI.ReturnType->isDependentType()) if (CSI.ReturnType->isDependentType() || CSI.ReturnType->isUndeducedType())
return; return;
// Try to apply the enum-fuzz rule. // Try to apply the enum-fuzz rule.
@ -519,15 +588,25 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
} }
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo, Declarator &ParamInfo, Scope *CurScope) {
Scope *CurScope) {
// Determine if we're within a context where we know that the lambda will // Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope. // be dependent, because there are template parameters in scope.
bool KnownDependent = false; bool KnownDependent = false;
if (Scope *TmplScope = CurScope->getTemplateParamParent()) LambdaScopeInfo *const LSI = getCurLambda();
if (!TmplScope->decl_empty()) 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; KnownDependent = true;
}
// Determine the signature of the call operator. // Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo; TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true; bool ExplicitParams = true;
@ -542,7 +621,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
FunctionProtoType::ExtProtoInfo EPI; FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = true; EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const; EPI.TypeQuals |= DeclSpec::TQ_const;
QualType MethodTy = Context.getFunctionType(Context.DependentTy, None, // For C++1y, use the new return type deduction machinery, by imaginging
// 'auto' if no trailing return type.
QualType DefaultTypeForNoTrailingReturn = getLangOpts().CPlusPlus1y ?
Context.getAutoDeductType() : Context.DependentTy;
QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn, None,
EPI); EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false; ExplicitParams = false;
@ -560,14 +643,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (!FTI.hasMutableQualifier()) if (!FTI.hasMutableQualifier())
FTI.TypeQuals |= DeclSpec::TQ_const; FTI.TypeQuals |= DeclSpec::TQ_const;
ExplicitResultType = FTI.hasTrailingReturnType();
// In C++11 if there is no explicit return type, the return type is
// artificially set to DependentTy, whereas in C++1y it is set to AutoTy
// (through ConvertDeclSpecToType) which allows us to support both
// C++11 and C++1y return type deduction semantics.
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
assert(MethodTyInfo && "no type from lambda-declarator"); assert(MethodTyInfo && "no type from lambda-declarator");
EndLoc = ParamInfo.getSourceRange().getEnd(); EndLoc = ParamInfo.getSourceRange().getEnd();
ExplicitResultType
= MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
!= Context.DependentTy;
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
// Empty arg list, don't push any params. // Empty arg list, don't push any params.
@ -588,7 +672,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params); MethodTyInfo, EndLoc, Params);
if (ExplicitParams) if (ExplicitParams)
CheckCXXDefaultArguments(Method); CheckCXXDefaultArguments(Method);
@ -598,9 +681,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Introduce the function call operator as the current declaration context. // Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method); PushDeclContext(CurScope, Method);
// Introduce the lambda scope. // Build the lambda scope.
LambdaScopeInfo *LSI buildLambdaScope(LSI, Method,
= enterLambdaScope(Method,
Intro.Range, Intro.Range,
Intro.Default, Intro.DefaultLoc, Intro.Default, Intro.DefaultLoc,
ExplicitParams, ExplicitParams,
@ -812,6 +894,8 @@ static void addFunctionPointerConversion(Sema &S,
SourceRange IntroducerRange, SourceRange IntroducerRange,
CXXRecordDecl *Class, CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) { CXXMethodDecl *CallOperator) {
// FIXME: The conversion operator needs to be fixed for generic lambdas.
if (Class->isGenericLambda()) return;
// Add the conversion to function pointer. // Add the conversion to function pointer.
const FunctionProtoType *Proto const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>(); = CallOperator->getType()->getAs<FunctionProtoType>();
@ -849,10 +933,9 @@ static void addFunctionPointerConversion(Sema &S,
Conversion->setAccess(AS_public); Conversion->setAccess(AS_public);
Conversion->setImplicit(true); Conversion->setImplicit(true);
Class->addDecl(Conversion); Class->addDecl(Conversion);
// Add a non-static member function that will be the result of
// Add a non-static member function "__invoke" that will be the result of // the conversion with a certain unique ID.
// the conversion. Name = &S.Context.Idents.get(getLambdaStaticInvokerName());
Name = &S.Context.Idents.get("__invoke");
CXXMethodDecl *Invoke CXXMethodDecl *Invoke
= CXXMethodDecl::Create(S.Context, Class, Loc, = CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy, DeclarationNameInfo(Name, Loc), FunctionTy,
@ -1000,8 +1083,11 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// If a lambda-expression does not include a // If a lambda-expression does not include a
// trailing-return-type, it is as if the trailing-return-type // trailing-return-type, it is as if the trailing-return-type
// denotes the following type: // denotes the following type:
// Skip for C++1y return type deduction semantics which uses
// different machinery currently.
// FIXME: Refactor and Merge the return type deduction machinery.
// FIXME: Assumes current resolution to core issue 975. // FIXME: Assumes current resolution to core issue 975.
if (LSI->HasImplicitReturnType) { if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus1y) {
deduceClosureReturnType(*LSI); deduceClosureReturnType(*LSI);
// - if there are no return statements in the // - if there are no return statements in the
@ -1019,13 +1105,18 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
LSI->ReturnType, Proto->getArgTypes(), Proto->getExtProtoInfo()); LSI->ReturnType, Proto->getArgTypes(), Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy); CallOperator->setType(FunctionTy);
} }
// C++ [expr.prim.lambda]p7: // C++ [expr.prim.lambda]p7:
// The lambda-expression's compound-statement yields the // The lambda-expression's compound-statement yields the
// function-body (8.4) of the function call operator [...]. // function-body (8.4) of the function call operator [...].
ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
CallOperator->setLexicalDeclContext(Class); CallOperator->setLexicalDeclContext(Class);
Class->addDecl(CallOperator); Decl *TemplateOrNonTemplateCallOperatorDecl =
!CallOperator->getDescribedFunctionTemplate() ? cast<Decl>(CallOperator)
: CallOperator->getDescribedFunctionTemplate();
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
PopExpressionEvaluationContext(); PopExpressionEvaluationContext();
// C++11 [expr.prim.lambda]p6: // C++11 [expr.prim.lambda]p6:
@ -1065,7 +1156,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
CaptureInits, ArrayIndexVars, CaptureInits, ArrayIndexVars,
ArrayIndexStarts, Body->getLocEnd(), ArrayIndexStarts, Body->getLocEnd(),
ContainsUnexpandedParameterPack); ContainsUnexpandedParameterPack);
Class->setLambdaExpr(Lambda);
// C++11 [expr.prim.lambda]p2: // C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand // A lambda-expression shall not appear in an unevaluated operand
// (Clause 5). // (Clause 5).
@ -1085,7 +1176,15 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
break; 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); return MaybeBindToTemporary(Lambda);
} }

View File

@ -8670,6 +8670,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(), S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch) diag::note_ovl_candidate_non_deduced_mismatch)
<< FirstTA << SecondTA; << FirstTA << SecondTA;

View File

@ -2487,12 +2487,31 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// [expr.prim.lambda]p4 in C++11; block literals follow the same rules. // [expr.prim.lambda]p4 in C++11; block literals follow the same rules.
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
QualType FnRetType = CurCap->ReturnType; QualType FnRetType = CurCap->ReturnType;
LambdaScopeInfo *const LambdaSI = getCurLambda();
// For blocks/lambdas with implicit return types, we check each return // In C++1y, an implicit return type behaves as if 'auto' was
// statement individually, and deduce the common return type when the block // the return type.
// or lambda is completed. if (FnRetType.isNull() && getLangOpts().CPlusPlus1y) {
if (CurCap->HasImplicitReturnType) { if (LambdaSI) {
// FIXME: Fold this into the 'auto' codepath below. FunctionDecl *CallOp = LambdaSI->CallOperator;
FnRetType = CallOp->getResultType();
assert(FnRetType->getContainedAutoType());
}
}
// For blocks/lambdas with implicit return types in C++11, we check each
// return statement individually, and deduce the common return type when
// the block or lambda is completed. In C++1y, the return type deduction
// of a lambda is specified in terms of auto.
// Notably, in C++11, we take the type of the expression after decay and
// lvalue-to-rvalue conversion, so a class type can be cv-qualified.
// In C++1y, we perform template argument deduction as if the return
// type were 'auto', so an implicit return type is never cv-qualified.
// i.e if (getLangOpts().CPlusPlus1y && FnRetType.hasQualifiers())
// FnRetType = FnRetType.getUnqualifiedType();
// Return type deduction is unchanged for blocks in C++1y.
// FIXME: Fold this into the 'auto' codepath below.
if (CurCap->HasImplicitReturnType &&
(!LambdaSI || !getLangOpts().CPlusPlus1y)) {
if (RetValExp && !isa<InitListExpr>(RetValExp)) { if (RetValExp && !isa<InitListExpr>(RetValExp)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid()) if (Result.isInvalid())
@ -2500,13 +2519,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
RetValExp = Result.take(); RetValExp = Result.take();
if (!CurContext->isDependentContext()) { if (!CurContext->isDependentContext()) {
FnRetType = RetValExp->getType(); FnRetType = RetValExp->getType();
// In C++11, we take the type of the expression after decay and
// lvalue-to-rvalue conversion, so a class type can be cv-qualified.
// In C++1y, we perform template argument deduction as if the return
// type were 'auto', so an implicit return type is never cv-qualified.
if (getLangOpts().CPlusPlus1y && FnRetType.hasQualifiers())
FnRetType = FnRetType.getUnqualifiedType();
} else } else
FnRetType = CurCap->ReturnType = Context.DependentTy; FnRetType = CurCap->ReturnType = Context.DependentTy;
} else { } else {
@ -2517,7 +2530,6 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, diag::err_lambda_return_init_list) Diag(ReturnLoc, diag::err_lambda_return_init_list)
<< RetValExp->getSourceRange(); << RetValExp->getSourceRange();
} }
FnRetType = Context.VoidTy; FnRetType = Context.VoidTy;
} }
@ -2526,7 +2538,8 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (CurCap->ReturnType.isNull()) if (CurCap->ReturnType.isNull())
CurCap->ReturnType = FnRetType; CurCap->ReturnType = FnRetType;
} else if (AutoType *AT = } else if (AutoType *AT =
FnRetType.isNull() ? 0 : FnRetType->getContainedAutoType()) { (FnRetType.isNull() || !LambdaSI) ? 0
: FnRetType->getContainedAutoType()) {
// In C++1y, the return type may involve 'auto'. // In C++1y, the return type may involve 'auto'.
FunctionDecl *FD = cast<LambdaScopeInfo>(CurCap)->CallOperator; FunctionDecl *FD = cast<LambdaScopeInfo>(CurCap)->CallOperator;
if (CurContext->isDependentContext()) { if (CurContext->isDependentContext()) {
@ -2534,7 +2547,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Return type deduction [...] occurs when the definition is // Return type deduction [...] occurs when the definition is
// instantiated even if the function body contains a return // instantiated even if the function body contains a return
// statement with a non-type-dependent operand. // statement with a non-type-dependent operand.
CurCap->ReturnType = FnRetType = Context.DependentTy; CurCap->ReturnType = FnRetType;
} else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { } else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
FD->setInvalidDecl(); FD->setInvalidDecl();
return StmtError(); return StmtError();
@ -2564,7 +2577,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// pickier with blocks than for normal functions because we don't have GCC // pickier with blocks than for normal functions because we don't have GCC
// compatibility to worry about here. // compatibility to worry about here.
const VarDecl *NRVOCandidate = 0; const VarDecl *NRVOCandidate = 0;
if (FnRetType->isDependentType()) { if (FnRetType->isDependentType() || FnRetType->isUndeducedType()) {
// Delay processing for now. TODO: there are lots of dependent // Delay processing for now. TODO: there are lots of dependent
// types we can conclusively prove aren't void. // types we can conclusively prove aren't void.
} else if (FnRetType->isVoidType()) { } else if (FnRetType->isVoidType()) {
@ -2624,7 +2637,6 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
return Owned(Result); return Owned(Result);
} }
/// Deduce the return type for a function from a returned expression, per /// Deduce the return type for a function from a returned expression, per
/// C++1y [dcl.spec.auto]p6. /// C++1y [dcl.spec.auto]p6.
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
@ -2634,7 +2646,6 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc(). TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc().
IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc(); IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
QualType Deduced; QualType Deduced;
if (RetExpr && isa<InitListExpr>(RetExpr)) { if (RetExpr && isa<InitListExpr>(RetExpr)) {
// If the deduction is for a return statement and the initializer is // If the deduction is for a return statement and the initializer is
// a braced-init-list, the program is ill-formed. // a braced-init-list, the program is ill-formed.
@ -2692,9 +2703,18 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
AutoType *NewAT = Deduced->getContainedAutoType(); AutoType *NewAT = Deduced->getContainedAutoType();
if (!FD->isDependentContext() && if (!FD->isDependentContext() &&
!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { !Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
Diag(ReturnLoc, diag::err_auto_fn_different_deductions) LambdaScopeInfo *const LambdaSI = getCurLambda();
<< (AT->isDecltypeAuto() ? 1 : 0) if (LambdaSI && LambdaSI->HasImplicitReturnType) {
<< NewAT->getDeducedType() << AT->getDeducedType(); Diag(ReturnLoc,
diag::err_typecheck_missing_return_type_incompatible)
<< NewAT->getDeducedType() << AT->getDeducedType()
<< true /*IsLambda*/;
}
else {
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
<< (AT->isDecltypeAuto() ? 1 : 0)
<< NewAT->getDeducedType() << AT->getDeducedType();
}
return true; return true;
} }
} else if (!FD->isInvalidDecl()) { } else if (!FD->isInvalidDecl()) {
@ -2710,10 +2730,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Check for unexpanded parameter packs. // Check for unexpanded parameter packs.
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError(); return StmtError();
if (isa<CapturingScopeInfo>(getCurFunction())) if (isa<CapturingScopeInfo>(getCurFunction()))
return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType; QualType FnRetType;
QualType RelatedRetType; QualType RelatedRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) { if (const FunctionDecl *FD = getCurFunctionDecl()) {

View File

@ -3766,7 +3766,8 @@ namespace {
QualType Result = QualType Result =
SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement,
TL.getTypePtr()->isDecltypeAuto(), TL.getTypePtr()->isDecltypeAuto(),
Dependent); Dependent, TL.getTypePtr()->
containsUnexpandedParameterPack());
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc()); NewTL.setNameLoc(TL.getNameLoc());
return Result; return Result;
@ -3907,8 +3908,16 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
return DAR_Succeeded; return DAR_Succeeded;
} }
QualType Sema::SubstAutoType(QualType Type, QualType Deduced) { QualType Sema::SubstAutoType(QualType TypeWithAuto,
return SubstituteAutoTransform(*this, Deduced).TransformType(Type); 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) { void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {

View File

@ -781,7 +781,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// specified with a trailing return type or inferred. // specified with a trailing return type or inferred.
if (declarator.getContext() == Declarator::LambdaExprContext || if (declarator.getContext() == Declarator::LambdaExprContext ||
isOmittedBlockReturnType(declarator)) { isOmittedBlockReturnType(declarator)) {
Result = Context.DependentTy; // In C++1y (n3690 CD), 5.1.2 [expr.prim.lambda]/4 : The lambda return
// type is auto, which is replaced by the trailing-return-type if
// provided and/or deduced from return statements as described
// in 7.1.6.4.
Result = S.getLangOpts().CPlusPlus1y &&
declarator.getContext() == Declarator::LambdaExprContext
? Context.getAutoDeductType() : Context.DependentTy;
break; break;
} }
@ -1006,11 +1012,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TST_auto: case DeclSpec::TST_auto:
// TypeQuals handled by caller. // TypeQuals handled by caller.
Result = Context.getAutoType(QualType(), /*decltype(auto)*/false); Result = Context.getAutoType(QualType(),
/*decltype(auto)*/false,
/*IsDependent*/ false,
/*IsParameterPack*/ declarator.hasEllipsis());
break; break;
case DeclSpec::TST_decltype_auto: case DeclSpec::TST_decltype_auto:
Result = Context.getAutoType(QualType(), /*decltype(auto)*/true); Result = Context.getAutoType(QualType(),
/*decltype(auto)*/true,
/*IsDependent*/ false,
/*IsParameterPack*/ false);
break; break;
case DeclSpec::TST_unknown_anytype: case DeclSpec::TST_unknown_anytype:
@ -1557,7 +1569,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
ASM = ArrayType::Normal; ASM = ArrayType::Normal;
} }
} else if (!T->isDependentType() && !T->isVariablyModifiedType() && } else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
!T->isIncompleteType()) { !T->isIncompleteType() && !T->isUndeducedType()) {
// Is the array too large? // Is the array too large?
unsigned ActiveSizeBits unsigned ActiveSizeBits
= ConstantArrayType::getNumAddressingBits(Context, T, ConstVal); = ConstantArrayType::getNumAddressingBits(Context, T, ConstVal);
@ -2097,6 +2109,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// In C++11, a function declarator using 'auto' must have a trailing return // 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 // type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless. // using auto, we need to check regardless.
// Generic Lambdas (C++14) allow 'auto' in their parameters.
if (ContainsPlaceholderType && if (ContainsPlaceholderType &&
(!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1; int Error = -1;
@ -2109,7 +2122,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::ObjCParameterContext: case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext: case Declarator::ObjCResultContext:
case Declarator::PrototypeContext: case Declarator::PrototypeContext:
Error = 0; // Function prototype Error = 0;
break;
case Declarator::LambdaExprParameterContext:
if (!(SemaRef.getLangOpts().CPlusPlus1y
&& D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
Error = 0;
break; break;
case Declarator::MemberContext: case Declarator::MemberContext:
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
@ -2189,8 +2207,13 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
AutoRange = D.getName().getSourceRange(); AutoRange = D.getName().getSourceRange();
if (Error != -1) { if (Error != -1) {
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto) {
SemaRef.Diag(AutoRange.getBegin(),
diag::err_decltype_auto_function_declarator_not_declaration);
} else {
SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed) SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed)
<< Error << AutoRange; << Error << AutoRange;
}
T = SemaRef.Context.IntTy; T = SemaRef.Context.IntTy;
D.setInvalidType(true); D.setInvalidType(true);
} else } else
@ -2240,6 +2263,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType(true); D.setInvalidType(true);
break; break;
case Declarator::PrototypeContext: case Declarator::PrototypeContext:
case Declarator::LambdaExprParameterContext:
case Declarator::ObjCParameterContext: case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext: case Declarator::ObjCResultContext:
case Declarator::KNRTypeListContext: case Declarator::KNRTypeListContext:
@ -2613,8 +2637,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} }
} }
} }
const AutoType *AT = T->getContainedAutoType();
if (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 && !(S.getLangOpts().CPlusPlus1y &&
D.getContext() == Declarator::LambdaExprParameterContext)) {
// We've already diagnosed this for decltype(auto). // We've already diagnosed this for decltype(auto).
if (!AT->isDecltypeAuto()) if (!AT->isDecltypeAuto())
S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
@ -3110,6 +3137,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// is a parameter pack (14.5.3). [...] // is a parameter pack (14.5.3). [...]
switch (D.getContext()) { switch (D.getContext()) {
case Declarator::PrototypeContext: case Declarator::PrototypeContext:
case Declarator::LambdaExprParameterContext:
// C++0x [dcl.fct]p13: // C++0x [dcl.fct]p13:
// [...] When it is part of a parameter-declaration-clause, the // [...] When it is part of a parameter-declaration-clause, the
// parameter pack is a function parameter pack (14.5.3). The type T // parameter pack is a function parameter pack (14.5.3). The type T
@ -3128,7 +3156,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getPackExpansionType(T, None); T = Context.getPackExpansionType(T, None);
} }
break; break;
case Declarator::TemplateParamContext: case Declarator::TemplateParamContext:
// C++0x [temp.param]p15: // C++0x [temp.param]p15:
// If a template-parameter is a [...] is a parameter-declaration that // If a template-parameter is a [...] is a parameter-declaration that

View File

@ -782,7 +782,10 @@ public:
// Note, IsDependent is always false here: we implicitly convert an 'auto' // Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so // which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation. // that we'll retry deduction after the transformation.
return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto); // FIXME: Can we assume the same about IsParameterPack?
return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto,
/*IsDependent*/ false,
/*IsParameterPack*/ false);
} }
/// \brief Build a new template specialization type. /// \brief Build a new template specialization type.
@ -3494,7 +3497,9 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
Qs.removeObjCLifetime(); Qs.removeObjCLifetime();
Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
Qs); Qs);
Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto()); Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(),
AutoTy->isDependentType(),
AutoTy->containsUnexpandedParameterPack());
TLB.TypeWasModifiedSafely(Result); TLB.TypeWasModifiedSafely(Result);
} else { } else {
// Otherwise, complain about the addition of a qualifier to an // Otherwise, complain about the addition of a qualifier to an
@ -8193,6 +8198,14 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
template<typename Derived> template<typename Derived>
ExprResult ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { 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)
<< " nested lambdas not implemented yet";
return ExprError();
}
// Transform the type of the lambda parameters and start the definition of // Transform the type of the lambda parameters and start the definition of
// the lambda itself. // the lambda itself.
TypeSourceInfo *MethodTy TypeSourceInfo *MethodTy
@ -8215,7 +8228,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->param_size(), E->getCallOperator()->param_size(),
0, ParamTypes, &Params)) 0, ParamTypes, &Params))
return ExprError(); return ExprError();
getSema().PushLambdaScope();
LambdaScopeInfo *LSI = getSema().getCurLambda();
// TODO: Fix for nested lambdas
LSI->GLTemplateParameterList = 0;
// Build the call operator. // Build the call operator.
CXXMethodDecl *CallOperator CXXMethodDecl *CallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(), = getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
@ -8250,9 +8266,9 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
// Introduce the context of the call operator. // Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), CallOperator); Sema::ContextRAII SavedContext(getSema(), CallOperator);
LambdaScopeInfo *const LSI = getSema().getCurLambda();
// Enter the scope of the lambda. // Enter the scope of the lambda.
sema::LambdaScopeInfo *LSI getSema().buildLambdaScope(LSI, CallOperator, E->getIntroducerRange(),
= getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
E->getCaptureDefault(), E->getCaptureDefault(),
E->getCaptureDefaultLoc(), E->getCaptureDefaultLoc(),
E->hasExplicitParameters(), E->hasExplicitParameters(),

View File

@ -4740,7 +4740,9 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType Deduced = readType(*Loc.F, Record, Idx); QualType Deduced = readType(*Loc.F, Record, Idx);
bool IsDecltypeAuto = Record[Idx++]; bool IsDecltypeAuto = Record[Idx++];
bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); bool IsParameterPack = Record[Idx++];
return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent,
IsParameterPack);
} }
case TYPE_RECORD: { case TYPE_RECORD: {

View File

@ -1201,6 +1201,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
= (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures); = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures; Capture *ToCapture = Lambda.Captures;
Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx); Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx);
Lambda.TheLambdaExpr = cast<LambdaExpr>(Reader.ReadExpr(F));
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
SourceLocation Loc = ReadSourceLocation(Record, Idx); SourceLocation Loc = ReadSourceLocation(Record, Idx);
bool IsImplicit = Record[Idx++]; bool IsImplicit = Record[Idx++];

View File

@ -253,6 +253,7 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Record.push_back(T->isDecltypeAuto()); Record.push_back(T->isDecltypeAuto());
if (T->getDeducedType().isNull()) if (T->getDeducedType().isNull())
Record.push_back(T->isDependentType()); Record.push_back(T->isDependentType());
Record.push_back(T->containsUnexpandedParameterPack());
Code = TYPE_AUTO; Code = TYPE_AUTO;
} }
@ -5136,6 +5137,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Lambda.ManglingNumber); Record.push_back(Lambda.ManglingNumber);
AddDeclRef(Lambda.ContextDecl, Record); AddDeclRef(Lambda.ContextDecl, Record);
AddTypeSourceInfo(Lambda.MethodTyInfo, Record); AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
AddStmt(Lambda.TheLambdaExpr);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
LambdaExpr::Capture &Capture = Lambda.Captures[I]; LambdaExpr::Capture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record); AddSourceLocation(Capture.getLocation(), Record);

View File

@ -0,0 +1,75 @@
// 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 ()'}}
}
}

View File

@ -0,0 +1,50 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -emit-llvm
namespace return_type_deduction_ok {
// FIXME: Once return type deduction is implemented for generic lambdas
// this will need to be updated.
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}}
}
}
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)) {
}
}

View File

@ -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}}
}

View File

@ -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 &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 &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 &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);
}

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify // 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() { void missing_lambda_declarator() {
[](){}(); [](){}();
@ -18,7 +18,7 @@ void infer_void_return_type(int i) {
switch (x) { switch (x) {
case 0: return get<void>(); case 0: return get<void>();
case 1: return; 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); }(7);
} }

View File

@ -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);
}
}