diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 46 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 301 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.h | 32 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/blocks.cpp | 32 |
9 files changed, 284 insertions, 164 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index c9e27db566..a6b4254db3 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -482,7 +482,7 @@ public: /// This gets the struct used to keep track of pointer to blocks, complete /// with captured variables. QualType getBlockParmType(bool BlockHasCopyDispose, - llvm::SmallVector<const Expr *, 8> &BDRDs); + llvm::SmallVectorImpl<const Expr *> &Layout); /// This builds the struct used for __block variables. QualType BuildByRefType(const char *DeclName, QualType Ty); @@ -910,6 +910,9 @@ public: CharUnits getTypeAlignInChars(QualType T); CharUnits getTypeAlignInChars(const Type *T); + std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T); + std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T); + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 23478e4f3c..720a88c6b6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" @@ -421,6 +422,18 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { return CharUnits::fromQuantity(Align / Target.getCharWidth()); } +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoInChars(const Type *T) { + std::pair<uint64_t, unsigned> Info = getTypeInfo(T); + return std::make_pair(CharUnits::fromQuantity(Info.first / getCharWidth()), + CharUnits::fromQuantity(Info.second / getCharWidth())); +} + +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoInChars(QualType T) { + return getTypeInfoInChars(T.getTypePtr()); +} + /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. /// @@ -3070,7 +3083,8 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { QualType ASTContext::getBlockParmType( bool BlockHasCopyDispose, - llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) { + llvm::SmallVectorImpl<const Expr *> &Layout) { + // FIXME: Move up static unsigned int UniqueBlockParmTypeID = 0; llvm::SmallString<36> Name; @@ -3107,22 +3121,28 @@ QualType ASTContext::getBlockParmType( T->addDecl(Field); } - for (size_t i = 0; i < BlockDeclRefDecls.size(); ++i) { - const Expr *E = BlockDeclRefDecls[i]; - const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); - clang::IdentifierInfo *Name = 0; - if (BDRE) { + for (unsigned i = 0; i < Layout.size(); ++i) { + const Expr *E = Layout[i]; + + QualType FieldType = E->getType(); + IdentifierInfo *FieldName = 0; + if (isa<CXXThisExpr>(E)) { + FieldName = &Idents.get("this"); + } else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E)) { const ValueDecl *D = BDRE->getDecl(); - Name = &Idents.get(D->getName()); + FieldName = D->getIdentifier(); + if (BDRE->isByRef()) + FieldType = BuildByRefType(D->getNameAsCString(), FieldType); + } else { + // Padding. + assert(isa<ConstantArrayType>(FieldType) && + isa<DeclRefExpr>(E) && + !cast<DeclRefExpr>(E)->getDecl()->getDeclName() && + "doesn't match characteristics of padding decl"); } - QualType FieldType = E->getType(); - - if (BDRE && BDRE->isByRef()) - FieldType = BuildByRefType(BDRE->getDecl()->getNameAsCString(), - FieldType); FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), - Name, FieldType, /*TInfo=*/0, + FieldName, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); Field->setAccess(AS_public); T->addDecl(Field); diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index f157f2f406..7b4eb8f582 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -110,6 +110,9 @@ static void CollectBlockDeclRefInfo( if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) Info.DeclRefs.push_back(BDRE); } + + if (isa<CXXThisExpr>(S)) + Info.CXXThisRef = cast<CXXThisExpr>(S); } /// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be @@ -123,7 +126,8 @@ static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { /// invoke function. static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, CodeGenFunction *CGF) { - // FIXME: Also always forward the this pointer in C++ as well. + if (Info.CXXThisRef) + CGF->AllocateBlockCXXThisPointer(Info.CXXThisRef); for (size_t i = 0; i < Info.DeclRefs.size(); ++i) CGF->AllocateBlockDecl(Info.DeclRefs[i]); @@ -162,14 +166,14 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // __invoke CharUnits subBlockSize; CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; + llvm::SmallVector<const Expr *, 8> subBlockLayout; bool subBlockHasCopyDispose = false; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, LocalDeclMap, subBlockSize, subBlockAlign, - subBlockDeclRefDecls, + subBlockLayout, subBlockHasCopyDispose); BlockHasCopyDispose |= subBlockHasCopyDispose; Elts[3] = Fn; @@ -206,7 +210,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantInt::get(IntTy, 0); Elts[2] = C; - if (subBlockDeclRefDecls.size() == 0) { + if (subBlockLayout.empty()) { // __descriptor Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, 0, 0); @@ -227,13 +231,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { return C; } - std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size()); + std::vector<const llvm::Type *> Types(BlockFields+subBlockLayout.size()); for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; - for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { - const Expr *E = subBlockDeclRefDecls[i]; + for (unsigned i = 0, n = subBlockLayout.size(); i != n; ++i) { + const Expr *E = subBlockLayout[i]; const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { @@ -248,97 +252,105 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { A->setAlignment(subBlockAlign.getQuantity()); V = A; - std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size()); - int helpersize = 0; + // 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()); + 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 < subBlockDeclRefDecls.size(); ++i) - { - // FIXME: Push const down. - Expr *E = const_cast<Expr*>(subBlockDeclRefDecls[i]); - DeclRefExpr *DR; - ValueDecl *VD; - - DR = dyn_cast<DeclRefExpr>(E); - // Skip padding. - if (DR) continue; - - BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); - VD = BDRE->getDecl(); - - llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); - NoteForHelper[helpersize].index = i+5; - NoteForHelper[helpersize].RequiresCopying - = BlockRequiresCopying(VD->getType()); - NoteForHelper[helpersize].flag - = (VD->getType()->isBlockPointerType() - ? BLOCK_FIELD_IS_BLOCK - : BLOCK_FIELD_IS_OBJECT); - - if (LocalDeclMap[VD]) { - if (BDRE->isByRef()) { - NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | - // FIXME: Someone double check this. - (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - llvm::Value *Loc = LocalDeclMap[VD]; - Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc); - Builder.CreateStore(Loc, Addr); - ++helpersize; - continue; - } else - E = new (getContext()) DeclRefExpr (VD, - VD->getType(), - SourceLocation()); - } + for (unsigned i=0; i < subBlockLayout.size(); ++i) { + const Expr *E = subBlockLayout[i]; + + // Skip padding. + if (isa<DeclRefExpr>(E)) continue; + + llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); + HelperInfo &Note = NoteForHelper[NumHelpers++]; + + Note.index = i+5; + + if (isa<CXXThisExpr>(E)) { + Note.RequiresCopying = false; + Note.flag = BLOCK_FIELD_IS_OBJECT; + + Builder.CreateStore(LoadCXXThis(), Addr); + continue; + } + + const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E); + const ValueDecl *VD = BDRE->getDecl(); + QualType T = VD->getType(); + + Note.RequiresCopying = BlockRequiresCopying(T); + + if (BDRE->isByRef()) { + Note.flag = BLOCK_FIELD_IS_BYREF; + if (T.isObjCGCWeak()) + Note.flag |= BLOCK_FIELD_IS_WEAK; + } else if (T->isBlockPointerType()) { + Note.flag = BLOCK_FIELD_IS_BLOCK; + } else { + Note.flag = BLOCK_FIELD_IS_OBJECT; + } + + if (LocalDeclMap[VD]) { if (BDRE->isByRef()) { - NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | - // FIXME: Someone double check this. - (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - E = new (getContext()) - UnaryOperator(E, UnaryOperator::AddrOf, - getContext().getPointerType(E->getType()), - SourceLocation()); - } - ++helpersize; - - RValue r = EmitAnyExpr(E, Addr, false); - if (r.isScalar()) { - llvm::Value *Loc = r.getScalarVal(); - const llvm::Type *Ty = Types[i+BlockFields]; - if (BDRE->isByRef()) { - // E is now the address of the value field, instead, we want the - // address of the actual ByRef struct. We optimize this slightly - // compared to gcc by not grabbing the forwarding slot as this must - // be done during Block_copy for us, and we can postpone the work - // until then. - CharUnits offset = BlockDecls[BDRE->getDecl()]; - - llvm::Value *BlockLiteral = LoadBlockStruct(); - - Loc = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset.getQuantity()), - "block.literal"); - Ty = llvm::PointerType::get(Ty, 0); - Loc = Builder.CreateBitCast(Loc, Ty); - Loc = Builder.CreateLoad(Loc); - // Loc = Builder.CreateBitCast(Loc, Ty); - } + llvm::Value *Loc = LocalDeclMap[VD]; + Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); + Loc = Builder.CreateLoad(Loc); Builder.CreateStore(Loc, Addr); - } else if (r.isComplex()) - // FIXME: implement - ErrorUnsupported(BE, "complex in block literal"); - else if (r.isAggregate()) - ; // Already created into the destination - else - assert (0 && "bad block variable"); - // FIXME: Ensure that the offset created by the backend for - // the struct matches the previously computed offset in BlockDecls. + continue; + } else { + E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD), + VD->getType(), + SourceLocation()); + } + } + + if (BDRE->isByRef()) { + E = new (getContext()) + UnaryOperator(const_cast<Expr*>(E), UnaryOperator::AddrOf, + getContext().getPointerType(E->getType()), + SourceLocation()); } - NoteForHelper.resize(helpersize); + + RValue r = EmitAnyExpr(E, Addr, false); + if (r.isScalar()) { + llvm::Value *Loc = r.getScalarVal(); + const llvm::Type *Ty = Types[i+BlockFields]; + if (BDRE->isByRef()) { + // E is now the address of the value field, instead, we want the + // address of the actual ByRef struct. We optimize this slightly + // compared to gcc by not grabbing the forwarding slot as this must + // be done during Block_copy for us, and we can postpone the work + // until then. + CharUnits offset = BlockDecls[BDRE->getDecl()]; + + llvm::Value *BlockLiteral = LoadBlockStruct(); + + Loc = Builder.CreateGEP(BlockLiteral, + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + offset.getQuantity()), + "block.literal"); + Ty = llvm::PointerType::get(Ty, 0); + Loc = Builder.CreateBitCast(Loc, Ty); + Loc = Builder.CreateLoad(Loc); + // Loc = Builder.CreateBitCast(Loc, Ty); + } + Builder.CreateStore(Loc, Addr); + } else if (r.isComplex()) + // FIXME: implement + ErrorUnsupported(BE, "complex in block literal"); + else if (r.isAggregate()) + ; // Already created into the destination + else + assert (0 && "bad block variable"); + // FIXME: Ensure that the offset created by the backend for + // the struct matches the previously computed offset in BlockDecls. + } + NoteForHelper.resize(NumHelpers); // __descriptor llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, @@ -487,13 +499,25 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, return EmitCall(FnInfo, Func, ReturnValue, Args); } -CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { +void CodeGenFunction::AllocateBlockCXXThisPointer(const CXXThisExpr *E) { + assert(BlockCXXThisOffset.isZero() && "already computed 'this' pointer"); + + // Figure out what the offset is. + QualType T = E->getType(); + std::pair<CharUnits,CharUnits> TypeInfo = getContext().getTypeInfoInChars(T); + CharUnits Offset = getBlockOffset(TypeInfo.first, TypeInfo.second); + + BlockCXXThisOffset = Offset; + BlockLayout.push_back(E); +} + +void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - CharUnits &offset = BlockDecls[VD]; + CharUnits &Offset = BlockDecls[VD]; // See if we have already allocated an offset for this variable. - if (offset.isPositive()) - return offset; + if (!Offset.isZero()) + return; // Don't run the expensive check, unless we have to. if (!BlockHasCopyDispose) @@ -501,16 +525,27 @@ CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { || BlockRequiresCopying(E->getType())) BlockHasCopyDispose = true; - // if not, allocate one now. - offset = getBlockOffset(E); + const ValueDecl *D = cast<ValueDecl>(E->getDecl()); + + CharUnits Size; + CharUnits Align; + + if (E->isByRef()) { + llvm::tie(Size,Align) = + getContext().getTypeInfoInChars(getContext().VoidPtrTy); + } else { + Size = getContext().getTypeSizeInChars(D->getType()); + Align = getContext().getDeclAlign(D); + } - return offset; + Offset = getBlockOffset(Size, Align); + BlockLayout.push_back(E); } llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - CharUnits offset = AllocateBlockDecl(E); - + CharUnits offset = BlockDecls[VD]; + assert(!offset.isZero() && "getting address of unallocated decl"); llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, @@ -603,14 +638,14 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { CodeGenFunction::BlockInfo Info(0, n); CharUnits subBlockSize; CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; + llvm::SmallVector<const Expr *, 8> subBlockLayout; bool subBlockHasCopyDispose = false; llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap, subBlockSize, subBlockAlign, - subBlockDeclRefDecls, + subBlockLayout, subBlockHasCopyDispose); assert(subBlockSize == BlockLiteralSize && "no imports allowed for global block"); @@ -656,7 +691,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, llvm::DenseMap<const Decl*, llvm::Value*> ldm, CharUnits &Size, CharUnits &Align, - llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, + llvm::SmallVectorImpl<const Expr *> &subBlockLayout, bool &subBlockHasCopyDispose) { // Check if we should generate debug info for this block. @@ -701,11 +736,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); - // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below. + // Build the block struct now. AllocateAllBlockDeclRefs(Info, this); QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, - BlockDeclRefDecls); + BlockLayout); + // FIXME: This leaks ImplicitParamDecl *SelfDecl = ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD), @@ -738,6 +774,27 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CurFuncDecl = OuterFuncDecl; CurCodeDecl = BD; + // If we have a C++ 'this' reference, go ahead and force it into + // existence now. + if (Info.CXXThisRef) { + assert(!BlockCXXThisOffset.isZero() && + "haven't yet allocated 'this' reference"); + + // TODO: I have a dream that one day this will be typed. + llvm::Value *BlockLiteral = LoadBlockStruct(); + llvm::Value *ThisPtrRaw = + Builder.CreateConstInBoundsGEP1_64(BlockLiteral, + BlockCXXThisOffset.getQuantity(), + "this.ptr.raw"); + + const llvm::Type *Ty = + CGM.getTypes().ConvertType(Info.CXXThisRef->getType()); + Ty = llvm::PointerType::get(Ty, 0); + llvm::Value *ThisPtr = Builder.CreateBitCast(ThisPtrRaw, Ty, "this.ptr"); + + CXXThisValue = Builder.CreateLoad(ThisPtr, "this"); + } + // Save a spot to insert the debug information for all the BlockDeclRefDecls. llvm::BasicBlock *entry = Builder.GetInsertBlock(); llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); @@ -754,9 +811,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, if (CGDebugInfo *DI = getDebugInfo()) { // Emit debug information for all the BlockDeclRefDecls. - for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) { - if (const BlockDeclRefExpr *BDRE = - dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) { + // FIXME: also for 'this' + for (unsigned i = 0, e = BlockLayout.size(); i != e; ++i) { + if (const BlockDeclRefExpr *BDRE = + dyn_cast<BlockDeclRefExpr>(BlockLayout[i])) { const ValueDecl *D = BDRE->getDecl(); DI->setLocation(D->getLocation()); DI->EmitDeclareOfBlockDeclRefVariable(BDRE, @@ -781,23 +839,13 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, Size = BlockOffset; Align = BlockAlign; - subBlockDeclRefDecls = BlockDeclRefDecls; + subBlockLayout = BlockLayout; subBlockHasCopyDispose |= BlockHasCopyDispose; return Fn; } -CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { - const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl()); - - CharUnits Size = getContext().getTypeSizeInChars(D->getType()); - CharUnits Align = getContext().getDeclAlign(D); - - if (BDRE->isByRef()) { - Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy); - Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy); - } - - assert ((Align.isPositive()) && "alignment must be 1 byte or more"); +CharUnits BlockFunction::getBlockOffset(CharUnits Size, CharUnits Align) { + assert((Align.isPositive()) && "alignment must be 1 byte or more"); CharUnits OldOffset = BlockOffset; @@ -808,7 +856,6 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { CharUnits Pad = BlockOffset - OldOffset; if (Pad.isPositive()) { - llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity()); QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, llvm::APInt(32, Pad.getQuantity()), @@ -818,15 +865,13 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { SourceLocation(), 0, QualType(PadTy), 0, VarDecl::None, VarDecl::None); - Expr *E; - E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), - SourceLocation()); - BlockDeclRefDecls.push_back(E); + Expr *E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), + SourceLocation()); + BlockLayout.push_back(E); } - BlockDeclRefDecls.push_back(BDRE); BlockOffset += Size; - return BlockOffset-Size; + return BlockOffset - Size; } llvm::Constant *BlockFunction:: diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 5646d0036e..067dfc7fdf 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -160,8 +160,12 @@ public: /// 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) { + : BlockLiteralTy(blt), Name(n), CXXThisRef(0) { // Skip asm prefix, if any. if (Name && Name[0] == '\01') ++Name; @@ -179,19 +183,31 @@ public: /// characters. CharUnits BlockAlign; - /// getBlockOffset - Allocate an offset for the ValueDecl from a - /// BlockDeclRefExpr in a block literal (BlockExpr). - CharUnits getBlockOffset(const BlockDeclRefExpr *E); + /// getBlockOffset - Allocate a location within the block's storage + /// for a value with the given size and alignment requirements. + CharUnits getBlockOffset(CharUnits Size, CharUnits Align); /// BlockHasCopyDispose - True iff the block uses copy/dispose. bool BlockHasCopyDispose; - /// BlockDeclRefDecls - Decls from BlockDeclRefExprs in apperance order - /// in a block literal. Decls without names are used for padding. - llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls; + /// BlockLayout - The layout of the block's storage, represented as + /// a sequence of expressions which require such storage. The + /// expressions can be: + /// - a BlockDeclRefExpr, indicating that the given declaration + /// from an enclosing scope is needed by the block; + /// - a DeclRefExpr, which always wraps an anonymous VarDecl with + /// array type, used to insert padding into the block; or + /// - a CXXThisExpr, indicating that the C++ 'this' value should + /// propagate from the parent to the block. + /// This is a really silly representation. + llvm::SmallVector<const Expr *, 8> BlockLayout; /// BlockDecls - Offsets for all Decls in BlockDeclRefExprs. - std::map<const Decl*, CharUnits> BlockDecls; + llvm::DenseMap<const Decl*, CharUnits> BlockDecls; + + /// BlockCXXThisOffset - The offset of the C++ 'this' value within + /// the block structure. + CharUnits BlockCXXThisOffset; ImplicitParamDecl *BlockStructDecl; ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index e3e7472317..077b8169f1 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -505,13 +505,14 @@ public: const Decl *OuterFuncDecl, llvm::DenseMap<const Decl*, llvm::Value*> ldm, CharUnits &Size, CharUnits &Align, - llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, + llvm::SmallVectorImpl<const Expr*> &subBlockDeclRefDecls, bool &subBlockHasCopyDispose); void BlockForwardSelf(); llvm::Value *LoadBlockStruct(); - CharUnits AllocateBlockDecl(const BlockDeclRefExpr *E); + void AllocateBlockCXXThisPointer(const CXXThisExpr *E); + void AllocateBlockDecl(const BlockDeclRefExpr *E); llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); const llvm::Type *BuildByRefType(const ValueDecl *D); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5e1f21b4c3..67c2fcbb9e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -602,7 +602,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + DeclContext *DC = getFunctionLevelDeclContext(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { if (!MD->isStatic()) { QualType AnonFieldType = Context.getTagDeclType( @@ -838,9 +839,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); + DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); bool isStaticContext = - (!isa<CXXMethodDecl>(SemaRef.CurContext) || - cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic()); + (!isa<CXXMethodDecl>(DC) || + cast<CXXMethodDecl>(DC)->isStatic()); if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -880,7 +882,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // declaring classes, it can't be an implicit member reference (in // which case it's an error if any of those members are selected). if (IsProvablyNotDerivedFrom(SemaRef, - cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(), + cast<CXXMethodDecl>(DC)->getParent(), Classes)) return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); @@ -1569,7 +1571,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // If this is known to be an instance access, go ahead and build a // 'this' expression now. - QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + DeclContext *DC = getFunctionLevelDeclContext(); + QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); Expr *This = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 62b7b4abbc..5849382050 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -466,10 +466,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - if (!isa<FunctionDecl>(CurContext)) - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); - - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) + DeclContext *DC = getFunctionLevelDeclContext(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) if (MD->isInstance()) return Owned(new (Context) CXXThisExpr(ThisLoc, MD->getThisType(Context), diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 91ef67e1c9..3242f70f12 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -330,11 +330,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + DeclContext *DC = getFunctionLevelDeclContext(); if (!isAddressOfOperand && - isa<CXXMethodDecl>(CurContext) && - cast<CXXMethodDecl>(CurContext)->isInstance()) { - QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + isa<CXXMethodDecl>(DC) && + cast<CXXMethodDecl>(DC)->isInstance()) { + QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp index 94295437e1..baa79e7d89 100644 --- a/test/SemaCXX/blocks.cpp +++ b/test/SemaCXX/blocks.cpp @@ -9,3 +9,35 @@ void tovoid_test(int (^f)(int, int)) { void reference_lvalue_test(int& (^f)()) { f() = 10; } + +// PR 7165 +namespace test1 { + void g(void (^)()); + struct Foo { + void foo(); + void test() { + (void) ^{ foo(); }; + } + }; +} + +namespace test2 { + int repeat(int value, int (^block)(int), unsigned n) { + while (n--) value = block(value); + return value; + } + + class Power { + int base; + + public: + Power(int base) : base(base) {} + int calculate(unsigned n) { + return repeat(1, ^(int v) { return v * base; }, n); + } + }; + + int test() { + return Power(2).calculate(10); + } +} |