forked from OSchip/llvm-project
Correctly emit certain implicit references to 'self' even within
a lambda. Bug #1 is that CGF's CurFuncDecl was "stuck" at lambda invocation functions. Fix that by generally improving getNonClosureContext to look through lambdas and captured statements but only report code contexts, which is generally what's wanted. Audit uses of CurFuncDecl and getNonClosureAncestor for correctness. Bug #2 is that lambdas weren't specially mapping 'self' when inside an ObjC method. Fix that by removing the requirement for that and using the normal EmitDeclRefLValue path in LoadObjCSelf. rdar://13800041 llvm-svn: 181000
This commit is contained in:
parent
320fbf057c
commit
dec348f7db
|
@ -372,10 +372,13 @@ public:
|
|||
return const_cast<Decl*>(this)->getDeclContext();
|
||||
}
|
||||
|
||||
/// Finds the innermost non-closure context of this declaration.
|
||||
/// That is, walk out the DeclContext chain, skipping any blocks.
|
||||
DeclContext *getNonClosureContext();
|
||||
const DeclContext *getNonClosureContext() const {
|
||||
/// Find the innermost non-closure ancestor of this declaration,
|
||||
/// walking up through blocks, lambdas, etc. If that ancestor is
|
||||
/// not a code context (!isFunctionOrMethod()), returns null.
|
||||
///
|
||||
/// A declaration may be its own non-closure context.
|
||||
Decl *getNonClosureContext();
|
||||
const Decl *getNonClosureContext() const {
|
||||
return const_cast<Decl*>(this)->getNonClosureContext();
|
||||
}
|
||||
|
||||
|
@ -1114,8 +1117,8 @@ public:
|
|||
/// \brief Find the nearest non-closure ancestor of this context,
|
||||
/// i.e. the innermost semantic parent of this context which is not
|
||||
/// a closure. A context may be its own non-closure ancestor.
|
||||
DeclContext *getNonClosureAncestor();
|
||||
const DeclContext *getNonClosureAncestor() const {
|
||||
Decl *getNonClosureAncestor();
|
||||
const Decl *getNonClosureAncestor() const {
|
||||
return const_cast<DeclContext*>(this)->getNonClosureAncestor();
|
||||
}
|
||||
|
||||
|
|
|
@ -704,21 +704,37 @@ void Decl::CheckAccessDeclContext() const {
|
|||
#endif
|
||||
}
|
||||
|
||||
DeclContext *Decl::getNonClosureContext() {
|
||||
return getDeclContext()->getNonClosureAncestor();
|
||||
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
|
||||
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }
|
||||
|
||||
/// Starting at a given context (a Decl or DeclContext), look for a
|
||||
/// code context that is not a closure (a lambda, block, etc.).
|
||||
template <class T> static Decl *getNonClosureContext(T *D) {
|
||||
if (getKind(D) == Decl::CXXMethod) {
|
||||
CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
|
||||
if (MD->getParent()->isLambda() &&
|
||||
MD->getOverloadedOperator() == OO_Call)
|
||||
return getNonClosureContext(MD->getParent()->getParent());
|
||||
return MD;
|
||||
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
return FD;
|
||||
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
return MD;
|
||||
} else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
|
||||
return getNonClosureContext(BD->getParent());
|
||||
} else if (CapturedDecl *CD = dyn_cast<CapturedDecl>(D)) {
|
||||
return getNonClosureContext(CD->getParent());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DeclContext *DeclContext::getNonClosureAncestor() {
|
||||
DeclContext *DC = this;
|
||||
Decl *Decl::getNonClosureContext() {
|
||||
return ::getNonClosureContext(this);
|
||||
}
|
||||
|
||||
// This is basically "while (DC->isClosure()) DC = DC->getParent();"
|
||||
// except that it's significantly more efficient to cast to a known
|
||||
// decl type and call getDeclContext() than to call getParent().
|
||||
while (isa<BlockDecl>(DC))
|
||||
DC = cast<BlockDecl>(DC)->getDeclContext();
|
||||
|
||||
assert(!DC->isClosure());
|
||||
return DC;
|
||||
Decl *DeclContext::getNonClosureAncestor() {
|
||||
return ::getNonClosureContext(this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -695,8 +695,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
|
|||
bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
|
||||
llvm::Constant *blockFn
|
||||
= CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo,
|
||||
CurFuncDecl, LocalDeclMap,
|
||||
isLambdaConv);
|
||||
LocalDeclMap,
|
||||
isLambdaConv);
|
||||
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
|
||||
|
||||
// If there is nothing to capture, we can emit this as a global block.
|
||||
|
@ -1034,7 +1034,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr,
|
|||
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
|
||||
blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(),
|
||||
blockInfo,
|
||||
0, LocalDeclMap,
|
||||
LocalDeclMap,
|
||||
false);
|
||||
}
|
||||
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
|
||||
|
@ -1088,7 +1088,6 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
|
|||
llvm::Function *
|
||||
CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
|
||||
const CGBlockInfo &blockInfo,
|
||||
const Decl *outerFnDecl,
|
||||
const DeclMapTy &ldm,
|
||||
bool IsLambdaConversionToBlock) {
|
||||
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
|
||||
|
@ -1148,7 +1147,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
|
|||
// Begin generating the function.
|
||||
StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args,
|
||||
blockInfo.getBlockExpr()->getBody()->getLocStart());
|
||||
CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl
|
||||
|
||||
// Okay. Undo some of what StartFunction did.
|
||||
|
||||
|
@ -1184,23 +1182,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
|
|||
CXXThisValue = Builder.CreateLoad(addr, "this");
|
||||
}
|
||||
|
||||
// LoadObjCSelf() expects there to be an entry for 'self' in LocalDeclMap;
|
||||
// appease it.
|
||||
if (const ObjCMethodDecl *method
|
||||
= dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl)) {
|
||||
const VarDecl *self = method->getSelfDecl();
|
||||
|
||||
// There might not be a capture for 'self', but if there is...
|
||||
if (blockInfo.Captures.count(self)) {
|
||||
const CGBlockInfo::Capture &capture = blockInfo.getCapture(self);
|
||||
|
||||
llvm::Value *selfAddr = Builder.CreateStructGEP(BlockPointer,
|
||||
capture.getIndex(),
|
||||
"block.captured-self");
|
||||
LocalDeclMap[self] = selfAddr;
|
||||
}
|
||||
}
|
||||
|
||||
// Also force all the constant captures.
|
||||
for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
|
||||
ce = blockDecl->capture_end(); ci != ce; ++ci) {
|
||||
|
|
|
@ -1196,7 +1196,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
|||
// initialize the return value. TODO: it might be nice to have
|
||||
// a more general mechanism for this that didn't require synthesized
|
||||
// return statements.
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) {
|
||||
if (FD->hasImplicitReturnZero()) {
|
||||
QualType RetTy = FD->getResultType().getUnqualifiedType();
|
||||
llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
|
||||
|
|
|
@ -290,7 +290,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
|
|||
return 0;
|
||||
}
|
||||
|
||||
const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent();
|
||||
const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurCodeDecl)->getParent();
|
||||
const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
|
||||
|
||||
llvm::Value *VTT;
|
||||
|
@ -2232,10 +2232,10 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
|
|||
}
|
||||
|
||||
void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
|
||||
if (cast<CXXMethodDecl>(CurFuncDecl)->isVariadic()) {
|
||||
if (cast<CXXMethodDecl>(CurCodeDecl)->isVariadic()) {
|
||||
// FIXME: Making this work correctly is nasty because it requires either
|
||||
// cloning the body of the call operator or making the call operator forward.
|
||||
CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to variadic function");
|
||||
CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2495,6 +2495,17 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
|
|||
llvm_unreachable("Unhandled member declaration!");
|
||||
}
|
||||
|
||||
/// Given that we are currently emitting a lambda, emit an l-value for
|
||||
/// one of its members.
|
||||
LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) {
|
||||
assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent()->isLambda());
|
||||
assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent() == Field->getParent());
|
||||
QualType LambdaTagType =
|
||||
getContext().getTagDeclType(Field->getParent());
|
||||
LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType);
|
||||
return EmitLValueForField(LambdaLV, Field);
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitLValueForField(LValue base,
|
||||
const FieldDecl *field) {
|
||||
if (field->isBitField()) {
|
||||
|
|
|
@ -1401,8 +1401,10 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
|
|||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::LoadObjCSelf() {
|
||||
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
|
||||
return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
|
||||
VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
|
||||
DeclRefExpr DRE(Self, /*is enclosing local*/ (CurFuncDecl != CurCodeDecl),
|
||||
Self->getType(), VK_LValue, SourceLocation());
|
||||
return EmitLoadOfScalar(EmitDeclRefLValue(&DRE));
|
||||
}
|
||||
|
||||
QualType CodeGenFunction::TypeOfSelfObject() {
|
||||
|
|
|
@ -471,7 +471,8 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
|
|||
OpenCLKernelMetadata->addOperand(kernelMDNode);
|
||||
}
|
||||
|
||||
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
||||
void CodeGenFunction::StartFunction(GlobalDecl GD,
|
||||
QualType RetTy,
|
||||
llvm::Function *Fn,
|
||||
const CGFunctionInfo &FnInfo,
|
||||
const FunctionArgList &Args,
|
||||
|
@ -479,7 +480,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
|||
const Decl *D = GD.getDecl();
|
||||
|
||||
DidCallStackSave = false;
|
||||
CurCodeDecl = CurFuncDecl = D;
|
||||
CurCodeDecl = D;
|
||||
CurFuncDecl = (D ? D->getNonClosureContext() : 0);
|
||||
FnRetTy = RetTy;
|
||||
CurFn = Fn;
|
||||
CurFnInfo = &FnInfo;
|
||||
|
@ -578,12 +580,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
|||
LambdaThisCaptureField);
|
||||
if (LambdaThisCaptureField) {
|
||||
// If this lambda captures this, load it.
|
||||
QualType LambdaTagType =
|
||||
getContext().getTagDeclType(LambdaThisCaptureField->getParent());
|
||||
LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue,
|
||||
LambdaTagType);
|
||||
LValue ThisLValue = EmitLValueForField(LambdaLV,
|
||||
LambdaThisCaptureField);
|
||||
LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField);
|
||||
CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -579,8 +579,8 @@ public:
|
|||
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
|
||||
CGBuilderTy Builder;
|
||||
|
||||
/// CurFuncDecl - Holds the Decl for the current function or ObjC method.
|
||||
/// This excludes BlockDecls.
|
||||
/// CurFuncDecl - Holds the Decl for the current outermost
|
||||
/// non-closure context.
|
||||
const Decl *CurFuncDecl;
|
||||
/// CurCodeDecl - This is the inner-most code context, which includes blocks.
|
||||
const Decl *CurCodeDecl;
|
||||
|
@ -1451,7 +1451,6 @@ public:
|
|||
|
||||
llvm::Function *GenerateBlockFunction(GlobalDecl GD,
|
||||
const CGBlockInfo &Info,
|
||||
const Decl *OuterFuncDecl,
|
||||
const DeclMapTy &ldm,
|
||||
bool IsLambdaConversionToBlock);
|
||||
|
||||
|
@ -1482,7 +1481,8 @@ public:
|
|||
|
||||
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
||||
const CGFunctionInfo &FnInfo);
|
||||
void StartFunction(GlobalDecl GD, QualType RetTy,
|
||||
void StartFunction(GlobalDecl GD,
|
||||
QualType RetTy,
|
||||
llvm::Function *Fn,
|
||||
const CGFunctionInfo &FnInfo,
|
||||
const FunctionArgList &Args,
|
||||
|
@ -2379,6 +2379,7 @@ public:
|
|||
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
|
||||
const ObjCIvarDecl *Ivar);
|
||||
LValue EmitLValueForField(LValue Base, const FieldDecl* Field);
|
||||
LValue EmitLValueForLambdaField(const FieldDecl *Field);
|
||||
|
||||
/// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
|
||||
/// if the Field is a reference, this will return the address of the reference
|
||||
|
|
|
@ -1334,7 +1334,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
|
|||
bool Sema::isSelfExpr(Expr *receiver) {
|
||||
// 'self' is objc 'self' in an objc method only.
|
||||
ObjCMethodDecl *method =
|
||||
dyn_cast<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
|
||||
dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
|
||||
if (!method) return false;
|
||||
|
||||
receiver = receiver->IgnoreParenLValueCasts();
|
||||
|
|
|
@ -59,7 +59,6 @@ typedef enum {
|
|||
// CHECK: call void @llvm.dbg.declare(metadata !{i8* [[BLOCK_DESC]]}, metadata ![[BDMD:[0-9]+]])
|
||||
// CHECK: %[[TMP1:.*]] = bitcast
|
||||
// CHECK-NEXT: store
|
||||
// CHECK-NEXT: %[[TMP2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[TMP1]]
|
||||
// CHECK: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** {{.*}}}, metadata ![[SELF:.*]])
|
||||
// make sure we are still in the same function
|
||||
// CHECK: define {{.*}}__copy_helper_block_
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
// CHECK: define {{.*}}_block_invoke
|
||||
// CHECK: %[[BLOCK:.*]] = bitcast i8* %.block_descriptor to <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>*, !dbg
|
||||
// CHECK-NEXT: store <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA:.*]], align
|
||||
// CHECK-NEXT: getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], i32 0, i32 5
|
||||
// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]]}, metadata ![[SELF:[0-9]+]])
|
||||
// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{%1** %d}, metadata ![[D:[0-9]+]])
|
||||
// CHECK: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line 52]
|
||||
// CHECK: ![[D]] = {{.*}} [d] [line 50]
|
||||
// CHECK: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line 51]
|
||||
// CHECK: ![[D]] = {{.*}} [d] [line 49]
|
||||
|
||||
typedef unsigned int NSUInteger;
|
||||
|
||||
|
|
|
@ -38,6 +38,28 @@ void f2() { global = []{ return 3; }; }
|
|||
// ARC: define internal i32 @___Z2f2v_block_invoke
|
||||
// ARC: call i32 @"_ZZ2f2vENK3$_1clEv
|
||||
|
||||
template <class T> void take_lambda(T &&lambda) { lambda(); }
|
||||
void take_block(void (^block)()) { block(); }
|
||||
|
||||
// rdar://13800041
|
||||
@interface A
|
||||
- (void) test;
|
||||
@end
|
||||
@interface B : A @end
|
||||
@implementation B
|
||||
- (void) test {
|
||||
take_block(^{
|
||||
take_lambda([=]{
|
||||
take_block(^{
|
||||
take_lambda([=] {
|
||||
[super test];
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@end
|
||||
|
||||
// ARC: attributes [[NUW]] = { nounwind{{.*}} }
|
||||
|
||||
// MRC: attributes [[NUW]] = { nounwind{{.*}} }
|
||||
|
|
Loading…
Reference in New Issue