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:
Douglas Gregor 2012-02-13 22:00:16 +00:00
Родитель 07e5288c65
Коммит dfca6f53ab
11 изменённых файлов: 376 добавлений и 100 удалений

Просмотреть файл

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