[cfe-commits] r150417 - in /cfe/trunk: include/clang/AST/ExprCXX.h include/clang/Sema/Sema.h lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLambda.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/TreeTransform.h test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
Douglas Gregor
dgregor at apple.com
Mon Feb 13 14:00:16 PST 2012
Author: dgregor
Date: Mon Feb 13 16:00:16 2012
New Revision: 150417
URL: http://llvm.org/viewvc/llvm-project?rev=150417&view=rev
Log:
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.
Added:
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
Modified:
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaLambda.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Mon Feb 13 16:00:16 2012
@@ -1059,6 +1059,11 @@
/// 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 @@
LambdaCaptureDefault CaptureDefault,
ArrayRef<Capture> Captures,
bool ExplicitParams,
+ bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
@@ -1186,6 +1192,7 @@
LambdaCaptureDefault CaptureDefault,
ArrayRef<Capture> Captures,
bool ExplicitParams,
+ bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
@@ -1276,6 +1283,9 @@
/// 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;
}
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Feb 13 16:00:16 2012
@@ -3467,6 +3467,31 @@
/// 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 @@
/// 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,
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Mon Feb 13 16:00:16 2012
@@ -752,6 +752,7 @@
LambdaCaptureDefault CaptureDefault,
ArrayRef<Capture> Captures,
bool ExplicitParams,
+ bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
@@ -763,6 +764,7 @@
NumCaptures(Captures.size()),
CaptureDefault(CaptureDefault),
ExplicitParams(ExplicitParams),
+ ExplicitResultType(ExplicitResultType),
ClosingBrace(ClosingBrace)
{
assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
@@ -810,6 +812,7 @@
LambdaCaptureDefault CaptureDefault,
ArrayRef<Capture> Captures,
bool ExplicitParams,
+ bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
@@ -824,8 +827,8 @@
+ 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);
}
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Mon Feb 13 16:00:16 2012
@@ -1344,9 +1344,9 @@
// 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.
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Feb 13 16:00:16 2012
@@ -9283,8 +9283,6 @@
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;
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Mon Feb 13 16:00:16 2012
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
CXXMethodDecl *CallOperator;
SourceRange IntroducerRange;
bool ExplicitParams;
+ bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
@@ -314,6 +357,7 @@
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 @@
// 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 @@
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
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb 13 16:00:16 2012
@@ -6842,6 +6842,11 @@
this->Loc = Loc;
this->Entity = Entity;
}
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Lambdas never need to be transformed.
+ return E;
+ }
};
}
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Feb 13 16:00:16 2012
@@ -3379,6 +3379,11 @@
return Result;
}
}
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Lambdas never need to be transformed.
+ return E;
+ }
};
}
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Feb 13 16:00:16 2012
@@ -732,6 +732,14 @@
/// 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);
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=150417&r1=150416&r2=150417&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Feb 13 16:00:16 2012
@@ -112,6 +112,11 @@
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 @@
/// \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 @@
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>
Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp?rev=150417&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp Mon Feb 13 16:00:16 2012
@@ -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}}
+
More information about the cfe-commits
mailing list