[cfe-commits] r104202 - in /cfe/trunk: include/clang/AST/ASTContext.h lib/AST/ASTContext.cpp lib/CodeGen/CGBlocks.cpp lib/CodeGen/CGBlocks.h lib/CodeGen/CodeGenFunction.h lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaTemplate.cpp test/SemaCXX/blocks.cpp

John McCall rjmccall at apple.com
Wed May 19 18:18:32 PDT 2010


Author: rjmccall
Date: Wed May 19 20:18:31 2010
New Revision: 104202

URL: http://llvm.org/viewvc/llvm-project?rev=104202&view=rev
Log:
Support implicitly closing on 'this' in a block.  Fixed PR7165.

(the codegen works here, too, but that's annoying to test without execution)


Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/CodeGen/CGBlocks.cpp
    cfe/trunk/lib/CodeGen/CGBlocks.h
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaCXX/blocks.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed May 19 20:18:31 2010
@@ -482,7 +482,7 @@
   /// 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 @@
   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

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed May 19 20:18:31 2010
@@ -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 @@
   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::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 @@
     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);

Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Wed May 19 20:18:31 2010
@@ -110,6 +110,9 @@
     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 @@
 /// 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 @@
     // __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 @@
     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 @@
       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 @@
     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());
-        }
-        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;
+    for (unsigned i=0; i < subBlockLayout.size(); ++i) {
+      const Expr *E = subBlockLayout[i];
 
-        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()];
+      // Skip padding.
+      if (isa<DeclRefExpr>(E)) continue;
 
-            llvm::Value *BlockLiteral = LoadBlockStruct();
+      llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
+      HelperInfo &Note = NoteForHelper[NumHelpers++];
 
-            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);
-          }
+      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()) {
+          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 @@
   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 @@
         || 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 @@
   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 @@
                                   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 @@
 
   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 @@
   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 @@
 
   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 @@
 
   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 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 @@
                                          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::

Modified: cfe/trunk/lib/CodeGen/CGBlocks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.h?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.h (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.h Wed May 19 20:18:31 2010
@@ -160,8 +160,12 @@
     /// 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 @@
   /// 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; }

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed May 19 20:18:31 2010
@@ -505,13 +505,14 @@
                                         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);
 

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed May 19 20:18:31 2010
@@ -602,7 +602,8 @@
     // 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 @@
                                             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 @@
   // 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 @@
 
   // 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();

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed May 19 20:18:31 2010
@@ -466,10 +466,8 @@
   /// 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),

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed May 19 20:18:31 2010
@@ -330,11 +330,13 @@
                            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.

Modified: cfe/trunk/test/SemaCXX/blocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/blocks.cpp?rev=104202&r1=104201&r2=104202&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/blocks.cpp (original)
+++ cfe/trunk/test/SemaCXX/blocks.cpp Wed May 19 20:18:31 2010
@@ -9,3 +9,35 @@
 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);
+  }
+}





More information about the cfe-commits mailing list