forked from OSchip/llvm-project
Lambda closure types have a conversion function to a block pointer
with the same parameter types and return type as the function call operator. This is the real answer to http://stackoverflow.com/questions/4148242/is-it-possible-to-convert-a-c0x-lambda-to-a-clang-block :) llvm-svn: 150620
This commit is contained in:
parent
690a1fb045
commit
33e863cfc8
|
@ -411,6 +411,48 @@ static void addFunctionPointerConversion(Sema &S,
|
||||||
Class->addDecl(Conversion);
|
Class->addDecl(Conversion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \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,
|
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
||||||
Scope *CurScope, bool IsInstantiation) {
|
Scope *CurScope, bool IsInstantiation) {
|
||||||
// Leave the expression-evaluation context.
|
// Leave the expression-evaluation context.
|
||||||
|
@ -543,6 +585,14 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
||||||
addFunctionPointerConversion(*this, IntroducerRange, Class,
|
addFunctionPointerConversion(*this, IntroducerRange, Class,
|
||||||
CallOperator);
|
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 (getLangOptions().Blocks)
|
||||||
|
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
|
||||||
|
|
||||||
// Finalize the lambda class.
|
// Finalize the lambda class.
|
||||||
SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
|
SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
|
||||||
ActOnFields(0, Class->getLocation(), Class, Fields,
|
ActOnFields(0, Class->getLocation(), Class, Fields,
|
||||||
|
|
|
@ -6,3 +6,10 @@ void block_capture_errors() {
|
||||||
|
|
||||||
(void)[=] { var = 17; }; // expected-error{{__block variable 'var' cannot be captured in a lambda}}
|
(void)[=] { var = 17; }; // expected-error{{__block variable 'var' cannot be captured in a lambda}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void conversion_to_block(int captured) {
|
||||||
|
int (^b1)(int) = [=](int x) { return x + captured; };
|
||||||
|
|
||||||
|
const auto lambda = [=](int x) { return x + captured; };
|
||||||
|
int (^b2)(int) = lambda;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue