llvm-project/clang/lib/Sema/SemaLambda.cpp

964 lines
38 KiB
C++
Raw Normal View History

//===--- SemaLambda.cpp - Semantic Analysis for C++11 Lambdas -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for C++ lambda expressions.
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace sema;
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
bool KnownDependent) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
// Start constructing the lambda class.
CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC,
IntroducerRange.getBegin(),
KnownDependent);
DC->addDecl(Class);
return Class;
}
/// \brief Determine whether the given context is or is enclosed in an inline
/// function.
static bool isInInlineFunction(const DeclContext *DC) {
while (!DC->isFileContext()) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
if (FD->isInlined())
return true;
DC = DC->getLexicalParent();
}
return false;
}
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
llvm::ArrayRef<ParmVarDecl *> Params) {
// 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(CurContext);
// Add parameters.
if (!Params.empty()) {
Method->setParams(Params);
CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
const_cast<ParmVarDecl **>(Params.end()),
/*CheckParameterNames=*/false);
for (CXXMethodDecl::param_iterator P = Method->param_begin(),
PEnd = Method->param_end();
P != PEnd; ++P)
(*P)->setOwningFunction(Method);
}
// Allocate a mangling number for this lambda expression, if the ABI
// requires one.
Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
enum ContextKind {
Normal,
DefaultArgument,
DataMember,
StaticDataMember
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
// definition, as well as the initializers of data members, receive special
// treatment. Identify them.
if (ContextDecl) {
if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
if (const DeclContext *LexicalDC
= Param->getDeclContext()->getLexicalParent())
if (LexicalDC->isRecord())
Kind = DefaultArgument;
} else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
if (Var->getDeclContext()->isRecord())
Kind = StaticDataMember;
} else if (isa<FieldDecl>(ContextDecl)) {
Kind = DataMember;
}
}
// Itanium ABI [5.1.7]:
// In the following contexts [...] the one-definition rule requires closure
// types in different translation units to "correspond":
bool IsInNonspecializedTemplate =
!ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
unsigned ManglingNumber;
switch (Kind) {
case Normal:
// -- the bodies of non-exported nonspecialized template functions
// -- the bodies of inline functions
if ((IsInNonspecializedTemplate &&
!(ContextDecl && isa<ParmVarDecl>(ContextDecl))) ||
isInInlineFunction(CurContext))
ManglingNumber = Context.getLambdaManglingNumber(Method);
else
ManglingNumber = 0;
// There is no special context for this lambda.
ContextDecl = 0;
break;
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
if (!IsInNonspecializedTemplate) {
ManglingNumber = 0;
ContextDecl = 0;
break;
}
// Fall through to assign a mangling number.
case DataMember:
// -- the in-class initializers of class members
case DefaultArgument:
// -- default arguments appearing in class definitions
ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
.getManglingNumber(Method);
break;
}
Class->setLambdaMangling(ManglingNumber, ContextDecl);
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();
if (!LSI->ReturnType->isDependentType() &&
!LSI->ReturnType->isVoidType()) {
if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType,
diag::err_lambda_incomplete_result)) {
// Do nothing.
} else if (LSI->ReturnType->isObjCObjectOrInterfaceType()) {
Diag(CallOperator->getLocStart(), diag::err_lambda_objc_object_result)
<< LSI->ReturnType;
}
}
} else {
LSI->HasImplicitReturnType = true;
}
return LSI;
}
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
LSI->finishedExplicitCaptures();
}
void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
ParmVarDecl *Param = CallOperator->getParamDecl(p);
// If this has an identifier, add it to the scope stack.
if (CurScope && Param->getIdentifier()) {
CheckShadow(CurScope, Param);
PushOnScopeChains(Param, CurScope);
}
}
}
static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
QualType &DeducedType,
QualType &AlternateType) {
// Handle ReturnStmts with no expressions.
if (!E) {
if (AlternateType.isNull())
AlternateType = Ctx.VoidTy;
return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
}
QualType StrictType = E->getType();
QualType LooseType = StrictType;
// In C, enum constants have the type of their underlying integer type,
// not the enum. When inferring block return types, we should allow
// the enum type if an enum constant is used, unless the enum is
// anonymous (in which case there can be no variables of its type).
if (!Ctx.getLangOpts().CPlusPlus) {
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
if (DRE) {
const Decl *D = DRE->getDecl();
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
LooseType = Ctx.getTypeDeclType(Enum);
}
}
}
// Special case for the first return statement we find.
// The return type has already been tentatively set, but we might still
// have an alternate type we should prefer.
if (AlternateType.isNull())
AlternateType = LooseType;
if (Ctx.hasSameType(DeducedType, StrictType)) {
// FIXME: The loose type is different when there are constants from two
// different enums. We could consider warning here.
if (AlternateType != Ctx.DependentTy)
if (!Ctx.hasSameType(AlternateType, LooseType))
AlternateType = Ctx.VoidTy;
return true;
}
if (Ctx.hasSameType(DeducedType, LooseType)) {
// Use DependentTy to signal that we're using an alternate type and may
// need to add casts somewhere.
AlternateType = Ctx.DependentTy;
return true;
}
if (Ctx.hasSameType(AlternateType, StrictType) ||
Ctx.hasSameType(AlternateType, LooseType)) {
DeducedType = AlternateType;
// Use DependentTy to signal that we're using an alternate type and may
// need to add casts somewhere.
AlternateType = Ctx.DependentTy;
return true;
}
return false;
}
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
// First case: no return statements, implicit void return type.
ASTContext &Ctx = getASTContext();
if (CSI.Returns.empty()) {
// It's possible there were simply no /valid/ return statements.
// In this case, the first one we found may have at least given us a type.
if (CSI.ReturnType.isNull())
CSI.ReturnType = Ctx.VoidTy;
return;
}
// Second case: at least one return statement has dependent type.
// Delay type checking until instantiation.
assert(!CSI.ReturnType.isNull() && "We should have a tentative return type.");
if (CSI.ReturnType->isDependentType())
return;
// Third case: only one return statement. Don't bother doing extra work!
SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
E = CSI.Returns.end();
if (I+1 == E)
return;
// General case: many return statements.
// Check that they all have compatible return types.
// For now, that means "identical", with an exception for enum constants.
// (In C, enum constants have the type of their underlying integer type,
// not the type of the enum. C++ uses the type of the enum.)
QualType AlternateType;
// We require the return types to strictly match here.
for (; I != E; ++I) {
const ReturnStmt *RS = *I;
const Expr *RetE = RS->getRetValue();
if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) {
// FIXME: This is a poor diagnostic for ReturnStmts without expressions.
Diag(RS->getLocStart(),
diag::err_typecheck_missing_return_type_incompatible)
<< (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType
<< isa<LambdaScopeInfo>(CSI);
// Don't bother fixing up the return statements in the block if some of
// them are unfixable anyway.
AlternateType = Ctx.VoidTy;
// Continue iterating so that we keep emitting diagnostics.
}
}
// If our return statements turned out to be compatible, but we needed to
// pick a different return type, go through and fix the ones that need it.
if (AlternateType == Ctx.DependentTy) {
for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
E = CSI.Returns.end();
I != E; ++I) {
ReturnStmt *RS = *I;
Expr *RetE = RS->getRetValue();
if (RetE->getType() == CSI.ReturnType)
continue;
// Right now we only support integral fixup casts.
assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType());
assert(RetE->getType()->isIntegralOrUnscopedEnumerationType());
ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType,
CK_IntegralCast);
assert(Casted.isUsable());
RS->setRetValue(Casted.take());
}
}
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
// Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope.
bool KnownDependent = false;
if (Scope *TmplScope = CurScope->getTemplateParamParent())
if (!TmplScope->decl_empty())
KnownDependent = true;
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent);
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
bool ExplicitResultType = true;
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
llvm::SmallVector<ParmVarDecl *, 8> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
// if the lambda-declarator were ().
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
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() &&
"lambda-declarator is a function");
DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
// C++11 [expr.prim.lambda]p5:
// This function call operator is declared const (9.3.1) if and only if
// the lambda-expression's parameter-declaration-clause is not followed
// by mutable. It is neither virtual nor declared volatile. [...]
if (!FTI.hasMutableQualifier())
FTI.TypeQuals |= DeclSpec::TQ_const;
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
assert(MethodTyInfo && "no type from lambda-declarator");
EndLoc = ParamInfo.getSourceRange().getEnd();
ExplicitResultType
= MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
!= Context.DependentTy;
Params.reserve(FTI.NumArgs);
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
Params.push_back(cast<ParmVarDecl>(FTI.ArgInfo[i].Param));
// Check for unexpanded parameter packs in the method type.
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
}
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
// Attributes on the lambda apply to the method.
ProcessDeclAttributes(CurScope, Method, ParamInfo);
// Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method);
// Introduce the lambda scope.
LambdaScopeInfo *LSI
= enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
ExplicitResultType,
!Method->isConst());
// Handle explicit captures.
SourceLocation PrevCaptureLoc
= Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
C = Intro.Captures.begin(),
E = Intro.Captures.end();
C != E;
PrevCaptureLoc = C->Loc, ++C) {
if (C->Kind == LCK_This) {
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
if (LSI->isCXXThisCaptured()) {
Diag(C->Loc, diag::err_capture_more_than_once)
<< "'this'"
<< SourceRange(LSI->getCXXThisCapture().getLocation())
<< FixItHint::CreateRemoval(
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
// C++11 [expr.prim.lambda]p8:
// If a lambda-capture includes a capture-default that is =, the
// lambda-capture shall not contain this [...].
if (Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_this_capture_with_copy_default)
<< FixItHint::CreateRemoval(
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
// C++11 [expr.prim.lambda]p12:
// If this is captured by a local lambda expression, its nearest
// enclosing function shall be a non-static member function.
QualType ThisCaptureType = getCurrentThisType();
if (ThisCaptureType.isNull()) {
Diag(C->Loc, diag::err_this_capture) << true;
continue;
}
CheckCXXThisCapture(C->Loc, /*Explicit=*/true);
continue;
}
assert(C->Id && "missing identifier for capture");
// C++11 [expr.prim.lambda]p8:
// If a lambda-capture includes a capture-default that is &, the
// identifiers in the lambda-capture shall not be preceded by &.
// If a lambda-capture includes a capture-default that is =, [...]
// each identifier it contains shall be preceded by &.
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
Diag(C->Loc, diag::err_reference_capture_with_reference_default)
<< FixItHint::CreateRemoval(
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_copy_capture_with_copy_default)
<< FixItHint::CreateRemoval(
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
DeclarationNameInfo Name(C->Id, C->Loc);
LookupResult R(*this, Name, LookupOrdinaryName);
LookupName(R, CurScope);
if (R.isAmbiguous())
continue;
if (R.empty()) {
// FIXME: Disable corrections that would add qualification?
CXXScopeSpec ScopeSpec;
DeclFilterCCC<VarDecl> Validator;
if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
continue;
}
// C++11 [expr.prim.lambda]p10:
// The identifiers in a capture-list are looked up using the usual rules
// for unqualified name lookup (3.4.1); each such lookup shall find a
// variable with automatic storage duration declared in the reaching
// scope of the local lambda expression.
//
Rewrite variable capture within lambda expressions and blocks, eliminating a bunch of redundant code and properly modeling how the captures of outside blocks/lambdas affect the types seen by inner captures. This new scheme makes two passes over the capturing scope stack. The first pass goes up the stack (from innermost to outermost), assessing whether the capture looks feasible and stopping when it either hits the scope where the variable is declared or when it finds an existing capture. The second pass then walks down the stack (from outermost to innermost), capturing the variable at each step and updating the captured type and the type that an expression referring to that captured variable would see. It also checks type-specific restrictions, such as the inability to capture an array within a block. Note that only the first odr-use of each variable needs to do the full walk; subsequent uses will find the capture immediately, so multiple walks need not occur. The same routine that builds the captures can also compute the type of the captures without signaling errors and without actually performing the capture. This functionality is used to determine the type of declaration references as well as implementing the weird decltype((x)) rule within lambda expressions. The capture code now explicitly takes sides in the debate over C++ core issue 1249, which concerns the type of captures within nested lambdas. We opt to use the more permissive, more useful definition implemented by GCC rather than the one implemented by EDG. llvm-svn: 150875
2012-02-18 17:37:24 +08:00
// Note that the 'reaching scope' check happens in tryCaptureVariable().
VarDecl *Var = R.getAsSingle<VarDecl>();
if (!Var) {
Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
continue;
}
// Ignore invalid decls; they'll just confuse the code later.
if (Var->isInvalidDecl())
continue;
if (!Var->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
continue;
}
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
if (LSI->isCaptured(Var)) {
Diag(C->Loc, diag::err_capture_more_than_once)
<< C->Id
<< SourceRange(LSI->getCapture(Var).getLocation())
<< FixItHint::CreateRemoval(
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
// C++11 [expr.prim.lambda]p23:
// A capture followed by an ellipsis is a pack expansion (14.5.3).
SourceLocation EllipsisLoc;
if (C->EllipsisLoc.isValid()) {
if (Var->isParameterPack()) {
EllipsisLoc = C->EllipsisLoc;
} else {
Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< SourceRange(C->Loc);
// Just ignore the ellipsis.
}
} else if (Var->isParameterPack()) {
ContainsUnexpandedParameterPack = true;
}
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
Rewrite variable capture within lambda expressions and blocks, eliminating a bunch of redundant code and properly modeling how the captures of outside blocks/lambdas affect the types seen by inner captures. This new scheme makes two passes over the capturing scope stack. The first pass goes up the stack (from innermost to outermost), assessing whether the capture looks feasible and stopping when it either hits the scope where the variable is declared or when it finds an existing capture. The second pass then walks down the stack (from outermost to innermost), capturing the variable at each step and updating the captured type and the type that an expression referring to that captured variable would see. It also checks type-specific restrictions, such as the inability to capture an array within a block. Note that only the first odr-use of each variable needs to do the full walk; subsequent uses will find the capture immediately, so multiple walks need not occur. The same routine that builds the captures can also compute the type of the captures without signaling errors and without actually performing the capture. This functionality is used to determine the type of declaration references as well as implementing the weird decltype((x)) rule within lambda expressions. The capture code now explicitly takes sides in the debate over C++ core issue 1249, which concerns the type of captures within nested lambdas. We opt to use the more permissive, more useful definition implemented by GCC rather than the one implemented by EDG. llvm-svn: 150875
2012-02-18 17:37:24 +08:00
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
}
finishLambdaExplicitCaptures(LSI);
LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
// Add lambda parameters into scope.
addLambdaParameters(Method, CurScope);
// 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,
bool IsInstantiation) {
// Leave the expression-evaluation context.
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
// Leave the context of the lambda.
if (!IsInstantiation)
PopDeclContext();
// Finalize the lambda.
LambdaScopeInfo *LSI = getCurLambda();
CXXRecordDecl *Class = LSI->Lambda;
Class->setInvalidDecl();
SmallVector<Decl*, 4> Fields;
for (RecordDecl::field_iterator i = Class->field_begin(),
e = Class->field_end(); i != e; ++i)
Fields.push_back(*i);
ActOnFields(0, Class->getLocation(), Class, Fields,
SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Class);
PopFunctionScopeInfo();
}
/// \brief Add a lambda's conversion to function pointer, as described in
/// C++11 [expr.prim.lambda]p6.
static void addFunctionPointerConversion(Sema &S,
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
// Add the conversion to function pointer.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionPtrTy;
QualType FunctionTy;
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
Proto->arg_type_begin(),
Proto->getNumArgs(),
ExtInfo);
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
= S.Context.DeclarationNames.getCXXConversionFunctionName(
S.Context.getCanonicalType(FunctionPtrTy));
DeclarationNameLoc NameLoc;
NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(FunctionPtrTy,
Loc);
CXXConversionDecl *Conversion
= CXXConversionDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc, NameLoc),
ConvTy,
S.Context.getTrivialTypeSourceInfo(ConvTy,
Loc),
/*isInline=*/false, /*isExplicit=*/false,
/*isConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Class->addDecl(Conversion);
// Add a non-static member function "__invoke" that will be the result of
// the conversion.
Name = &S.Context.Idents.get("__invoke");
CXXMethodDecl *Invoke
= CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy,
CallOperator->getTypeSourceInfo(),
/*IsStatic=*/true, SC_Static, /*IsInline=*/true,
/*IsConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
SmallVector<ParmVarDecl *, 4> InvokeParams;
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
ParmVarDecl *From = CallOperator->getParamDecl(I);
InvokeParams.push_back(ParmVarDecl::Create(S.Context, Invoke,
From->getLocStart(),
From->getLocation(),
From->getIdentifier(),
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
From->getStorageClassAsWritten(),
/*DefaultArg=*/0));
}
Invoke->setParams(InvokeParams);
Invoke->setAccess(AS_private);
Invoke->setImplicit(true);
Class->addDecl(Invoke);
}
/// \brief Add a lambda's conversion to block pointer.
static void addBlockPointerConversion(Sema &S,
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType BlockPtrTy;
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
QualType FunctionTy
= S.Context.getFunctionType(Proto->getResultType(),
Proto->arg_type_begin(),
Proto->getNumArgs(),
ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, 0, 0, ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
= S.Context.DeclarationNames.getCXXConversionFunctionName(
S.Context.getCanonicalType(BlockPtrTy));
DeclarationNameLoc NameLoc;
NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(BlockPtrTy, Loc);
CXXConversionDecl *Conversion
= CXXConversionDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc, NameLoc),
ConvTy,
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
/*isInline=*/false, /*isExplicit=*/false,
/*isConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Class->addDecl(Conversion);
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
bool IsInstantiation) {
// Collect information from the lambda scope.
llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
llvm::SmallVector<Expr *, 4> CaptureInits;
LambdaCaptureDefault CaptureDefault;
CXXRecordDecl *Class;
CXXMethodDecl *CallOperator;
SourceRange IntroducerRange;
bool ExplicitParams;
bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
bool ContainsUnexpandedParameterPack;
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
{
LambdaScopeInfo *LSI = getCurLambda();
CallOperator = LSI->CallOperator;
Class = LSI->Lambda;
IntroducerRange = LSI->IntroducerRange;
ExplicitParams = LSI->ExplicitParams;
ExplicitResultType = !LSI->HasImplicitReturnType;
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
ArrayIndexVars.swap(LSI->ArrayIndexVars);
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
// Translate captures.
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
LambdaScopeInfo::Capture From = LSI->Captures[I];
assert(!From.isBlockCapture() && "Cannot capture __block variables");
bool IsImplicit = I >= LSI->NumExplicitCaptures;
// Handle 'this' capture.
if (From.isThisCapture()) {
Captures.push_back(LambdaExpr::Capture(From.getLocation(),
IsImplicit,
LCK_This));
CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(),
getCurrentThisType(),
/*isImplicit=*/true));
continue;
}
VarDecl *Var = From.getVariable();
LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit,
Kind, Var, From.getEllipsisLoc()));
CaptureInits.push_back(From.getCopyExpr());
}
switch (LSI->ImpCaptureStyle) {
case CapturingScopeInfo::ImpCap_None:
CaptureDefault = LCD_None;
break;
case CapturingScopeInfo::ImpCap_LambdaByval:
CaptureDefault = LCD_ByCopy;
break;
case CapturingScopeInfo::ImpCap_LambdaByref:
CaptureDefault = LCD_ByRef;
break;
case CapturingScopeInfo::ImpCap_Block:
llvm_unreachable("block capture in lambda");
break;
}
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a
// trailing-return-type, it is as if the trailing-return-type
// denotes the following type:
// FIXME: Assumes current resolution to core issue 975.
if (LSI->HasImplicitReturnType) {
deduceClosureReturnType(*LSI);
// - if there are no return statements in the
// compound-statement, or all return statements return
// either an expression of type void or no expression or
// braced-init-list, the type void;
if (LSI->ReturnType.isNull()) {
LSI->ReturnType = Context.VoidTy;
}
// Create a function type with the inferred return type.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionTy
= Context.getFunctionType(LSI->ReturnType,
Proto->arg_type_begin(),
Proto->getNumArgs(),
Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
// 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, IsInstantiation);
CallOperator->setLexicalDeclContext(Class);
Class->addDecl(CallOperator);
PopExpressionEvaluationContext();
// C++11 [expr.prim.lambda]p6:
// The closure type for a lambda-expression with no lambda-capture
// has a public non-virtual non-explicit const conversion function
// to pointer to function having the same parameter and return
// types as the closure type's function call operator.
if (Captures.empty() && CaptureDefault == LCD_None)
addFunctionPointerConversion(*this, IntroducerRange, Class,
CallOperator);
// Objective-C++:
// The closure type for a lambda-expression has a public non-virtual
// non-explicit const conversion function to a block pointer having the
// same parameter and return types as the closure type's function call
// operator.
if (getLangOpts().Blocks && getLangOpts().ObjC1)
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
SmallVector<Decl*, 4> Fields;
for (RecordDecl::field_iterator i = Class->field_begin(),
e = Class->field_end(); i != e; ++i)
Fields.push_back(*i);
ActOnFields(0, Class->getLocation(), Class, Fields,
SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Class);
}
if (LambdaExprNeedsCleanups)
ExprNeedsCleanups = true;
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
CaptureDefault, Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
ArrayIndexStarts, Body->getLocEnd(),
ContainsUnexpandedParameterPack);
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
// (Clause 5).
if (!CurContext->isDependentContext()) {
switch (ExprEvalContexts.back().Context) {
case Unevaluated:
// We don't actually diagnose this case immediately, because we
// could be within a context where we might find out later that
// the expression is potentially evaluated (e.g., for typeid).
ExprEvalContexts.back().Lambdas.push_back(Lambda);
break;
case ConstantEvaluated:
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
break;
}
}
return MaybeBindToTemporary(Lambda);
}
ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
SourceLocation ConvLocation,
CXXConversionDecl *Conv,
Expr *Src) {
// Make sure that the lambda call operator is marked used.
CXXRecordDecl *Lambda = Conv->getParent();
CXXMethodDecl *CallOperator
= cast<CXXMethodDecl>(
*Lambda->lookup(
Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
CallOperator->setReferenced();
CallOperator->setUsed();
ExprResult Init = PerformCopyInitialization(
InitializedEntity::InitializeBlock(ConvLocation,
Src->getType(),
/*NRVO=*/false),
CurrentLocation, Src);
if (!Init.isInvalid())
Init = ActOnFinishFullExpr(Init.take());
if (Init.isInvalid())
return ExprError();
// Create the new block to be returned.
BlockDecl *Block = BlockDecl::Create(Context, CurContext, ConvLocation);
// Set the type information.
Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo());
Block->setIsVariadic(CallOperator->isVariadic());
Block->setBlockMissingReturnType(false);
// Add parameters.
SmallVector<ParmVarDecl *, 4> BlockParams;
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
ParmVarDecl *From = CallOperator->getParamDecl(I);
BlockParams.push_back(ParmVarDecl::Create(Context, Block,
From->getLocStart(),
From->getLocation(),
From->getIdentifier(),
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
From->getStorageClassAsWritten(),
/*DefaultArg=*/0));
}
Block->setParams(BlockParams);
Block->setIsConversionFromLambda(true);
// Add capture. The capture uses a fake variable, which doesn't correspond
// to any actual memory location. However, the initializer copy-initializes
// the lambda object.
TypeSourceInfo *CapVarTSI =
Context.getTrivialTypeSourceInfo(Src->getType());
VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
ConvLocation, 0,
Src->getType(), CapVarTSI,
SC_None, SC_None);
BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
/*Nested=*/false, /*Copy=*/Init.take());
Block->setCaptures(Context, &Capture, &Capture + 1,
/*CapturesCXXThis=*/false);
// Add a fake function body to the block. IR generation is responsible
// for filling in the actual body, which cannot be expressed as an AST.
Block->setBody(new (Context) CompoundStmt(ConvLocation));
// Create the block literal expression.
Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
ExprCleanupObjects.push_back(Block);
ExprNeedsCleanups = true;
return BuildBlock;
}