aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h4
-rw-r--r--include/clang/AST/Decl.h74
-rw-r--r--include/clang/AST/Expr.h24
-rw-r--r--include/clang/Sema/ScopeInfo.h7
-rw-r--r--lib/AST/ASTContext.cpp9
-rw-r--r--lib/AST/Decl.cpp23
-rw-r--r--lib/AST/Expr.cpp7
-rw-r--r--lib/AST/StmtDumper.cpp52
-rw-r--r--lib/AST/StmtProfile.cpp2
-rw-r--r--lib/CodeGen/CGBlocks.cpp1655
-rw-r--r--lib/CodeGen/CGBlocks.h69
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp30
-rw-r--r--lib/CodeGen/CGDebugInfo.h14
-rw-r--r--lib/CodeGen/CGDecl.cpp7
-rw-r--r--lib/CodeGen/CGExpr.cpp4
-rw-r--r--lib/CodeGen/CGExprScalar.cpp4
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp4
-rw-r--r--lib/CodeGen/CGObjCMac.cpp92
-rw-r--r--lib/CodeGen/CGObjCRuntime.h6
-rw-r--r--lib/CodeGen/CodeGenFunction.h90
-rw-r--r--lib/Rewrite/RewriteObjC.cpp3
-rw-r--r--lib/Sema/SemaExpr.cpp210
-rw-r--r--lib/Sema/SemaExprObjC.cpp13
-rw-r--r--lib/Sema/TreeTransform.h4
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp21
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp3
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp16
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp1
-rw-r--r--test/CXX/expr/expr.cast/p4.cpp8
-rw-r--r--test/CodeGen/blocks-1.c24
-rw-r--r--test/CodeGen/blocksignature.c8
-rw-r--r--test/CodeGen/blockstret.c2
-rw-r--r--test/CodeGenObjC/block-var-layout.m91
-rw-r--r--test/CodeGenObjCXX/block-var-layout.mm73
34 files changed, 1467 insertions, 1187 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 6d3a9f0619..8a05730154 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -855,9 +855,9 @@ public:
void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S)
const;
- /// getObjCEncodingForBlockDecl - Return the encoded type for this block
+ /// getObjCEncodingForBlock - Return the encoded type for this block
/// declaration.
- void getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S) const;
+ std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const;
/// getObjCEncodingForPropertyDecl - Return the encoded type for
/// this method declaration. If non-NULL, Container must be either
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 485883e18b..f81f9d0ca4 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2493,6 +2493,46 @@ public:
/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
///
class BlockDecl : public Decl, public DeclContext {
+public:
+ /// A class which contains all the information about a particular
+ /// captured value.
+ class Capture {
+ enum {
+ flag_isByRef = 0x1,
+ flag_isNested = 0x2
+ };
+
+ /// The variable being captured.
+ llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags;
+
+ /// The copy expression, expressed in terms of a DeclRef (or
+ /// BlockDeclRef) to the captured variable. Only required if the
+ /// variable has a C++ class type.
+ Expr *CopyExpr;
+
+ public:
+ Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy)
+ : VariableAndFlags(variable,
+ (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)),
+ CopyExpr(copy) {}
+
+ /// The variable being captured.
+ VarDecl *getVariable() const { return VariableAndFlags.getPointer(); }
+
+ /// Whether this is a "by ref" capture, i.e. a capture of a __block
+ /// variable.
+ bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; }
+
+ /// Whether this is a nested capture, i.e. the variable captured
+ /// is not from outside the immediately enclosing function/block.
+ bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; }
+
+ bool hasCopyExpr() const { return CopyExpr != 0; }
+ Expr *getCopyExpr() const { return CopyExpr; }
+ void setCopyExpr(Expr *e) { CopyExpr = e; }
+ };
+
+private:
// FIXME: This can be packed into the bitfields in Decl.
bool IsVariadic : 1;
bool CapturesCXXThis : 1;
@@ -2505,15 +2545,15 @@ class BlockDecl : public Decl, public DeclContext {
Stmt *Body;
TypeSourceInfo *SignatureAsWritten;
- VarDecl **CapturedDecls;
- unsigned NumCapturedDecls;
+ Capture *Captures;
+ unsigned NumCaptures;
protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block),
IsVariadic(false), CapturesCXXThis(false),
ParamInfo(0), NumParams(0), Body(0),
- SignatureAsWritten(0), CapturedDecls(0), NumCapturedDecls(0) {}
+ SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
@@ -2555,25 +2595,25 @@ public:
/// hasCaptures - True if this block (or its nested blocks) captures
/// anything of local storage from its enclosing scopes.
- bool hasCaptures() const { return NumCapturedDecls != 0 || CapturesCXXThis; }
+ bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; }
- unsigned getNumCapturedDecls() const { return NumCapturedDecls; }
+ /// getNumCaptures - Returns the number of captured variables.
+ /// Does not include an entry for 'this'.
+ unsigned getNumCaptures() const { return NumCaptures; }
- typedef VarDecl * const *capture_iterator;
- typedef VarDecl const * const *capture_const_iterator;
- capture_iterator capture_begin() { return CapturedDecls; }
- capture_iterator capture_end() { return CapturedDecls + NumCapturedDecls; }
- capture_const_iterator capture_begin() const { return CapturedDecls; }
- capture_const_iterator capture_end() const {
- return CapturedDecls + NumCapturedDecls;
- }
+ typedef const Capture *capture_iterator;
+ typedef const Capture *capture_const_iterator;
+ capture_iterator capture_begin() { return Captures; }
+ capture_iterator capture_end() { return Captures + NumCaptures; }
+ capture_const_iterator capture_begin() const { return Captures; }
+ capture_const_iterator capture_end() const { return Captures + NumCaptures; }
bool capturesCXXThis() const { return CapturesCXXThis; }
- void setCapturedDecls(ASTContext &Context,
- VarDecl * const *begin,
- VarDecl * const *end,
- bool capturesCXXThis);
+ void setCaptures(ASTContext &Context,
+ const Capture *begin,
+ const Capture *end,
+ bool capturesCXXThis);
virtual SourceRange getSourceRange() const;
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index cf1faf1aff..247a4d10ba 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -3565,27 +3565,25 @@ public:
virtual child_iterator child_end();
};
-/// BlockDeclRefExpr - A reference to a declared variable, function,
-/// enum, etc.
+/// BlockDeclRefExpr - A reference to a local variable declared in an
+/// enclosing scope.
class BlockDeclRefExpr : public Expr {
- ValueDecl *D;
+ VarDecl *D;
SourceLocation Loc;
bool IsByRef : 1;
bool ConstQualAdded : 1;
- Stmt *CopyConstructorVal;
public:
- BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
- SourceLocation l, bool ByRef, bool constAdded = false,
- Stmt *copyConstructorVal = 0);
+ BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
+ SourceLocation l, bool ByRef, bool constAdded = false);
// \brief Build an empty reference to a declared variable in a
// block.
explicit BlockDeclRefExpr(EmptyShell Empty)
: Expr(BlockDeclRefExprClass, Empty) { }
- ValueDecl *getDecl() { return D; }
- const ValueDecl *getDecl() const { return D; }
- void setDecl(ValueDecl *VD) { D = VD; }
+ VarDecl *getDecl() { return D; }
+ const VarDecl *getDecl() const { return D; }
+ void setDecl(VarDecl *VD) { D = VD; }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -3598,12 +3596,6 @@ public:
bool isConstQualAdded() const { return ConstQualAdded; }
void setConstQualAdded(bool C) { ConstQualAdded = C; }
- const Expr *getCopyConstructorExpr() const
- { return cast_or_null<Expr>(CopyConstructorVal); }
- Expr *getCopyConstructorExpr()
- { return cast_or_null<Expr>(CopyConstructorVal); }
- void setCopyConstructorExpr(Expr *E) { CopyConstructorVal = E; }
-
static bool classof(const Stmt *T) {
return T->getStmtClass() == BlockDeclRefExprClass;
}
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 0ba61b34eb..edd1432d8e 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -116,8 +116,11 @@ public:
/// Its return type may be BuiltinType::Dependent.
QualType FunctionType;
- /// Captures - The set of variables captured by this block.
- llvm::SmallSetVector<VarDecl*, 4> Captures;
+ /// CaptureMap - A map of captured variables to (index+1) into Captures.
+ llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+
+ /// Captures - The captured variables.
+ llvm::SmallVector<BlockDecl::Capture, 4> Captures;
/// CapturesCXXThis - Whether this block captures 'this'.
bool CapturesCXXThis;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d96d079908..63e84d4131 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3693,10 +3693,11 @@ std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
}
-/// getObjCEncodingForBlockDecl - Return the encoded type for this block
+/// getObjCEncodingForBlock - Return the encoded type for this block
/// declaration.
-void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
- std::string& S) const {
+std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
+ std::string S;
+
const BlockDecl *Decl = Expr->getBlockDecl();
QualType BlockTy =
Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
@@ -3739,6 +3740,8 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return S;
}
void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index db69e0878a..4fb47bfcdc 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2104,21 +2104,26 @@ void BlockDecl::setParams(ParmVarDecl **NewParamInfo,
}
}
-void BlockDecl::setCapturedDecls(ASTContext &Context,
- VarDecl * const *begin,
- VarDecl * const *end,
- bool capturesCXXThis) {
+void BlockDecl::setCaptures(ASTContext &Context,
+ const Capture *begin,
+ const Capture *end,
+ bool capturesCXXThis) {
CapturesCXXThis = capturesCXXThis;
if (begin == end) {
- NumCapturedDecls = 0;
- CapturedDecls = 0;
+ NumCaptures = 0;
+ Captures = 0;
return;
}
- NumCapturedDecls = end - begin;
- CapturedDecls = new (Context) VarDecl*[NumCapturedDecls];
- memcpy(CapturedDecls, begin, NumCapturedDecls * sizeof(VarDecl*));
+ NumCaptures = end - begin;
+
+ // Avoid new Capture[] because we don't want to provide a default
+ // constructor.
+ size_t allocationSize = NumCaptures * sizeof(Capture);
+ void *buffer = Context.Allocate(allocationSize, /*alignment*/sizeof(void*));
+ memcpy(buffer, begin, allocationSize);
+ Captures = static_cast<Capture*>(buffer);
}
SourceRange BlockDecl::getSourceRange() const {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 04498f7b9a..b22d9d5452 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2961,13 +2961,12 @@ Stmt::child_iterator ObjCMessageExpr::child_end() {
}
// Blocks
-BlockDeclRefExpr::BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
+BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
SourceLocation l, bool ByRef,
- bool constAdded, Stmt *copyConstructorVal)
+ bool constAdded)
: Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false,
d->isParameterPack()),
- D(d), Loc(l), IsByRef(ByRef),
- ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal)
+ D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded)
{
bool TypeDependent = false;
bool ValueDependent = false;
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 8b62dcc940..5def7d9a0b 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -100,6 +100,7 @@ namespace {
OS << ":'" << QualType::getAsString(D_split) << "'";
}
}
+ void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
Indent();
OS << "(" << Node->getStmtClassName()
@@ -153,6 +154,7 @@ namespace {
void VisitBinaryOperator(BinaryOperator *Node);
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
void VisitAddrLabelExpr(AddrLabelExpr *Node);
+ void VisitBlockExpr(BlockExpr *Node);
// C++
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -362,21 +364,21 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
OS << " ";
- switch (Node->getDecl()->getKind()) {
- default: OS << "Decl"; break;
- case Decl::Function: OS << "FunctionDecl"; break;
- case Decl::Var: OS << "Var"; break;
- case Decl::ParmVar: OS << "ParmVar"; break;
- case Decl::EnumConstant: OS << "EnumConstant"; break;
- case Decl::Typedef: OS << "Typedef"; break;
- case Decl::Record: OS << "Record"; break;
- case Decl::Enum: OS << "Enum"; break;
- case Decl::CXXRecord: OS << "CXXRecord"; break;
- case Decl::ObjCInterface: OS << "ObjCInterface"; break;
- case Decl::ObjCClass: OS << "ObjCClass"; break;
+ DumpDeclRef(Node->getDecl());
+}
+
+void StmtDumper::DumpDeclRef(Decl *d) {
+ OS << d->getDeclKindName() << ' ' << (void*) d;
+
+ if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
+ OS << " '";
+ nd->getDeclName().printName(OS);
+ OS << "'";
}
- OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl();
+ if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
+ OS << ' '; DumpType(vd->getType());
+ }
}
void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
@@ -474,6 +476,30 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
DumpType(Node->getComputationResultType());
}
+void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
+ DumpExpr(Node);
+
+ IndentLevel++;
+ BlockDecl *block = Node->getBlockDecl();
+ if (block->capturesCXXThis()) {
+ OS << '\n'; Indent(); OS << "(capture this)";
+ }
+ for (BlockDecl::capture_iterator
+ i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
+ OS << '\n';
+ Indent();
+ OS << "(capture ";
+ if (i->isByRef()) OS << "byref ";
+ if (i->isNested()) OS << "nested ";
+ DumpDeclRef(i->getVariable());
+ if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
+ OS << ")";
+ }
+ IndentLevel--;
+
+ DumpSubTree(block->getBody());
+}
+
// GNU extensions.
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index e75c274015..842a2d92d8 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -425,8 +425,6 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
VisitDecl(S->getDecl());
ID.AddBoolean(S->isByRef());
ID.AddBoolean(S->isConstQualAdded());
- if (S->getCopyConstructorExpr())
- Visit(S->getCopyConstructorExpr());
}
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index a594a0bb9e..bdbc9d3b55 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -24,141 +24,84 @@
using namespace clang;
using namespace CodeGen;
-CGBlockInfo::CGBlockInfo(const char *N)
- : Name(N), CXXThisRef(0), NeedsObjCSelf(false),
- HasCXXObject(false) {
+CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N)
+ : Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
+ HasCXXObject(false), HasWeakBlockVariable(false),
+ StructureType(0), Block(blockExpr) {
// Skip asm prefix, if any.
if (Name && Name[0] == '\01')
++Name;
}
+/// Build the given block as a global block.
+static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo,
+ llvm::Constant *blockFn);
-llvm::Constant *CodeGenFunction::
-BuildDescriptorBlockDecl(const BlockExpr *BE, const CGBlockInfo &Info,
- const llvm::StructType* Ty,
- llvm::Constant *BlockVarLayout,
- std::vector<HelperInfo> *NoteForHelper) {
- CharUnits Size = Info.BlockSize;
- const llvm::Type *UnsignedLongTy
- = CGM.getTypes().ConvertType(getContext().UnsignedLongTy);
- llvm::Constant *C;
- std::vector<llvm::Constant*> Elts;
+/// Build the helper function to copy a block.
+static llvm::Constant *buildCopyHelper(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ return CodeGenFunction(CGM).GenerateCopyHelperFunction(blockInfo);
+}
+
+/// Build the helper function to dipose of a block.
+static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
+}
+
+/// Build the block descriptor constant for a block.
+static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ ASTContext &C = CGM.getContext();
+
+ const llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy);
+ const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
+
+ llvm::SmallVector<llvm::Constant*, 6> elements;
// reserved
- C = llvm::ConstantInt::get(UnsignedLongTy, 0);
- Elts.push_back(C);
+ elements.push_back(llvm::ConstantInt::get(ulong, 0));
// Size
// FIXME: What is the right way to say this doesn't fit? We should give
// a user diagnostic in that case. Better fix would be to change the
// API to size_t.
- C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity());
- Elts.push_back(C);
+ elements.push_back(llvm::ConstantInt::get(ulong,
+ blockInfo.BlockSize.getQuantity()));
- // optional copy/dispose helpers
- if (Info.BlockHasCopyDispose) {
+ // Optional copy/dispose helpers.
+ if (blockInfo.NeedsCopyDispose) {
// copy_func_helper_decl
- Elts.push_back(BuildCopyHelper(Ty, NoteForHelper));
+ elements.push_back(buildCopyHelper(CGM, blockInfo));
// destroy_func_decl
- Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper));
+ elements.push_back(buildDisposeHelper(CGM, blockInfo));
}
- // Signature. non-optional ObjC-style method descriptor @encode sequence
- std::string BlockTypeEncoding;
- CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
-
- Elts.push_back(llvm::ConstantExpr::getBitCast(
- CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty));
+ // Signature. Mandatory ObjC-style method descriptor @encode sequence.
+ std::string typeAtEncoding =
+ CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr());
+ elements.push_back(llvm::ConstantExpr::getBitCast(
+ CGM.GetAddrOfConstantCString(typeAtEncoding), i8p));
- // Layout.
- C = BlockVarLayout;
-
- Elts.push_back(C);
-
- C = llvm::ConstantStruct::get(VMContext, Elts, false);
-
- C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- C, "__block_descriptor_tmp");
- return C;
-}
-
-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);
-
- // 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)) {
- Info.InnerBlocks.insert(BE->getBlockDecl());
- CollectBlockDeclRefInfo(BE->getBody(), Info);
- }
-
- else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- const ValueDecl *D = BDRE->getDecl();
- // FIXME: Handle enums.
- 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 (!Info.InnerBlocks.count(D->getDeclContext())) {
- if (BDRE->getCopyConstructorExpr())
- Info.HasCXXObject = true;
- Info.DeclRefs.push_back(BDRE);
- }
- }
+ // GC layout.
+ if (C.getLangOptions().ObjC1)
+ elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
+ else
+ elements.push_back(llvm::Constant::getNullValue(i8p));
- // 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;
- }
- else if (const ObjCPropertyRefExpr *PE = dyn_cast<ObjCPropertyRefExpr>(S)) {
- // Getter/setter uses may also cause implicit super references,
- // which we can check for with:
- if (PE->isSuperReceiver())
- Info.NeedsObjCSelf = true;
- }
- else if (isa<CXXThisExpr>(S))
- Info.CXXThisRef = cast<CXXThisExpr>(S);
-}
+ llvm::Constant *init =
+ llvm::ConstantStruct::get(CGM.getLLVMContext(), elements.data(),
+ elements.size(), false);
-/// 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 CGBlockInfo &Info) {
- return Info.DeclRefs.empty();
-}
+ llvm::GlobalVariable *global =
+ new llvm::GlobalVariable(CGM.getModule(), init->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ init, "__block_descriptor_tmp");
-/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to
-/// ensure we can generate the debug information for the parameter for the block
-/// invoke function.
-static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) {
- if (Info.CXXThisRef)
- CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef);
-
- for (size_t i = 0; i < Info.DeclRefs.size(); ++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(), VK_RValue,
- SourceLocation(), false);
- Info.DeclRefs.push_back(BDRE);
- CGF.AllocateBlockDecl(BDRE);
- }
+ return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType());
}
static unsigned computeBlockFlag(CodeGenModule &CGM,
@@ -176,256 +119,506 @@ static unsigned computeBlockFlag(CodeGenModule &CGM,
return flags;
}
-// 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();
- CGBlockInfo Info(Name.c_str());
- Info.InnerBlocks.insert(BE->getBlockDecl());
- CollectBlockDeclRefInfo(BE->getBody(), Info);
+/*
+ Purely notional variadic template describing the layout of a block.
+
+ template <class _ResultType, class... _ParamTypes, class... _CaptureTypes>
+ struct Block_literal {
+ /// Initialized to one of:
+ /// extern void *_NSConcreteStackBlock[];
+ /// extern void *_NSConcreteGlobalBlock[];
+ ///
+ /// In theory, we could start one off malloc'ed by setting
+ /// BLOCK_NEEDS_FREE, giving it a refcount of 1, and using
+ /// this isa:
+ /// extern void *_NSConcreteMallocBlock[];
+ struct objc_class *isa;
+
+ /// These are the flags (with corresponding bit number) that the
+ /// compiler is actually supposed to know about.
+ /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block
+ /// descriptor provides copy and dispose helper functions
+ /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured
+ /// object with a nontrivial destructor or copy constructor
+ /// 28. BLOCK_IS_GLOBAL - indicates that the block is allocated
+ /// as global memory
+ /// 29. BLOCK_USE_STRET - indicates that the block function
+ /// uses stret, which objc_msgSend needs to know about
+ /// 30. BLOCK_HAS_SIGNATURE - indicates that the block has an
+ /// @encoded signature string
+ /// And we're not supposed to manipulate these:
+ /// 24. BLOCK_NEEDS_FREE - indicates that the block has been moved
+ /// to malloc'ed memory
+ /// 27. BLOCK_IS_GC - indicates that the block has been moved to
+ /// to GC-allocated memory
+ /// Additionally, the bottom 16 bits are a reference count which
+ /// should be zero on the stack.
+ int flags;
+
+ /// Reserved; should be zero-initialized.
+ int reserved;
+
+ /// Function pointer generated from block literal.
+ _ResultType (*invoke)(Block_literal *, _ParamTypes...);
+
+ /// Block description metadata generated from block literal.
+ struct Block_descriptor *block_descriptor;
+
+ /// Captured values follow.
+ _CapturesTypes captures...;
+ };
+ */
+
+/// The number of fields in a block header.
+const unsigned BlockHeaderSize = 5;
+
+namespace {
+ /// A chunk of data that we actually have to capture in the block.
+ struct BlockLayoutChunk {
+ CharUnits Alignment;
+ CharUnits Size;
+ const BlockDecl::Capture *Capture; // null for 'this'
+ const llvm::Type *Type;
+
+ BlockLayoutChunk(CharUnits align, CharUnits size,
+ const BlockDecl::Capture *capture,
+ const llvm::Type *type)
+ : Alignment(align), Size(size), Capture(capture), Type(type) {}
+
+ /// Tell the block info that this chunk has the given field index.
+ void setIndex(CGBlockInfo &info, unsigned index) {
+ if (!Capture)
+ info.CXXThisIndex = index;
+ else
+ info.Captures[Capture->getVariable()]
+ = CGBlockInfo::Capture::makeIndex(index);
+ }
+ };
- // Check if the block can be global.
- // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like
- // to just have one code path. We should move this function into CGM and pass
- // CGF, then we can just check to see if CGF is 0.
- if (0 && CanBlockBeGlobal(Info))
- return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
+ /// Order by descending alignment.
+ bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) {
+ return left.Alignment > right.Alignment;
+ }
+}
- size_t BlockFields = 5;
+/// It is illegal to modify a const object after initialization.
+/// Therefore, if a const object has a constant initializer, we don't
+/// actually need to keep storage for it in the block; we'll just
+/// rematerialize it at the start of the block function. This is
+/// acceptable because we make no promises about address stability of
+/// captured variables.
+static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
+ const VarDecl *var) {
+ QualType type = var->getType();
+
+ // We can only do this if the variable is const.
+ if (!type.isConstQualified()) return 0;
+
+ // Furthermore, in C++ we can't do this for classes. TODO: we might
+ // actually be able to get away with it for classes with a trivial
+ // destructor and a trivial copy constructor and no mutable fields.
+ if (CGM.getLangOptions().CPlusPlus &&
+ type->getBaseElementTypeUnsafe()->isRecordType())
+ return 0;
+
+ // If the variable doesn't have any initializer (shouldn't this be
+ // invalid?), it's not clear what we should do. Maybe capture as
+ // zero?
+ const Expr *init = var->getInit();
+ if (!init) return 0;
+
+ return CGM.EmitConstantExpr(init, var->getType());
+}
- std::vector<llvm::Constant*> Elts(BlockFields);
+/// Get the low bit of a nonzero character count. This is the
+/// alignment of the nth byte if the 0th byte is universally aligned.
+static CharUnits getLowBit(CharUnits v) {
+ return CharUnits::fromQuantity(v.getQuantity() & (~v.getQuantity() + 1));
+}
- llvm::Constant *C;
- llvm::Value *V;
+static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
+ std::vector<const llvm::Type*> &elementTypes) {
+ ASTContext &C = CGM.getContext();
- bool hasWeakBlockVariable = false;
+ // The header is basically a 'struct { void *; int; int; void *; void *; }'.
+