зеркало из https://github.com/microsoft/clang.git
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:
Родитель
a9976d3b19
Коммит
ee5042903d
|
@ -24,6 +24,45 @@
|
|||
using namespace clang;
|
||||
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::
|
||||
BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size,
|
||||
const llvm::StructType* Ty,
|
||||
|
@ -86,62 +125,85 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() {
|
|||
return NSConcreteStackBlock;
|
||||
}
|
||||
|
||||
static void CollectBlockDeclRefInfo(
|
||||
const Stmt *S, CodeGenFunction::BlockInfo &Info,
|
||||
llvm::SmallSet<const DeclContext *, 16> &InnerContexts) {
|
||||
static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) {
|
||||
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
|
||||
I != E; ++I)
|
||||
if (*I)
|
||||
CollectBlockDeclRefInfo(*I, Info, InnerContexts);
|
||||
CollectBlockDeclRefInfo(*I, Info);
|
||||
|
||||
// We want to ensure we walk down into block literals so we can find
|
||||
// all nested BlockDeclRefExprs.
|
||||
if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
|
||||
InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl()));
|
||||
CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
|
||||
Info.InnerBlocks.insert(BE->getBlockDecl());
|
||||
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.
|
||||
if (isa<FunctionDecl>(BDRE->getDecl()))
|
||||
if (isa<FunctionDecl>(D))
|
||||
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.
|
||||
if (!InnerContexts.count(BDRE->getDecl()->getDeclContext()))
|
||||
if (!Info.InnerBlocks.count(D->getDeclContext()))
|
||||
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);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) {
|
||||
static bool CanBlockBeGlobal(const CGBlockInfo &Info) {
|
||||
return Info.DeclRefs.empty();
|
||||
}
|
||||
|
||||
/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to
|
||||
/// ensure we can generate the debug information for the parameter for the block
|
||||
/// invoke function.
|
||||
static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info,
|
||||
CodeGenFunction *CGF) {
|
||||
static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) {
|
||||
if (Info.CXXThisRef)
|
||||
CGF->AllocateBlockCXXThisPointer(Info.CXXThisRef);
|
||||
CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef);
|
||||
|
||||
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
|
||||
// name.
|
||||
llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
||||
|
||||
std::string Name = CurFn->getName();
|
||||
CodeGenFunction::BlockInfo Info(0, Name.c_str());
|
||||
llvm::SmallSet<const DeclContext *, 16> InnerContexts;
|
||||
InnerContexts.insert(BE->getBlockDecl());
|
||||
CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
|
||||
CGBlockInfo Info(Name.c_str());
|
||||
Info.InnerBlocks.insert(BE->getBlockDecl());
|
||||
CollectBlockDeclRefInfo(BE->getBody(), Info);
|
||||
|
||||
// Check if the block can be global.
|
||||
// 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
|
||||
// block literal.
|
||||
// __invoke
|
||||
CharUnits subBlockSize;
|
||||
CharUnits subBlockAlign;
|
||||
llvm::SmallVector<const Expr *, 8> subBlockLayout;
|
||||
bool subBlockHasCopyDispose = false;
|
||||
llvm::Function *Fn
|
||||
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl,
|
||||
LocalDeclMap,
|
||||
subBlockSize,
|
||||
subBlockAlign,
|
||||
subBlockLayout,
|
||||
subBlockHasCopyDispose);
|
||||
BlockHasCopyDispose |= subBlockHasCopyDispose;
|
||||
LocalDeclMap);
|
||||
BlockHasCopyDispose |= Info.BlockHasCopyDispose;
|
||||
Elts[3] = Fn;
|
||||
|
||||
// FIXME: Don't use BlockHasCopyDispose, it is set more often then
|
||||
// necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); }
|
||||
if (subBlockHasCopyDispose)
|
||||
if (Info.BlockHasCopyDispose)
|
||||
flags |= BLOCK_HAS_COPY_DISPOSE;
|
||||
|
||||
// __isa
|
||||
|
@ -210,10 +264,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
C = llvm::ConstantInt::get(IntTy, 0);
|
||||
Elts[2] = C;
|
||||
|
||||
if (subBlockLayout.empty()) {
|
||||
if (Info.BlockLayout.empty()) {
|
||||
// __descriptor
|
||||
Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize,
|
||||
0, 0);
|
||||
Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose,
|
||||
Info.BlockSize, 0, 0);
|
||||
|
||||
// Optimize to being a global block.
|
||||
Elts[0] = CGM.getNSConcreteGlobalBlock();
|
||||
|
@ -231,13 +285,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
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)
|
||||
Types[i] = Elts[i]->getType();
|
||||
Types[4] = PtrToInt8Ty;
|
||||
|
||||
for (unsigned i = 0, n = subBlockLayout.size(); i != n; ++i) {
|
||||
const Expr *E = subBlockLayout[i];
|
||||
for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) {
|
||||
const Expr *E = Info.BlockLayout[i];
|
||||
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
|
||||
QualType Ty = E->getType();
|
||||
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::AllocaInst *A = CreateTempAlloca(Ty);
|
||||
A->setAlignment(subBlockAlign.getQuantity());
|
||||
A->setAlignment(Info.BlockAlign.getQuantity());
|
||||
V = A;
|
||||
|
||||
// Build layout / cleanup information for all the data entries in the
|
||||
// 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;
|
||||
|
||||
for (unsigned i=0; i<4; ++i)
|
||||
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
|
||||
|
||||
for (unsigned i=0; i < subBlockLayout.size(); ++i) {
|
||||
const Expr *E = subBlockLayout[i];
|
||||
for (unsigned i=0; i < Info.BlockLayout.size(); ++i) {
|
||||
const Expr *E = Info.BlockLayout[i];
|
||||
|
||||
// Skip padding.
|
||||
if (isa<DeclRefExpr>(E)) continue;
|
||||
|
@ -354,8 +408,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
|
||||
// __descriptor
|
||||
llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE,
|
||||
subBlockHasCopyDispose,
|
||||
subBlockSize, Ty,
|
||||
Info.BlockHasCopyDispose,
|
||||
Info.BlockSize, Ty,
|
||||
&NoteForHelper);
|
||||
Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty);
|
||||
Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp"));
|
||||
|
@ -542,8 +596,8 @@ void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
|
|||
BlockLayout.push_back(E);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
|
||||
const ValueDecl *VD = E->getDecl();
|
||||
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD,
|
||||
bool IsByRef) {
|
||||
CharUnits offset = BlockDecls[VD];
|
||||
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),
|
||||
offset.getQuantity()),
|
||||
"block.literal");
|
||||
if (E->isByRef()) {
|
||||
if (IsByRef) {
|
||||
const llvm::Type *PtrStructTy
|
||||
= llvm::PointerType::get(BuildByRefType(VD), 0);
|
||||
// The block literal will need a copy/destroy helper.
|
||||
|
@ -578,19 +632,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
|
|||
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 *
|
||||
BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
|
||||
// Generate the block descriptor.
|
||||
|
@ -635,19 +676,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
|
|||
|
||||
std::vector<llvm::Constant*> LiteralFields(FieldCount);
|
||||
|
||||
CodeGenFunction::BlockInfo Info(0, n);
|
||||
CharUnits subBlockSize;
|
||||
CharUnits subBlockAlign;
|
||||
llvm::SmallVector<const Expr *, 8> subBlockLayout;
|
||||
bool subBlockHasCopyDispose = false;
|
||||
CGBlockInfo Info(n);
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
|
||||
llvm::Function *Fn
|
||||
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap,
|
||||
subBlockSize,
|
||||
subBlockAlign,
|
||||
subBlockLayout,
|
||||
subBlockHasCopyDispose);
|
||||
assert(subBlockSize == BlockLiteralSize
|
||||
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap);
|
||||
assert(Info.BlockSize == BlockLiteralSize
|
||||
&& "no imports allowed for global block");
|
||||
|
||||
// isa
|
||||
|
@ -686,13 +719,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() {
|
|||
|
||||
llvm::Function *
|
||||
CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
||||
const BlockInfo& Info,
|
||||
CGBlockInfo &Info,
|
||||
const Decl *OuterFuncDecl,
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
|
||||
CharUnits &Size,
|
||||
CharUnits &Align,
|
||||
llvm::SmallVectorImpl<const Expr *> &subBlockLayout,
|
||||
bool &subBlockHasCopyDispose) {
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> ldm) {
|
||||
|
||||
// Check if we should generate debug info for this block.
|
||||
if (CGM.getDebugInfo())
|
||||
|
@ -737,7 +766,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
|||
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
|
||||
|
||||
// Build the block struct now.
|
||||
AllocateAllBlockDeclRefs(Info, this);
|
||||
AllocateAllBlockDeclRefs(*this, Info);
|
||||
|
||||
QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose,
|
||||
BlockLayout);
|
||||
|
@ -795,6 +824,13 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
|||
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.
|
||||
llvm::BasicBlock *entry = Builder.GetInsertBlock();
|
||||
llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
|
||||
|
@ -837,10 +873,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
|||
llvm::RoundUpToAlignment(BlockOffset.getQuantity(),
|
||||
MinAlign.getQuantity()));
|
||||
|
||||
Size = BlockOffset;
|
||||
Align = BlockAlign;
|
||||
subBlockLayout = BlockLayout;
|
||||
subBlockHasCopyDispose |= BlockHasCopyDispose;
|
||||
Info.BlockSize = BlockOffset;
|
||||
Info.BlockAlign = BlockAlign;
|
||||
Info.BlockLayout = BlockLayout;
|
||||
Info.BlockHasCopyDispose = BlockHasCopyDispose;
|
||||
return Fn;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,30 +148,6 @@ public:
|
|||
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;
|
||||
|
||||
BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B);
|
||||
|
|
|
@ -494,8 +494,6 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
|
|||
|
||||
llvm::Value *CodeGenFunction::LoadObjCSelf() {
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace CodeGen {
|
|||
class CGDebugInfo;
|
||||
class CGFunctionInfo;
|
||||
class CGRecordLayout;
|
||||
class CGBlockInfo;
|
||||
|
||||
/// CodeGenFunction - This class organizes the per-function state that is used
|
||||
/// while generating LLVM code.
|
||||
|
@ -501,19 +502,18 @@ public:
|
|||
std::vector<HelperInfo> *);
|
||||
|
||||
llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr,
|
||||
const BlockInfo& Info,
|
||||
CGBlockInfo &Info,
|
||||
const Decl *OuterFuncDecl,
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
|
||||
CharUnits &Size, CharUnits &Align,
|
||||
llvm::SmallVectorImpl<const Expr*> &subBlockDeclRefDecls,
|
||||
bool &subBlockHasCopyDispose);
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> ldm);
|
||||
|
||||
void BlockForwardSelf();
|
||||
llvm::Value *LoadBlockStruct();
|
||||
|
||||
void AllocateBlockCXXThisPointer(const CXXThisExpr *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);
|
||||
|
||||
void GenerateCode(GlobalDecl GD, llvm::Function *Fn);
|
||||
|
|
|
@ -31,5 +31,11 @@ void foo(T *P) {
|
|||
-(void) im1 {
|
||||
^(void) { [self im0]; }();
|
||||
}
|
||||
-(void) im2 {
|
||||
^{ [super im0]; }();
|
||||
}
|
||||
-(void) im3 {
|
||||
^{ ^{[super im0];}(); }();
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче