зеркало из https://github.com/microsoft/clang-1.git
Introduce support for template instantiation of lambda
expressions. This is mostly a simple refact, splitting the main "start a lambda expression" function into smaller chunks that are driven either from the parser (Sema::ActOnLambdaExpr) or during AST transformation (TreeTransform::TransformLambdaExpr). A few minor interesting points: - Added new entry points for TreeTransform, so that we can explicitly establish the link between the lambda closure type in the template and the lambda closure type in the instantiation. - Added a bit into LambdaExpr specifying whether it had an explicit result type or not. We should have had this anyway. This code is 'lightly' tested. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150417 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
07e5288c65
Коммит
dfca6f53ab
|
@ -1059,6 +1059,11 @@ class LambdaExpr : public Expr {
|
|||
/// implicit (and empty) parameter list.
|
||||
unsigned ExplicitParams : 1;
|
||||
|
||||
/// \brief Whether this lambda had the result type explicitly specified.
|
||||
unsigned ExplicitResultType : 1;
|
||||
|
||||
/// \brief Whether there are any array index variables stored at the end of
|
||||
/// this lambda expression.
|
||||
unsigned HasArrayIndexVars : 1;
|
||||
|
||||
/// \brief The location of the closing brace ('}') that completes
|
||||
|
@ -1157,6 +1162,7 @@ private:
|
|||
LambdaCaptureDefault CaptureDefault,
|
||||
ArrayRef<Capture> Captures,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
|
@ -1186,6 +1192,7 @@ public:
|
|||
LambdaCaptureDefault CaptureDefault,
|
||||
ArrayRef<Capture> Captures,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
|
@ -1276,6 +1283,9 @@ public:
|
|||
/// list vs. an implicit (empty) parameter list.
|
||||
bool hasExplicitParameters() const { return ExplicitParams; }
|
||||
|
||||
/// \brief Whether this lambda had its result type explicitly specified.
|
||||
bool hasExplicitResultType() const { return ExplicitResultType; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == LambdaExprClass;
|
||||
}
|
||||
|
|
|
@ -3467,6 +3467,31 @@ public:
|
|||
/// initializer for the declaration 'Dcl'.
|
||||
void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl);
|
||||
|
||||
/// \brief Create a new lambda closure type.
|
||||
CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange);
|
||||
|
||||
/// \brief Start the definition of a lambda expression.
|
||||
CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
|
||||
SourceRange IntroducerRange,
|
||||
TypeSourceInfo *MethodType,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// \brief Introduce the scope for a lambda expression.
|
||||
sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
bool Mutable);
|
||||
|
||||
/// \brief Note that we have finished the explicit captures for the
|
||||
/// given lambda.
|
||||
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
|
||||
|
||||
/// \brief Introduce the lambda parameters into scope.
|
||||
void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope,
|
||||
llvm::ArrayRef<ParmVarDecl *> Params);
|
||||
|
||||
/// ActOnStartOfLambdaDefinition - This is called just before we start
|
||||
/// parsing the body of a lambda; it analyzes the explicit captures and
|
||||
/// arguments, and sets up various data-structures for the body of the
|
||||
|
@ -3476,12 +3501,13 @@ public:
|
|||
|
||||
/// ActOnLambdaError - If there is an error parsing a lambda, this callback
|
||||
/// is invoked to pop the information about the lambda.
|
||||
void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope);
|
||||
void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
|
||||
bool IsInstantiation = false);
|
||||
|
||||
/// ActOnLambdaExpr - This is called when the body of a lambda expression
|
||||
/// was successfully completed.
|
||||
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
||||
Scope *CurScope);
|
||||
Scope *CurScope, bool IsInstantiation = false);
|
||||
|
||||
// ParseObjCStringLiteral - Parse Objective-C string literals.
|
||||
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
|
||||
|
|
|
@ -752,6 +752,7 @@ LambdaExpr::LambdaExpr(QualType T,
|
|||
LambdaCaptureDefault CaptureDefault,
|
||||
ArrayRef<Capture> Captures,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
|
@ -763,6 +764,7 @@ LambdaExpr::LambdaExpr(QualType T,
|
|||
NumCaptures(Captures.size()),
|
||||
CaptureDefault(CaptureDefault),
|
||||
ExplicitParams(ExplicitParams),
|
||||
ExplicitResultType(ExplicitResultType),
|
||||
ClosingBrace(ClosingBrace)
|
||||
{
|
||||
assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
|
||||
|
@ -810,6 +812,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
|
|||
LambdaCaptureDefault CaptureDefault,
|
||||
ArrayRef<Capture> Captures,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
|
@ -824,8 +827,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
|
|||
+ sizeof(unsigned) * (Captures.size() + 1);
|
||||
void *Mem = Context.Allocate(Size);
|
||||
return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
|
||||
Captures, ExplicitParams, CaptureInits,
|
||||
ArrayIndexVars, ArrayIndexStarts,
|
||||
Captures, ExplicitParams, ExplicitResultType,
|
||||
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
|
||||
ClosingBrace);
|
||||
}
|
||||
|
||||
|
|
|
@ -1344,9 +1344,9 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
|
|||
|
||||
// FIXME: Attributes
|
||||
|
||||
// FIXME: Suppress trailing return type if it wasn't specified in
|
||||
// the source.
|
||||
OS << " -> " << Proto->getResultType().getAsString(Policy);
|
||||
// Print the trailing return type if it was specified in the source.
|
||||
if (Node->hasExplicitResultType())
|
||||
OS << " -> " << Proto->getResultType().getAsString(Policy);
|
||||
}
|
||||
|
||||
// Print the body.
|
||||
|
|
|
@ -9283,8 +9283,6 @@ namespace {
|
|||
return BaseTransform::TransformUnaryOperator(E);
|
||||
}
|
||||
|
||||
/// \brief Transform the capture expressions in the lambda
|
||||
/// expression.
|
||||
ExprResult TransformLambdaExpr(LambdaExpr *E) {
|
||||
// Lambdas never need to be transformed.
|
||||
return E;
|
||||
|
|
|
@ -20,23 +20,115 @@
|
|||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||
Declarator &ParamInfo,
|
||||
Scope *CurScope) {
|
||||
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange) {
|
||||
DeclContext *DC = CurContext;
|
||||
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
|
||||
DC = DC->getParent();
|
||||
|
||||
|
||||
// Start constructing the lambda class.
|
||||
CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC,
|
||||
Intro.Range.getBegin());
|
||||
IntroducerRange.getBegin());
|
||||
CurContext->addDecl(Class);
|
||||
|
||||
return Class;
|
||||
}
|
||||
|
||||
// Build the call operator; we don't really have all the relevant information
|
||||
// at this point, but we need something to attach child declarations to.
|
||||
QualType MethodTy;
|
||||
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
|
||||
SourceRange IntroducerRange,
|
||||
TypeSourceInfo *MethodType,
|
||||
SourceLocation EndLoc) {
|
||||
// C++11 [expr.prim.lambda]p5:
|
||||
// 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
|
||||
// the lambda-expression's parameter-declaration-clause and
|
||||
// trailing-return-type respectively.
|
||||
DeclarationName MethodName
|
||||
= Context.DeclarationNames.getCXXOperatorName(OO_Call);
|
||||
DeclarationNameLoc MethodNameLoc;
|
||||
MethodNameLoc.CXXOperatorName.BeginOpNameLoc
|
||||
= IntroducerRange.getBegin().getRawEncoding();
|
||||
MethodNameLoc.CXXOperatorName.EndOpNameLoc
|
||||
= IntroducerRange.getEnd().getRawEncoding();
|
||||
CXXMethodDecl *Method
|
||||
= CXXMethodDecl::Create(Context, Class, EndLoc,
|
||||
DeclarationNameInfo(MethodName,
|
||||
IntroducerRange.getBegin(),
|
||||
MethodNameLoc),
|
||||
MethodType->getType(), MethodType,
|
||||
/*isStatic=*/false,
|
||||
SC_None,
|
||||
/*isInline=*/true,
|
||||
/*isConstExpr=*/false,
|
||||
EndLoc);
|
||||
Method->setAccess(AS_public);
|
||||
|
||||
// Temporarily set the lexical declaration context to the current
|
||||
// context, so that the Scope stack matches the lexical nesting.
|
||||
Method->setLexicalDeclContext(Class->getDeclContext());
|
||||
|
||||
return Method;
|
||||
}
|
||||
|
||||
LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
|
||||
SourceRange IntroducerRange,
|
||||
LambdaCaptureDefault CaptureDefault,
|
||||
bool ExplicitParams,
|
||||
bool ExplicitResultType,
|
||||
bool Mutable) {
|
||||
PushLambdaScope(CallOperator->getParent(), CallOperator);
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
if (CaptureDefault == LCD_ByCopy)
|
||||
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
|
||||
else if (CaptureDefault == LCD_ByRef)
|
||||
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
|
||||
LSI->IntroducerRange = IntroducerRange;
|
||||
LSI->ExplicitParams = ExplicitParams;
|
||||
LSI->Mutable = Mutable;
|
||||
|
||||
if (ExplicitResultType) {
|
||||
LSI->ReturnType = CallOperator->getResultType();
|
||||
} else {
|
||||
LSI->HasImplicitReturnType = true;
|
||||
}
|
||||
|
||||
return LSI;
|
||||
}
|
||||
|
||||
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
|
||||
LSI->finishedExplicitCaptures();
|
||||
}
|
||||
|
||||
void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope,
|
||||
llvm::ArrayRef<ParmVarDecl *> Params) {
|
||||
CallOperator->setParams(Params);
|
||||
CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
|
||||
const_cast<ParmVarDecl **>(Params.end()),
|
||||
/*CheckParameterNames=*/false);
|
||||
|
||||
// Introduce our parameters into the function scope
|
||||
for (unsigned p = 0, NumParams = CallOperator->getNumParams();
|
||||
p < NumParams; ++p) {
|
||||
ParmVarDecl *Param = CallOperator->getParamDecl(p);
|
||||
Param->setOwningFunction(CallOperator);
|
||||
|
||||
// If this has an identifier, add it to the scope stack.
|
||||
if (CurScope && Param->getIdentifier()) {
|
||||
CheckShadow(CurScope, Param);
|
||||
|
||||
PushOnScopeChains(Param, CurScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||
Declarator &ParamInfo,
|
||||
Scope *CurScope) {
|
||||
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range);
|
||||
|
||||
// Determine the signature of the call operator.
|
||||
TypeSourceInfo *MethodTyInfo;
|
||||
bool ExplicitParams = true;
|
||||
bool ExplicitResultType = true;
|
||||
SourceLocation EndLoc;
|
||||
if (ParamInfo.getNumTypeObjects() == 0) {
|
||||
// C++11 [expr.prim.lambda]p4:
|
||||
|
@ -45,10 +137,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
EPI.HasTrailingReturn = true;
|
||||
EPI.TypeQuals |= DeclSpec::TQ_const;
|
||||
MethodTy = Context.getFunctionType(Context.DependentTy,
|
||||
/*Args=*/0, /*NumArgs=*/0, EPI);
|
||||
QualType MethodTy = Context.getFunctionType(Context.DependentTy,
|
||||
/*Args=*/0, /*NumArgs=*/0, EPI);
|
||||
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
|
||||
ExplicitParams = false;
|
||||
ExplicitResultType = false;
|
||||
EndLoc = Intro.Range.getEnd();
|
||||
} else {
|
||||
assert(ParamInfo.isFunctionDeclarator() &&
|
||||
|
@ -70,40 +163,16 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
|
||||
// FIXME: Can these asserts actually fail?
|
||||
assert(MethodTyInfo && "no type from lambda-declarator");
|
||||
MethodTy = MethodTyInfo->getType();
|
||||
assert(!MethodTy.isNull() && "no type from lambda declarator");
|
||||
EndLoc = ParamInfo.getSourceRange().getEnd();
|
||||
|
||||
ExplicitResultType
|
||||
= MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
|
||||
!= Context.DependentTy;
|
||||
}
|
||||
|
||||
// C++11 [expr.prim.lambda]p5:
|
||||
// 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
|
||||
// the lambda-expression's parameter-declaration-clause and
|
||||
// trailing-return-type respectively.
|
||||
DeclarationName MethodName
|
||||
= Context.DeclarationNames.getCXXOperatorName(OO_Call);
|
||||
DeclarationNameLoc MethodNameLoc;
|
||||
MethodNameLoc.CXXOperatorName.BeginOpNameLoc
|
||||
= Intro.Range.getBegin().getRawEncoding();
|
||||
MethodNameLoc.CXXOperatorName.EndOpNameLoc
|
||||
= Intro.Range.getEnd().getRawEncoding();
|
||||
CXXMethodDecl *Method
|
||||
= CXXMethodDecl::Create(Context, Class, EndLoc,
|
||||
DeclarationNameInfo(MethodName,
|
||||
Intro.Range.getBegin(),
|
||||
MethodNameLoc),
|
||||
MethodTy, MethodTyInfo,
|
||||
/*isStatic=*/false,
|
||||
SC_None,
|
||||
/*isInline=*/true,
|
||||
/*isConstExpr=*/false,
|
||||
EndLoc);
|
||||
Method->setAccess(AS_public);
|
||||
|
||||
// Temporarily set the lexical declaration context to the current
|
||||
// context, so that the Scope stack matches the lexical nesting.
|
||||
Method->setLexicalDeclContext(DC);
|
||||
|
||||
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
|
||||
MethodTyInfo, EndLoc);
|
||||
|
||||
// Attributes on the lambda apply to the method.
|
||||
ProcessDeclAttributes(CurScope, Method, ParamInfo);
|
||||
|
||||
|
@ -111,15 +180,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
PushDeclContext(CurScope, Method);
|
||||
|
||||
// Introduce the lambda scope.
|
||||
PushLambdaScope(Class, Method);
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
if (Intro.Default == LCD_ByCopy)
|
||||
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
|
||||
else if (Intro.Default == LCD_ByRef)
|
||||
LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
|
||||
LSI->IntroducerRange = Intro.Range;
|
||||
LSI->ExplicitParams = ExplicitParams;
|
||||
LSI->Mutable = (Method->getTypeQualifiers() & Qualifiers::Const) == 0;
|
||||
LambdaScopeInfo *LSI
|
||||
= enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
|
||||
ExplicitResultType,
|
||||
(Method->getTypeQualifiers() & Qualifiers::Const) == 0);
|
||||
|
||||
// Handle explicit captures.
|
||||
SourceLocation PrevCaptureLoc
|
||||
|
@ -231,53 +295,31 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
TryCapture_ExplicitByVal;
|
||||
TryCaptureVar(Var, C->Loc, Kind);
|
||||
}
|
||||
LSI->finishedExplicitCaptures();
|
||||
finishLambdaExplicitCaptures(LSI);
|
||||
|
||||
// Set the parameters on the decl, if specified.
|
||||
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
|
||||
FunctionProtoTypeLoc Proto =
|
||||
cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
|
||||
Method->setParams(Proto.getParams());
|
||||
CheckParmsForFunctionDef(Method->param_begin(),
|
||||
Method->param_end(),
|
||||
/*CheckParameterNames=*/false);
|
||||
|
||||
// Introduce our parameters into the function scope
|
||||
for (unsigned p = 0, NumParams = Method->getNumParams(); p < NumParams; ++p) {
|
||||
ParmVarDecl *Param = Method->getParamDecl(p);
|
||||
Param->setOwningFunction(Method);
|
||||
|
||||
// If this has an identifier, add it to the scope stack.
|
||||
if (Param->getIdentifier()) {
|
||||
CheckShadow(CurScope, Param);
|
||||
|
||||
PushOnScopeChains(Param, CurScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FunctionType *Fn = MethodTy->getAs<FunctionType>();
|
||||
QualType RetTy = Fn->getResultType();
|
||||
if (RetTy != Context.DependentTy) {
|
||||
LSI->ReturnType = RetTy;
|
||||
} else {
|
||||
LSI->HasImplicitReturnType = true;
|
||||
FunctionProtoTypeLoc Proto
|
||||
= cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
|
||||
addLambdaParameters(Method, CurScope, Proto.getParams());
|
||||
}
|
||||
|
||||
// FIXME: Check return type is complete, !isObjCObjectType
|
||||
|
||||
// Enter a new evaluation context to insulate the block from any
|
||||
// Enter a new evaluation context to insulate the lambda from any
|
||||
// cleanups from the enclosing full-expression.
|
||||
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
||||
}
|
||||
|
||||
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
|
||||
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
|
||||
bool IsInstantiation) {
|
||||
// Leave the expression-evaluation context.
|
||||
DiscardCleanupsInEvaluationContext();
|
||||
PopExpressionEvaluationContext();
|
||||
|
||||
// Leave the context of the lambda.
|
||||
PopDeclContext();
|
||||
if (!IsInstantiation)
|
||||
PopDeclContext();
|
||||
|
||||
// Finalize the lambda.
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
|
@ -291,8 +333,8 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
|
|||
PopFunctionScopeInfo();
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
||||
Stmt *Body, Scope *CurScope) {
|
||||
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
||||
Scope *CurScope, bool IsInstantiation) {
|
||||
// Leave the expression-evaluation context.
|
||||
DiscardCleanupsInEvaluationContext();
|
||||
PopExpressionEvaluationContext();
|
||||
|
@ -305,6 +347,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
CXXMethodDecl *CallOperator;
|
||||
SourceRange IntroducerRange;
|
||||
bool ExplicitParams;
|
||||
bool ExplicitResultType;
|
||||
bool LambdaExprNeedsCleanups;
|
||||
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
|
||||
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
|
||||
|
@ -314,6 +357,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
Class = LSI->Lambda;
|
||||
IntroducerRange = LSI->IntroducerRange;
|
||||
ExplicitParams = LSI->ExplicitParams;
|
||||
ExplicitResultType = !LSI->HasImplicitReturnType;
|
||||
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
|
||||
ArrayIndexVars.swap(LSI->ArrayIndexVars);
|
||||
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
|
||||
|
@ -409,7 +453,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
// C++ [expr.prim.lambda]p7:
|
||||
// The lambda-expression's compound-statement yields the
|
||||
// function-body (8.4) of the function call operator [...].
|
||||
ActOnFinishFunctionBody(CallOperator, Body, /*IsInstantation=*/false);
|
||||
ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
|
||||
CallOperator->setLexicalDeclContext(Class);
|
||||
Class->addDecl(CallOperator);
|
||||
|
||||
|
@ -470,9 +514,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
|
||||
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
|
||||
CaptureDefault, Captures,
|
||||
ExplicitParams, CaptureInits,
|
||||
ArrayIndexVars, ArrayIndexStarts,
|
||||
Body->getLocEnd());
|
||||
ExplicitParams, ExplicitResultType,
|
||||
CaptureInits, ArrayIndexVars,
|
||||
ArrayIndexStarts, Body->getLocEnd());
|
||||
|
||||
// C++11 [expr.prim.lambda]p2:
|
||||
// A lambda-expression shall not appear in an unevaluated operand
|
||||
|
|
|
@ -6842,6 +6842,11 @@ namespace {
|
|||
this->Loc = Loc;
|
||||
this->Entity = Entity;
|
||||
}
|
||||
|
||||
ExprResult TransformLambdaExpr(LambdaExpr *E) {
|
||||
// Lambdas never need to be transformed.
|
||||
return E;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3379,6 +3379,11 @@ namespace {
|
|||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
ExprResult TransformLambdaExpr(LambdaExpr *E) {
|
||||
// Lambdas never need to be transformed.
|
||||
return E;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -732,6 +732,14 @@ namespace {
|
|||
/// this declaration.
|
||||
Decl *TransformDecl(SourceLocation Loc, Decl *D);
|
||||
|
||||
void transformAttrs(Decl *Old, Decl *New) {
|
||||
SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
|
||||
}
|
||||
|
||||
void transformedLocalDecl(Decl *Old, Decl *New) {
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
|
||||
}
|
||||
|
||||
/// \brief Transform the definition of the given declaration by
|
||||
/// instantiating it.
|
||||
Decl *TransformDefinition(SourceLocation Loc, Decl *D);
|
||||
|
|
|
@ -112,6 +112,11 @@ class TreeTransform {
|
|||
protected:
|
||||
Sema &SemaRef;
|
||||
|
||||
/// \brief The set of local declarations that have been transformed, for
|
||||
/// cases where we are forced to build new declarations within the transformer
|
||||
/// rather than in the subclass (e.g., lambda closure types).
|
||||
llvm::DenseMap<Decl *, Decl *> TransformedLocalDecls;
|
||||
|
||||
public:
|
||||
/// \brief Initializes a new tree transformer.
|
||||
TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
|
||||
|
@ -351,10 +356,36 @@ public:
|
|||
/// \brief Transform the given declaration, which is referenced from a type
|
||||
/// or expression.
|
||||
///
|
||||
/// By default, acts as the identity function on declarations. Subclasses
|
||||
/// By default, acts as the identity function on declarations, unless the
|
||||
/// transformer has had to transform the declaration itself. Subclasses
|
||||
/// may override this function to provide alternate behavior.
|
||||
Decl *TransformDecl(SourceLocation Loc, Decl *D) { return D; }
|
||||
Decl *TransformDecl(SourceLocation Loc, Decl *D) {
|
||||
llvm::DenseMap<Decl *, Decl *>::iterator Known
|
||||
= TransformedLocalDecls.find(D);
|
||||
if (Known != TransformedLocalDecls.end())
|
||||
return Known->second;
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
/// \brief Transform the attributes associated with the given declaration and
|
||||
/// place them on the new declaration.
|
||||
///
|
||||
/// By default, this operation does nothing. Subclasses may override this
|
||||
/// behavior to transform attributes.
|
||||
void transformAttrs(Decl *Old, Decl *New) { }
|
||||
|
||||
/// \brief Note that a local declaration has been transformed by this
|
||||
/// transformer.
|
||||
///
|
||||
/// Local declarations are typically transformed via a call to
|
||||
/// TransformDefinition. However, in some cases (e.g., lambda expressions),
|
||||
/// the transformer itself has to transform the declarations. This routine
|
||||
/// can be overridden by a subclass that keeps track of such mappings.
|
||||
void transformedLocalDecl(Decl *Old, Decl *New) {
|
||||
TransformedLocalDecls[Old] = New;
|
||||
}
|
||||
|
||||
/// \brief Transform the definition of the given declaration.
|
||||
///
|
||||
/// By default, invokes TransformDecl() to transform the declaration.
|
||||
|
@ -7622,8 +7653,109 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
|
|||
template<typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||
assert(false && "Lambda expressions cannot be instantiated (yet)");
|
||||
return ExprError();
|
||||
// Create the local class that will describe the lambda.
|
||||
CXXRecordDecl *Class
|
||||
= getSema().createLambdaClosureType(E->getIntroducerRange());
|
||||
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
|
||||
|
||||
// Transform the type of the lambda parameters and start the definition of
|
||||
// the lambda itself.
|
||||
TypeSourceInfo *MethodTy
|
||||
= TransformType(E->getCallOperator()->getTypeSourceInfo());
|
||||
if (!MethodTy)
|
||||
return ExprError();
|
||||
|
||||
// Build the call operator.
|
||||
CXXMethodDecl *CallOperator
|
||||
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
|
||||
MethodTy,
|
||||
E->getCallOperator()->getLocEnd());
|
||||
getDerived().transformAttrs(E->getCallOperator(), CallOperator);
|
||||
|
||||
// Enter the scope of the lambda.
|
||||
sema::LambdaScopeInfo *LSI
|
||||
= getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
|
||||
E->getCaptureDefault(),
|
||||
E->hasExplicitParameters(),
|
||||
E->hasExplicitResultType(),
|
||||
E->isMutable());
|
||||
|
||||
// Transform captures.
|
||||
bool Invalid = false;
|
||||
bool FinishedExplicitCaptures = false;
|
||||
for (LambdaExpr::capture_iterator C = E->capture_begin(),
|
||||
CEnd = E->capture_end();
|
||||
C != CEnd; ++C) {
|
||||
// When we hit the first implicit capture, tell Sema that we've finished
|
||||
// the list of explicit captures.
|
||||
if (!FinishedExplicitCaptures && C->isImplicit()) {
|
||||
getSema().finishLambdaExplicitCaptures(LSI);
|
||||
FinishedExplicitCaptures = true;
|
||||
}
|
||||
|
||||
// Capturing 'this' is trivial.
|
||||
if (C->capturesThis()) {
|
||||
getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Transform the captured variable.
|
||||
VarDecl *CapturedVar
|
||||
= cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
|
||||
C->getCapturedVar()));
|
||||
if (!CapturedVar) {
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Capture the transformed variable.
|
||||
getSema().TryCaptureVar(CapturedVar, C->getLocation(),
|
||||
C->isImplicit()? Sema::TryCapture_Implicit
|
||||
: C->getCaptureKind() == LCK_ByCopy
|
||||
? Sema::TryCapture_ExplicitByVal
|
||||
: Sema::TryCapture_ExplicitByRef);
|
||||
}
|
||||
if (!FinishedExplicitCaptures)
|
||||
getSema().finishLambdaExplicitCaptures(LSI);
|
||||
|
||||
// Transform lambda parameters.
|
||||
llvm::SmallVector<QualType, 4> ParamTypes;
|
||||
llvm::SmallVector<ParmVarDecl *, 4> Params;
|
||||
if (!getDerived().TransformFunctionTypeParams(E->getLocStart(),
|
||||
E->getCallOperator()->param_begin(),
|
||||
E->getCallOperator()->param_size(),
|
||||
0, ParamTypes, &Params))
|
||||
getSema().addLambdaParameters(CallOperator, /*CurScope=*/0, Params);
|
||||
else
|
||||
Invalid = true;
|
||||
|
||||
|
||||
// Enter a new evaluation context to insulate the lambda from any
|
||||
// cleanups from the enclosing full-expression.
|
||||
getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
|
||||
|
||||
if (Invalid) {
|
||||
getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
|
||||
/*IsInstantiation=*/true);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
// Instantiate the body of the lambda expression.
|
||||
StmtResult Body;
|
||||
{
|
||||
Sema::ContextRAII SavedContext(getSema(), CallOperator);
|
||||
|
||||
Body = getDerived().TransformStmt(E->getBody());
|
||||
if (Body.isInvalid()) {
|
||||
getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
|
||||
/*IsInstantiation=*/true);
|
||||
return ExprError();
|
||||
}
|
||||
}
|
||||
|
||||
return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(),
|
||||
/*CurScope=*/0,
|
||||
/*IsInstantiation=*/true);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Winvalid-noreturn %s -verify
|
||||
|
||||
template<typename T>
|
||||
void test_attributes() {
|
||||
auto nrl = []() [[noreturn]] {}; // expected-warning{{function declared 'noreturn' should not return}}
|
||||
}
|
||||
|
||||
template void test_attributes<int>(); // expected-note{{in instantiation of function}}
|
||||
|
||||
template<typename T>
|
||||
void call_with_zero() {
|
||||
[](T *ptr) -> T& { return *ptr; }(0);
|
||||
}
|
||||
|
||||
template void call_with_zero<int>();
|
||||
|
||||
template<typename T>
|
||||
T captures(T x, T y) {
|
||||
auto lambda = [=, &y] () -> T {
|
||||
T i = x;
|
||||
return i + y;
|
||||
};
|
||||
|
||||
return lambda();
|
||||
}
|
||||
|
||||
struct X {
|
||||
X(const X&);
|
||||
};
|
||||
|
||||
X operator+(X, X);
|
||||
X operator-(X, X);
|
||||
|
||||
template int captures(int, int);
|
||||
template X captures(X, X);
|
||||
|
||||
template<typename T>
|
||||
int infer_result(T x, T y) {
|
||||
auto lambda = [=](bool b) { return x + y; };
|
||||
return lambda(true); // expected-error{{no viable conversion from 'X' to 'int'}}
|
||||
}
|
||||
|
||||
template int infer_result(int, int);
|
||||
template int infer_result(X, X); // expected-note{{in instantiation of function template specialization 'infer_result<X>' requested here}}
|
||||
|
Загрузка…
Ссылка в новой задаче