forked from OSchip/llvm-project
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:
parent
da68efdb68
commit
fd5277c063
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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<
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) &&
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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++];
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 ()'}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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}}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue