Allocate space in a block record for implicit references to the Objective C

'self' variable arising from uses of the 'super' keyword.  Also reorganize
some code so that BlockInfo (now CGBlockInfo) can be opaque outside of
CGBlocks.cpp.

Fixes rdar://problem/8010633.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104312 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2010-05-21 04:11:14 +00:00
Родитель a9976d3b19
Коммит ee5042903d
5 изменённых файлов: 131 добавлений и 115 удалений

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

@ -24,6 +24,45 @@
using namespace clang; using namespace clang;
using namespace CodeGen; using namespace CodeGen;
/// CGBlockInfo - Information to generate a block literal.
class clang::CodeGen::CGBlockInfo {
public:
/// Name - The name of the block, kindof.
const char *Name;
/// DeclRefs - Variables from parent scopes that have been
/// imported into this block.
llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs;
/// InnerBlocks - This block and the blocks it encloses.
llvm::SmallPtrSet<const DeclContext *, 4> InnerBlocks;
/// CXXThisRef - Non-null if 'this' was required somewhere, in
/// which case this is that expression.
const CXXThisExpr *CXXThisRef;
/// NeedsObjCSelf - True if something in this block has an implicit
/// reference to 'self'.
bool NeedsObjCSelf;
/// These are initialized by GenerateBlockFunction.
bool BlockHasCopyDispose;
CharUnits BlockSize;
CharUnits BlockAlign;
llvm::SmallVector<const Expr*, 8> BlockLayout;
CGBlockInfo(const char *Name);
};
CGBlockInfo::CGBlockInfo(const char *N)
: Name(N), CXXThisRef(0), NeedsObjCSelf(false) {
// Skip asm prefix, if any.
if (Name && Name[0] == '\01')
++Name;
}
llvm::Constant *CodeGenFunction:: llvm::Constant *CodeGenFunction::
BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size,
const llvm::StructType* Ty, const llvm::StructType* Ty,
@ -86,62 +125,85 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() {
return NSConcreteStackBlock; return NSConcreteStackBlock;
} }
static void CollectBlockDeclRefInfo( static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) {
const Stmt *S, CodeGenFunction::BlockInfo &Info,
llvm::SmallSet<const DeclContext *, 16> &InnerContexts) {
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I != E; ++I) I != E; ++I)
if (*I) if (*I)
CollectBlockDeclRefInfo(*I, Info, InnerContexts); CollectBlockDeclRefInfo(*I, Info);
// We want to ensure we walk down into block literals so we can find // We want to ensure we walk down into block literals so we can find
// all nested BlockDeclRefExprs. // all nested BlockDeclRefExprs.
if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl())); Info.InnerBlocks.insert(BE->getBlockDecl());
CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); CollectBlockDeclRefInfo(BE->getBody(), Info);
} }
if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
const ValueDecl *D = BDRE->getDecl();
// FIXME: Handle enums. // FIXME: Handle enums.
if (isa<FunctionDecl>(BDRE->getDecl())) if (isa<FunctionDecl>(D))
return; return;
if (isa<ImplicitParamDecl>(D) &&
isa<ObjCMethodDecl>(D->getDeclContext()) &&
cast<ObjCMethodDecl>(D->getDeclContext())->getSelfDecl() == D) {
Info.NeedsObjCSelf = true;
return;
}
// Only Decls that escape are added. // Only Decls that escape are added.
if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) if (!Info.InnerBlocks.count(D->getDeclContext()))
Info.DeclRefs.push_back(BDRE); Info.DeclRefs.push_back(BDRE);
} }
if (isa<CXXThisExpr>(S)) // Make sure to capture implicit 'self' references due to super calls.
else if (const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(S))
if (E->getReceiverKind() == ObjCMessageExpr::SuperClass ||
E->getReceiverKind() == ObjCMessageExpr::SuperInstance)
Info.NeedsObjCSelf = true;
// Getter/setter uses may also cause implicit super references,
// which we can check for with:
else if (isa<ObjCSuperExpr>(S))
Info.NeedsObjCSelf = true;
else if (isa<CXXThisExpr>(S))
Info.CXXThisRef = cast<CXXThisExpr>(S); Info.CXXThisRef = cast<CXXThisExpr>(S);
} }
/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be /// CanBlockBeGlobal - Given a CGBlockInfo struct, determines if a block can be
/// declared as a global variable instead of on the stack. /// declared as a global variable instead of on the stack.
static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { static bool CanBlockBeGlobal(const CGBlockInfo &Info) {
return Info.DeclRefs.empty(); return Info.DeclRefs.empty();
} }
/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to /// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to
/// ensure we can generate the debug information for the parameter for the block /// ensure we can generate the debug information for the parameter for the block
/// invoke function. /// invoke function.
static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) {
CodeGenFunction *CGF) {
if (Info.CXXThisRef) if (Info.CXXThisRef)
CGF->AllocateBlockCXXThisPointer(Info.CXXThisRef); CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef);
for (size_t i = 0; i < Info.DeclRefs.size(); ++i) for (size_t i = 0; i < Info.DeclRefs.size(); ++i)
CGF->AllocateBlockDecl(Info.DeclRefs[i]); CGF.AllocateBlockDecl(Info.DeclRefs[i]);
if (Info.NeedsObjCSelf) {
ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl();
BlockDeclRefExpr *BDRE =
new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(),
SourceLocation(), false);
Info.DeclRefs.push_back(BDRE);
CGF.AllocateBlockDecl(BDRE);
}
} }
// FIXME: Push most into CGM, passing down a few bits, like current function // FIXME: Push most into CGM, passing down a few bits, like current function
// name. // name.
llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
std::string Name = CurFn->getName(); std::string Name = CurFn->getName();
CodeGenFunction::BlockInfo Info(0, Name.c_str()); CGBlockInfo Info(Name.c_str());
llvm::SmallSet<const DeclContext *, 16> InnerContexts; Info.InnerBlocks.insert(BE->getBlockDecl());
InnerContexts.insert(BE->getBlockDecl()); CollectBlockDeclRefInfo(BE->getBody(), Info);
CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
// Check if the block can be global. // Check if the block can be global.
// FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like
@ -164,23 +226,15 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// We run this first so that we set BlockHasCopyDispose from the entire // We run this first so that we set BlockHasCopyDispose from the entire
// block literal. // block literal.
// __invoke // __invoke
CharUnits subBlockSize;
CharUnits subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockLayout;
bool subBlockHasCopyDispose = false;
llvm::Function *Fn llvm::Function *Fn
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl,
LocalDeclMap, LocalDeclMap);
subBlockSize, BlockHasCopyDispose |= Info.BlockHasCopyDispose;
subBlockAlign,
subBlockLayout,
subBlockHasCopyDispose);
BlockHasCopyDispose |= subBlockHasCopyDispose;
Elts[3] = Fn; Elts[3] = Fn;
// FIXME: Don't use BlockHasCopyDispose, it is set more often then // FIXME: Don't use BlockHasCopyDispose, it is set more often then
// necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); } // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); }
if (subBlockHasCopyDispose) if (Info.BlockHasCopyDispose)
flags |= BLOCK_HAS_COPY_DISPOSE; flags |= BLOCK_HAS_COPY_DISPOSE;
// __isa // __isa
@ -210,10 +264,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
C = llvm::ConstantInt::get(IntTy, 0); C = llvm::ConstantInt::get(IntTy, 0);
Elts[2] = C; Elts[2] = C;
if (subBlockLayout.empty()) { if (Info.BlockLayout.empty()) {
// __descriptor // __descriptor
Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose,
0, 0); Info.BlockSize, 0, 0);
// Optimize to being a global block. // Optimize to being a global block.
Elts[0] = CGM.getNSConcreteGlobalBlock(); Elts[0] = CGM.getNSConcreteGlobalBlock();
@ -231,13 +285,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
return C; return C;
} }
std::vector<const llvm::Type *> Types(BlockFields+subBlockLayout.size()); std::vector<const llvm::Type *> Types(BlockFields+Info.BlockLayout.size());
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
Types[i] = Elts[i]->getType(); Types[i] = Elts[i]->getType();
Types[4] = PtrToInt8Ty; Types[4] = PtrToInt8Ty;
for (unsigned i = 0, n = subBlockLayout.size(); i != n; ++i) { for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) {
const Expr *E = subBlockLayout[i]; const Expr *E = Info.BlockLayout[i];
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType(); QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) { if (BDRE && BDRE->isByRef()) {
@ -249,19 +303,19 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
llvm::AllocaInst *A = CreateTempAlloca(Ty); llvm::AllocaInst *A = CreateTempAlloca(Ty);
A->setAlignment(subBlockAlign.getQuantity()); A->setAlignment(Info.BlockAlign.getQuantity());
V = A; V = A;
// Build layout / cleanup information for all the data entries in the // Build layout / cleanup information for all the data entries in the
// layout, and write the enclosing fields into the type. // layout, and write the enclosing fields into the type.
std::vector<HelperInfo> NoteForHelper(subBlockLayout.size()); std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size());
unsigned NumHelpers = 0; unsigned NumHelpers = 0;
for (unsigned i=0; i<4; ++i) for (unsigned i=0; i<4; ++i)
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
for (unsigned i=0; i < subBlockLayout.size(); ++i) { for (unsigned i=0; i < Info.BlockLayout.size(); ++i) {
const Expr *E = subBlockLayout[i]; const Expr *E = Info.BlockLayout[i];
// Skip padding. // Skip padding.
if (isa<DeclRefExpr>(E)) continue; if (isa<DeclRefExpr>(E)) continue;
@ -354,8 +408,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// __descriptor // __descriptor
llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE,
subBlockHasCopyDispose, Info.BlockHasCopyDispose,
subBlockSize, Ty, Info.BlockSize, Ty,
&NoteForHelper); &NoteForHelper);
Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty);
Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp")); Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp"));
@ -542,8 +596,8 @@ void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
BlockLayout.push_back(E); BlockLayout.push_back(E);
} }
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD,
const ValueDecl *VD = E->getDecl(); bool IsByRef) {
CharUnits offset = BlockDecls[VD]; CharUnits offset = BlockDecls[VD];
assert(!offset.isZero() && "getting address of unallocated decl"); assert(!offset.isZero() && "getting address of unallocated decl");
@ -552,7 +606,7 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
offset.getQuantity()), offset.getQuantity()),
"block.literal"); "block.literal");
if (E->isByRef()) { if (IsByRef) {
const llvm::Type *PtrStructTy const llvm::Type *PtrStructTy
= llvm::PointerType::get(BuildByRefType(VD), 0); = llvm::PointerType::get(BuildByRefType(VD), 0);
// The block literal will need a copy/destroy helper. // The block literal will need a copy/destroy helper.
@ -578,19 +632,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
return V; return V;
} }
void CodeGenFunction::BlockForwardSelf() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
ImplicitParamDecl *SelfDecl = OMD->getSelfDecl();
llvm::Value *&DMEntry = LocalDeclMap[SelfDecl];
if (DMEntry)
return;
// FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care
BlockDeclRefExpr *BDRE = new (getContext())
BlockDeclRefExpr(SelfDecl,
SelfDecl->getType(), SourceLocation(), false);
DMEntry = GetAddrOfBlockDecl(BDRE);
}
llvm::Constant * llvm::Constant *
BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Generate the block descriptor. // Generate the block descriptor.
@ -635,19 +676,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
std::vector<llvm::Constant*> LiteralFields(FieldCount); std::vector<llvm::Constant*> LiteralFields(FieldCount);
CodeGenFunction::BlockInfo Info(0, n); CGBlockInfo Info(n);
CharUnits subBlockSize;
CharUnits subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockLayout;
bool subBlockHasCopyDispose = false;
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
llvm::Function *Fn llvm::Function *Fn
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap, = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap);
subBlockSize, assert(Info.BlockSize == BlockLiteralSize
subBlockAlign,
subBlockLayout,
subBlockHasCopyDispose);
assert(subBlockSize == BlockLiteralSize
&& "no imports allowed for global block"); && "no imports allowed for global block");
// isa // isa
@ -686,13 +719,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() {
llvm::Function * llvm::Function *
CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const BlockInfo& Info, CGBlockInfo &Info,
const Decl *OuterFuncDecl, const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm, llvm::DenseMap<const Decl*, llvm::Value*> ldm) {
CharUnits &Size,
CharUnits &Align,
llvm::SmallVectorImpl<const Expr *> &subBlockLayout,
bool &subBlockHasCopyDispose) {
// Check if we should generate debug info for this block. // Check if we should generate debug info for this block.
if (CGM.getDebugInfo()) if (CGM.getDebugInfo())
@ -737,7 +766,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
// Build the block struct now. // Build the block struct now.
AllocateAllBlockDeclRefs(Info, this); AllocateAllBlockDeclRefs(*this, Info);
QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose,
BlockLayout); BlockLayout);
@ -795,6 +824,13 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
CXXThisValue = Builder.CreateLoad(ThisPtr, "this"); CXXThisValue = Builder.CreateLoad(ThisPtr, "this");
} }
// If we have an Objective C 'self' reference, go ahead and force it
// into existence now.
if (Info.NeedsObjCSelf) {
ValueDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
LocalDeclMap[Self] = GetAddrOfBlockDecl(Self, false);
}
// Save a spot to insert the debug information for all the BlockDeclRefDecls. // Save a spot to insert the debug information for all the BlockDeclRefDecls.
llvm::BasicBlock *entry = Builder.GetInsertBlock(); llvm::BasicBlock *entry = Builder.GetInsertBlock();
llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
@ -837,10 +873,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
llvm::RoundUpToAlignment(BlockOffset.getQuantity(), llvm::RoundUpToAlignment(BlockOffset.getQuantity(),
MinAlign.getQuantity())); MinAlign.getQuantity()));
Size = BlockOffset; Info.BlockSize = BlockOffset;
Align = BlockAlign; Info.BlockAlign = BlockAlign;
subBlockLayout = BlockLayout; Info.BlockLayout = BlockLayout;
subBlockHasCopyDispose |= BlockHasCopyDispose; Info.BlockHasCopyDispose = BlockHasCopyDispose;
return Fn; return Fn;
} }

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

@ -148,30 +148,6 @@ public:
BLOCK_BYREF_CURRENT_MAX = 256 BLOCK_BYREF_CURRENT_MAX = 256
}; };
/// BlockInfo - Information to generate a block literal.
struct BlockInfo {
/// BlockLiteralTy - The type of the block literal.
const llvm::Type *BlockLiteralTy;
/// Name - the name of the function this block was created for, if any.
const char *Name;
/// ByCopyDeclRefs - Variables from parent scopes that have been imported
/// into this block.
llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs;
/// CXXThisRef - An expression referring to the required 'this'
/// expression.
const CXXThisExpr *CXXThisRef;
BlockInfo(const llvm::Type *blt, const char *n)
: BlockLiteralTy(blt), Name(n), CXXThisRef(0) {
// Skip asm prefix, if any.
if (Name && Name[0] == '\01')
++Name;
}
};
CGBuilderTy &Builder; CGBuilderTy &Builder;
BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B); BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B);

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

@ -494,8 +494,6 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
llvm::Value *CodeGenFunction::LoadObjCSelf() { llvm::Value *CodeGenFunction::LoadObjCSelf() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
// See if we need to lazily forward self inside a block literal.
BlockForwardSelf();
return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self"); return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
} }

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

@ -67,6 +67,7 @@ namespace CodeGen {
class CGDebugInfo; class CGDebugInfo;
class CGFunctionInfo; class CGFunctionInfo;
class CGRecordLayout; class CGRecordLayout;
class CGBlockInfo;
/// CodeGenFunction - This class organizes the per-function state that is used /// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code. /// while generating LLVM code.
@ -501,19 +502,18 @@ public:
std::vector<HelperInfo> *); std::vector<HelperInfo> *);
llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr, llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr,
const BlockInfo& Info, CGBlockInfo &Info,
const Decl *OuterFuncDecl, const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm, llvm::DenseMap<const Decl*, llvm::Value*> ldm);
CharUnits &Size, CharUnits &Align,
llvm::SmallVectorImpl<const Expr*> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose);
void BlockForwardSelf();
llvm::Value *LoadBlockStruct(); llvm::Value *LoadBlockStruct();
void AllocateBlockCXXThisPointer(const CXXThisExpr *E); void AllocateBlockCXXThisPointer(const CXXThisExpr *E);
void AllocateBlockDecl(const BlockDeclRefExpr *E); void AllocateBlockDecl(const BlockDeclRefExpr *E);
llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
return GetAddrOfBlockDecl(E->getDecl(), E->isByRef());
}
llvm::Value *GetAddrOfBlockDecl(const ValueDecl *D, bool ByRef);
const llvm::Type *BuildByRefType(const ValueDecl *D); const llvm::Type *BuildByRefType(const ValueDecl *D);
void GenerateCode(GlobalDecl GD, llvm::Function *Fn); void GenerateCode(GlobalDecl GD, llvm::Function *Fn);

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

@ -31,5 +31,11 @@ void foo(T *P) {
-(void) im1 { -(void) im1 {
^(void) { [self im0]; }(); ^(void) { [self im0]; }();
} }
-(void) im2 {
^{ [super im0]; }();
}
-(void) im3 {
^{ ^{[super im0];}(); }();
}
@end @end