r216649 - [C++11] Support for capturing of variable length arrays in lambda expression.

Alexey Bataev a.bataev at hotmail.com
Wed Aug 27 21:28:19 PDT 2014


Author: abataev
Date: Wed Aug 27 23:28:19 2014
New Revision: 216649

URL: http://llvm.org/viewvc/llvm-project?rev=216649&view=rev
Log:
[C++11] Support for capturing of variable length arrays in lambda expression.
Differential Revision: http://reviews.llvm.org/D4368

Added:
    cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/LambdaCapture.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/Lambda.h
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/Sema/ScopeInfo.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/SemaTemplate/instantiate-typeof.cpp
    cfe/trunk/tools/libclang/IndexBody.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Aug 27 23:28:19 2014
@@ -2156,8 +2156,9 @@ class FieldDecl : public DeclaratorDecl,
   mutable unsigned CachedFieldIndex : 31;
 
   /// \brief An InClassInitStyle value, and either a bit width expression (if
-  /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class
-  /// initializer for this field (otherwise).
+  /// the InClassInitStyle value is ICIS_NoInit) in struct/class, or a captured
+  /// variable length array bound in a lambda expression, or a pointer to the
+  /// in-class initializer for this field (otherwise).
   ///
   /// We can safely combine these two because in-class initializers are not
   /// permitted for bit-fields.
@@ -2165,7 +2166,7 @@ class FieldDecl : public DeclaratorDecl,
   /// If the InClassInitStyle is not ICIS_NoInit and the initializer is null,
   /// then this field has an in-class initializer which has not yet been parsed
   /// and attached.
-  llvm::PointerIntPair<Expr *, 2, unsigned> InitializerOrBitWidth;
+  llvm::PointerIntPair<void *, 2, unsigned> InitializerOrBitWidth;
 protected:
   FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
             SourceLocation IdLoc, IdentifierInfo *Id,
@@ -2193,11 +2194,8 @@ public:
   /// isMutable - Determines whether this field is mutable (C++ only).
   bool isMutable() const { return Mutable; }
 
-  /// isBitfield - Determines whether this field is a bitfield.
-  bool isBitField() const {
-    return getInClassInitStyle() == ICIS_NoInit &&
-           InitializerOrBitWidth.getPointer();
-  }
+  /// \brief Determines whether this field is a bitfield.
+  bool isBitField() const;
 
   /// @brief Determines whether this is an unnamed bitfield.
   bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
@@ -2209,7 +2207,9 @@ public:
   bool isAnonymousStructOrUnion() const;
 
   Expr *getBitWidth() const {
-    return isBitField() ? InitializerOrBitWidth.getPointer() : nullptr;
+    return isBitField()
+               ? static_cast<Expr *>(InitializerOrBitWidth.getPointer())
+               : nullptr;
   }
   unsigned getBitWidthValue(const ASTContext &Ctx) const;
 
@@ -2239,8 +2239,9 @@ public:
   /// in-class initializer, but this returns null, then we have not parsed and
   /// attached it yet.
   Expr *getInClassInitializer() const {
-    return hasInClassInitializer() ? InitializerOrBitWidth.getPointer()
-                                   : nullptr;
+    return hasInClassInitializer()
+               ? static_cast<Expr *>(InitializerOrBitWidth.getPointer())
+               : nullptr;
   }
   /// setInClassInitializer - Set the C++11 in-class initializer for this
   /// member.
@@ -2253,6 +2254,18 @@ public:
     InitializerOrBitWidth.setInt(ICIS_NoInit);
   }
 
+  /// \brief Determine whether this member captures the variable length array
+  /// type.
+  bool hasCapturedVLAType() const;
+  /// \brief Get the captured variable length array type.
+  const VariableArrayType *getCapturedVLAType() const {
+    return hasCapturedVLAType() ? static_cast<const VariableArrayType *>(
+                                      InitializerOrBitWidth.getPointer())
+                                : nullptr;
+  }
+  /// \brief Set the captured variable length array type for this field.
+  void setCapturedVLAType(const VariableArrayType *VLAType);
+
   /// getParent - Returns the parent of this field declaration, which
   /// is the struct in which this method is defined.
   const RecordDecl *getParent() const {
@@ -3144,6 +3157,10 @@ public:
   /// \endcode
   bool isInjectedClassName() const;
 
+  /// \brief Determine whether this record is a class describing a lambda
+  /// function object.
+  bool isLambda() const;
+
   /// getDefinition - Returns the RecordDecl that actually defines
   ///  this struct/union/class.  When determining whether or not a
   ///  struct/union/class is completely defined, one should use this

Modified: cfe/trunk/include/clang/AST/LambdaCapture.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/LambdaCapture.h?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/LambdaCapture.h (original)
+++ cfe/trunk/include/clang/AST/LambdaCapture.h Wed Aug 27 23:28:19 2014
@@ -68,13 +68,23 @@ public:
 
   /// \brief Determine whether this capture handles the C++ \c this
   /// pointer.
-  bool capturesThis() const { return DeclAndBits.getPointer() == nullptr; }
+  bool capturesThis() const {
+    return (DeclAndBits.getPointer() == nullptr) &&
+           !(DeclAndBits.getInt() & Capture_ByCopy);
+  }
 
   /// \brief Determine whether this capture handles a variable.
   bool capturesVariable() const {
     return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
   }
 
+  /// \brief Determine whether this captures a variable length array bound
+  /// expression.
+  bool capturesVLAType() const {
+    return (DeclAndBits.getPointer() == nullptr) &&
+           (DeclAndBits.getInt() & Capture_ByCopy);
+  }
+
   /// \brief Determine whether this is an init-capture.
   bool isInitCapture() const {
     return capturesVariable() && getCapturedVar()->isInitCapture();

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Aug 27 23:28:19 2014
@@ -5357,9 +5357,6 @@ let CategoryName = "Lambda Issue" in {
     "'this' cannot be %select{implicitly |}0captured in this context">;
   def err_lambda_capture_anonymous_var : Error<
     "unnamed variable cannot be implicitly captured in a lambda expression">;
-  def err_lambda_capture_vm_type : Error<
-    "variable %0 with variably modified type cannot be captured in "
-    "a lambda expression">;
   def err_lambda_capture_flexarray_type : Error<
     "variable %0 with flexible array member cannot be captured in "
     "a lambda expression">;

Modified: cfe/trunk/include/clang/Basic/Lambda.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Lambda.h?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Lambda.h (original)
+++ cfe/trunk/include/clang/Basic/Lambda.h Wed Aug 27 23:28:19 2014
@@ -34,7 +34,8 @@ enum LambdaCaptureDefault {
 enum LambdaCaptureKind {
   LCK_This,   ///< Capturing the \c this pointer
   LCK_ByCopy, ///< Capturing by copy (a.k.a., by value)
-  LCK_ByRef   ///< Capturing by reference
+  LCK_ByRef,  ///< Capturing by reference
+  LCK_VLAType ///< Capturing variable-length array type
 };
 
 } // end namespace clang

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Wed Aug 27 23:28:19 2014
@@ -378,7 +378,7 @@ public:
     /// capture (if this is a capture and not an init-capture). The expression
     /// is only required if we are capturing ByVal and the variable's type has
     /// a non-trivial copy constructor.
-    llvm::PointerIntPair<Expr*, 2, CaptureKind> InitExprAndCaptureKind;
+    llvm::PointerIntPair<void *, 2, CaptureKind> InitExprAndCaptureKind;
 
     /// \brief The source location at which the first capture occurred.
     SourceLocation Loc;
@@ -410,10 +410,11 @@ public:
       return InitExprAndCaptureKind.getInt() == Cap_This;
     }
     bool isVariableCapture() const {
-      return InitExprAndCaptureKind.getInt() != Cap_This;
+      return InitExprAndCaptureKind.getInt() != Cap_This && !isVLATypeCapture();
     }
     bool isCopyCapture() const {
-      return InitExprAndCaptureKind.getInt() == Cap_ByCopy;
+      return InitExprAndCaptureKind.getInt() == Cap_ByCopy &&
+             !isVLATypeCapture();
     }
     bool isReferenceCapture() const {
       return InitExprAndCaptureKind.getInt() == Cap_ByRef;
@@ -421,7 +422,11 @@ public:
     bool isBlockCapture() const {
       return InitExprAndCaptureKind.getInt() == Cap_Block;
     }
-    bool isNested() { return VarAndNested.getInt(); }
+    bool isVLATypeCapture() const {
+      return InitExprAndCaptureKind.getInt() == Cap_ByCopy &&
+             getVariable() == nullptr;
+    }
+    bool isNested() const { return VarAndNested.getInt(); }
 
     VarDecl *getVariable() const {
       return VarAndNested.getPointer();
@@ -440,7 +445,8 @@ public:
     QualType getCaptureType() const { return CaptureType; }
     
     Expr *getInitExpr() const {
-      return InitExprAndCaptureKind.getPointer();
+      assert(!isVLATypeCapture() && "no init expression for type capture");
+      return static_cast<Expr *>(InitExprAndCaptureKind.getPointer());
     }
   };
 
@@ -475,6 +481,13 @@ public:
     CaptureMap[Var] = Captures.size();
   }
 
+  void addVLATypeCapture(SourceLocation Loc, QualType CaptureType) {
+    Captures.push_back(Capture(/*Var*/ nullptr, /*isBlock*/ false,
+                               /*isByref*/ false, /*isNested*/ false, Loc,
+                               /*EllipsisLoc*/ SourceLocation(), CaptureType,
+                               /*Cpy*/ nullptr));
+  }
+
   void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
                       Expr *Cpy);
 
@@ -491,7 +504,10 @@ public:
   bool isCaptured(VarDecl *Var) const {
     return CaptureMap.count(Var);
   }
-  
+
+  /// \brief Determine whether the given variable-array type has been captured.
+  bool isVLATypeCaptured(const VariableArrayType *VAT) const;
+
   /// \brief Retrieve the capture of the given variable, if it has been
   /// captured already.
   Capture &getCapture(VarDecl *Var) {

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Aug 27 23:28:19 2014
@@ -3261,9 +3261,18 @@ bool FieldDecl::isAnonymousStructOrUnion
   return false;
 }
 
+bool FieldDecl::isBitField() const {
+  if (getInClassInitStyle() == ICIS_NoInit &&
+      InitializerOrBitWidth.getPointer()) {
+    assert(getDeclContext() && "No parent context for FieldDecl");
+    return !getDeclContext()->isRecord() || !getParent()->isLambda();
+  }
+  return false;
+}
+
 unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
   assert(isBitField() && "not a bitfield");
-  Expr *BitWidth = InitializerOrBitWidth.getPointer();
+  Expr *BitWidth = static_cast<Expr *>(InitializerOrBitWidth.getPointer());
   return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue();
 }
 
@@ -3287,23 +3296,36 @@ unsigned FieldDecl::getFieldIndex() cons
 }
 
 SourceRange FieldDecl::getSourceRange() const {
-  if (const Expr *E = InitializerOrBitWidth.getPointer())
+  if (const Expr *E =
+          static_cast<const Expr *>(InitializerOrBitWidth.getPointer()))
     return SourceRange(getInnerLocStart(), E->getLocEnd());
   return DeclaratorDecl::getSourceRange();
 }
 
 void FieldDecl::setBitWidth(Expr *Width) {
   assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() &&
-         "bit width or initializer already set");
+         "bit width, initializer or captured type already set");
   InitializerOrBitWidth.setPointer(Width);
 }
 
 void FieldDecl::setInClassInitializer(Expr *Init) {
   assert(!InitializerOrBitWidth.getPointer() && hasInClassInitializer() &&
-         "bit width or initializer already set");
+         "bit width, initializer or captured expr already set");
   InitializerOrBitWidth.setPointer(Init);
 }
 
+bool FieldDecl::hasCapturedVLAType() const {
+  return getDeclContext()->isRecord() && getParent()->isLambda() &&
+         InitializerOrBitWidth.getPointer();
+}
+
+void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) {
+  assert(getParent()->isLambda() && "capturing type in non-lambda.");
+  assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() &&
+         "bit width, initializer or captured type already set");
+  InitializerOrBitWidth.setPointer(const_cast<VariableArrayType *>(VLAType));
+}
+
 //===----------------------------------------------------------------------===//
 // TagDecl Implementation
 //===----------------------------------------------------------------------===//
@@ -3524,6 +3546,12 @@ bool RecordDecl::isInjectedClassName() c
     cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
 }
 
+bool RecordDecl::isLambda() const {
+  if (auto RD = dyn_cast<CXXRecordDecl>(this))
+    return RD->isLambda();
+  return false;
+}
+
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage)
     LoadFieldsFromExternalStorage();

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Wed Aug 27 23:28:19 2014
@@ -909,16 +909,21 @@ LambdaCapture::LambdaCapture(SourceLocat
   case LCK_ByRef:
     assert(Var && "capture must have a variable!");
     break;
+  case LCK_VLAType:
+    assert(!Var && "VLA type capture cannot have a variable!");
+    Bits |= Capture_ByCopy;
+    break;
   }
   DeclAndBits.setInt(Bits);
 }
 
 LambdaCaptureKind LambdaCapture::getCaptureKind() const {
   Decl *D = DeclAndBits.getPointer();
+  bool CapByCopy = DeclAndBits.getInt() & Capture_ByCopy;
   if (!D)
-    return LCK_This;
+    return CapByCopy ? LCK_VLAType : LCK_This;
 
-  return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
+  return CapByCopy ? LCK_ByCopy : LCK_ByRef;
 }
 
 LambdaExpr::LambdaExpr(QualType T,

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Aug 27 23:28:19 2014
@@ -1742,6 +1742,8 @@ void StmtPrinter::VisitLambdaExpr(Lambda
     case LCK_ByCopy:
       OS << C->getCapturedVar()->getName();
       break;
+    case LCK_VLAType:
+      llvm_unreachable("VLA type in explicit captures.");
     }
 
     if (C->isInitCapture())

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Wed Aug 27 23:28:19 2014
@@ -1040,6 +1040,8 @@ StmtProfiler::VisitLambdaExpr(const Lamb
       VisitDecl(C->getCapturedVar());
       ID.AddBoolean(C->isPackExpansion());
       break;
+    case LCK_VLAType:
+      llvm_unreachable("VLA type in explicit captures.");
     }
   }
   // Note: If we actually needed to be able to match lambda

Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Wed Aug 27 23:28:19 2014
@@ -852,12 +852,11 @@ CollectRecordLambdaFields(const CXXRecor
                           C.getLocation(), Field->getAccess(),
                           layout.getFieldOffset(fieldno), VUnit, RecordTy);
       elements.push_back(fieldType);
-    } else {
+    } else if (C.capturesThis()) {
       // TODO: Need to handle 'this' in some way by probably renaming the
       // this of the lambda class and having a field member of 'this' or
       // by using AT_object_pointer for the function and having that be
       // used as 'this' for semantic references.
-      assert(C.capturesThis() && "Field that isn't captured and isn't this?");
       FieldDecl *f = *Field;
       llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
       QualType type = f->getType();

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Aug 27 23:28:19 2014
@@ -1805,19 +1805,23 @@ llvm::Value *CodeGenFunction::EmitDynami
 
 void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
   RunCleanupsScope Scope(*this);
-  LValue SlotLV = MakeAddrLValue(Slot.getAddr(), E->getType(),
-                                 Slot.getAlignment());
+  LValue SlotLV =
+      MakeAddrLValue(Slot.getAddr(), E->getType(), Slot.getAlignment());
 
   CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
   for (LambdaExpr::capture_init_iterator i = E->capture_init_begin(),
                                          e = E->capture_init_end();
        i != e; ++i, ++CurField) {
     // Emit initialization
-    
     LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
-    ArrayRef<VarDecl *> ArrayIndexes;
-    if (CurField->getType()->isArrayType())
-      ArrayIndexes = E->getCaptureInitIndexVars(i);
-    EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+    if (CurField->hasCapturedVLAType()) {
+      auto VAT = CurField->getCapturedVLAType();
+      EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
+    } else {
+      ArrayRef<VarDecl *> ArrayIndexes;
+      if (CurField->getType()->isArrayType())
+        ArrayIndexes = E->getCaptureInitIndexVars(i);
+      EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+    }
   }
 }

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Aug 27 23:28:19 2014
@@ -691,6 +691,14 @@ void CodeGenFunction::StartFunction(Glob
         CXXThisValue = EmitLoadOfLValue(ThisLValue,
                                         SourceLocation()).getScalarVal();
       }
+      for (auto *FD : MD->getParent()->fields()) {
+        if (FD->hasCapturedVLAType()) {
+          auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD),
+                                           SourceLocation()).getScalarVal();
+          auto VAT = FD->getCapturedVLAType();
+          VLASizeMap[VAT->getSizeExpr()] = ExprArg;
+        }
+      }
     } else {
       // Not in a lambda; just use 'this' from the method.
       // FIXME: Should we generate a new load for each use of 'this'?  The

Modified: cfe/trunk/lib/Sema/ScopeInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/ScopeInfo.cpp (original)
+++ cfe/trunk/lib/Sema/ScopeInfo.cpp Wed Aug 27 23:28:19 2014
@@ -14,6 +14,7 @@
 
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
@@ -93,6 +94,15 @@ FunctionScopeInfo::WeakObjectProfileTy::
   return BaseInfoTy(D, IsExact);
 }
 
+bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
+  if (auto *LSI = dyn_cast<LambdaScopeInfo>(this))
+    for (auto *FD : LSI->Lambda->fields()) {
+      if (FD->hasCapturedVLAType() && FD->getCapturedVLAType() == VAT)
+        return true;
+    }
+  return false;
+}
+
 FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
                                           const ObjCPropertyRefExpr *PropE)
     : Base(nullptr, true), Property(getBestPropertyDecl(PropE)) {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Aug 27 23:28:19 2014
@@ -9959,6 +9959,7 @@ static void RebuildLambdaScopeInfo(CXXMe
 
   // Add the captures to the LSI so they can be noted as already
   // captured within tryCaptureVar. 
+  auto I = LambdaClass->field_begin();
   for (const auto &C : LambdaClass->captures()) {
     if (C.capturesVariable()) {
       VarDecl *VD = C.getCapturedVar();
@@ -9975,7 +9976,10 @@ static void RebuildLambdaScopeInfo(CXXMe
     } else if (C.capturesThis()) {
       LSI->addThisCapture(/*Nested*/ false, C.getLocation(), 
                               S.getCurrentThisType(), /*Expr*/ nullptr);
+    } else {
+      LSI->addVLATypeCapture(C.getLocation(), I->getType());
     }
+    ++I;
   }
 }
 

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Aug 27 23:28:19 2014
@@ -11681,13 +11681,10 @@ static bool isVariableCapturable(Capturi
     return false;
   }
 
-  // Prohibit variably-modified types; they're difficult to deal with.
-  if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) {
+  // Prohibit variably-modified types in blocks; they're difficult to deal with.
+  if (Var->getType()->isVariablyModifiedType() && IsBlock) {
     if (Diagnose) {
-      if (IsBlock)
-        S.Diag(Loc, diag::err_ref_vm_type);
-      else
-        S.Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
+      S.Diag(Loc, diag::err_ref_vm_type);
       S.Diag(Var->getLocation(), diag::note_previous_decl) 
         << Var->getDeclName();
     }
@@ -12091,7 +12088,6 @@ static bool captureInLambda(LambdaScopeI
   return true;
 }
 
-
 bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, 
                               TryCaptureKind Kind, SourceLocation EllipsisLoc,
                               bool BuildAndDiagnose, 
@@ -12228,14 +12224,37 @@ bool Sema::tryCaptureVariable(VarDecl *V
           break;
         case Type::VariableArray: {
           // Losing element qualification here is fine.
-          const VariableArrayType *Vat = cast<VariableArrayType>(Ty);
+          const VariableArrayType *VAT = cast<VariableArrayType>(Ty);
 
           // Unknown size indication requires no size computation.
           // Otherwise, evaluate and record it.
-          if (Expr *Size = Vat->getSizeExpr()) {
-            MarkDeclarationsReferencedInExpr(Size);
+          if (auto Size = VAT->getSizeExpr()) {
+            if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+              if (!LSI->isVLATypeCaptured(VAT)) {
+                auto ExprLoc = Size->getExprLoc();
+                auto SizeType = Context.getSizeType();
+                auto Lambda = LSI->Lambda;
+
+                // Build the non-static data member.
+                auto Field = FieldDecl::Create(
+                    Context, Lambda, ExprLoc, ExprLoc,
+                    /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
+                    /*BW*/ nullptr, /*Mutable*/ false,
+                    /*InitStyle*/ ICIS_NoInit);
+                Field->setImplicit(true);
+                Field->setAccess(AS_private);
+                Field->setCapturedVLAType(VAT);
+                Lambda->addDecl(Field);
+
+                LSI->addVLATypeCapture(ExprLoc, SizeType);
+              }
+            } else {
+              // Immediately mark all referenced vars for CapturedStatements,
+              // they all are captured by reference.
+              MarkDeclarationsReferencedInExpr(Size);
+            }
           }
-          QTy = Vat->getElementType();
+          QTy = VAT->getElementType();
           break;
         }
         case Type::FunctionProto:

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Aug 27 23:28:19 2014
@@ -1414,6 +1414,12 @@ ExprResult Sema::ActOnLambdaExpr(SourceL
                                                          /*isImplicit=*/true));
         continue;
       }
+      if (From.isVLATypeCapture()) {
+        Captures.push_back(
+            LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
+        CaptureInits.push_back(nullptr);
+        continue;
+      }
 
       VarDecl *Var = From.getVariable();
       LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Aug 27 23:28:19 2014
@@ -9002,6 +9002,10 @@ TreeTransform<Derived>::TransformLambdaS
       getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
       continue;
     }
+    // Captured expression will be recaptured during captured variables
+    // rebuilding.
+    if (C->capturesVLAType())
+      continue;
 
     // Rebuild init-captures, including the implied field declaration.
     if (C->isInitCapture()) {

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Aug 27 23:28:19 2014
@@ -976,7 +976,13 @@ void ASTDeclReader::VisitFieldDecl(Field
   FD->Mutable = Record[Idx++];
   if (int BitWidthOrInitializer = Record[Idx++]) {
     FD->InitializerOrBitWidth.setInt(BitWidthOrInitializer - 1);
-    FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F));
+    if (FD->getDeclContext()->isRecord() && FD->getParent()->isLambda()) {
+      // Read captured variable length array.
+      FD->InitializerOrBitWidth.setPointer(
+          Reader.readType(F, Record, Idx).getAsOpaquePtr());
+    } else {
+      FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F));
+    }
   }
   if (!FD->getDeclName()) {
     if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>(Record, Idx))
@@ -1301,6 +1307,7 @@ void ASTDeclReader::ReadCXXDefinitionDat
       LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
       switch (Kind) {
       case LCK_This:
+      case LCK_VLAType:
         *ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation());
         break;
       case LCK_ByCopy:

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Aug 27 23:28:19 2014
@@ -5582,6 +5582,7 @@ void ASTWriter::AddCXXDefinitionData(con
       Record.push_back(Capture.getCaptureKind());
       switch (Capture.getCaptureKind()) {
       case LCK_This:
+      case LCK_VLAType:
         break;
       case LCK_ByCopy:
       case LCK_ByRef:

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Aug 27 23:28:19 2014
@@ -666,10 +666,16 @@ void ASTDeclWriter::VisitObjCPropertyImp
 void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
   VisitDeclaratorDecl(D);
   Record.push_back(D->isMutable());
-  if (D->InitializerOrBitWidth.getInt() != ICIS_NoInit ||
-      D->InitializerOrBitWidth.getPointer()) {
+  if ((D->InitializerOrBitWidth.getInt() != ICIS_NoInit ||
+       D->InitializerOrBitWidth.getPointer()) &&
+      !D->hasCapturedVLAType()) {
     Record.push_back(D->InitializerOrBitWidth.getInt() + 1);
-    Writer.AddStmt(D->InitializerOrBitWidth.getPointer());
+    Writer.AddStmt(static_cast<Expr *>(D->InitializerOrBitWidth.getPointer()));
+  } else if (D->hasCapturedVLAType()) {
+    Record.push_back(D->InitializerOrBitWidth.getInt() + 1);
+    Writer.AddTypeRef(
+        QualType(static_cast<Type *>(D->InitializerOrBitWidth.getPointer()), 0),
+        Record);
   } else {
     Record.push_back(0);
   }

Added: cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp?rev=216649&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp Wed Aug 27 23:28:19 2014
@@ -0,0 +1,172 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-pch -o %t
+// RUN: %clang_cc1 %s -std=c++11 -include-pch %t -emit-llvm -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG:   [[CAP_TYPE1:%.+]] = type { [[INTPTR_T:i.+]], [[INTPTR_T]]*, [[INTPTR_T]]* }
+// CHECK-DAG:   [[CAP_TYPE2:%.+]] = type { [[INTPTR_T]], [[INTPTR_T]]* }
+// CHECK-DAG:   [[CAP_TYPE3:%.+]] = type { [[INTPTR_T]]*, [[INTPTR_T]], [[INTPTR_T]], [[INTPTR_T]]*, [[INTPTR_T]]* }
+// CHECK-DAG:   [[CAP_TYPE4:%.+]] = type { [[INTPTR_T]]*, [[INTPTR_T]], [[INTPTR_T]]*, [[INTPTR_T]], [[INTPTR_T]]* }
+
+// CHECK:       define void [[G:@.+]](
+// CHECK:       [[N_ADDR:%.+]] = alloca [[INTPTR_T]]
+// CHECK:       store [[INTPTR_T]] %{{.+}}, [[INTPTR_T]]* [[N_ADDR]]
+// CHECK:       [[N_VAL:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK:       [[CAP_EXPR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK:       store [[INTPTR_T]] [[N_VAL]], [[INTPTR_T]]* [[CAP_EXPR_REF]]
+// CHECK:       [[CAP_BUFFER_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK:       store [[INTPTR_T]]* %{{.+}}, [[INTPTR_T]]** [[CAP_BUFFER_ADDR]]
+// CHECK:       [[CAP_N_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 2
+// CHECK:       store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_REF]]
+// CHECK:       call void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]])
+// CHECK:       ret void
+void g(intptr_t n) {
+  intptr_t buffer[n];
+  [&buffer, &n]() {
+    __typeof(buffer) x;
+  }();
+}
+
+// CHECK: void [[G_LAMBDA]]([[CAP_TYPE1]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE1]]**
+// CHECK: [[N_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[BUFFER_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[THIS]], i{{.+}} 0, i{{.+}} 1
+// CHECK: [[BUFFER:%.+]] = load [[INTPTR_T]]** [[BUFFER_ADDR]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[N]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+template <typename T>
+void f(T n, T m) {
+  intptr_t buffer[n + m];
+  [&buffer]() {
+    __typeof(buffer) x;
+  }();
+}
+
+template <typename T>
+intptr_t getSize(T);
+
+template <typename T>
+void b(intptr_t n, T arg) {
+  typedef intptr_t ArrTy[getSize(arg)];
+  ArrTy buffer2;
+  ArrTy buffer1[n + arg];
+  intptr_t a;
+  [&]() {
+    n = sizeof(buffer1[n]);
+    [&](){
+      n = sizeof(buffer2);
+      n = sizeof(buffer1);
+    }();
+  }();
+}
+
+// CHECK-LABEL: @main
+int main() {
+  // CHECK:       call void [[G]]([[INTPTR_T]] 1)
+  g((intptr_t)1);
+  // CHECK:       call void [[F_INT:@.+]]([[INTPTR_T]] 1, [[INTPTR_T]] 2)
+  f((intptr_t)1, (intptr_t)2);
+  // CHECK:       call void [[B_INT:@.+]]([[INTPTR_T]] 12, [[INTPTR_T]] 13)
+  b((intptr_t)12, (intptr_t)13);
+  // CHECK:       ret i32 0
+  return 0;
+}
+
+// CHECK: void [[F_INT]]([[INTPTR_T]]
+// CHECK: [[SIZE:%.+]] = add
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: [[BUFFER_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE]]
+// CHECK: [[CAP_SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]] [[SIZE]], [[INTPTR_T]]* [[CAP_SIZE_REF]]
+// CHECK: [[CAP_BUFFER_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store [[INTPTR_T]]* [[BUFFER_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER_ADDR_REF]]
+// CHECK: call void [[F_INT_LAMBDA:@.+]]([[CAP_TYPE2]]* [[CAP_ARG]])
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+// CHECK: void [[B_INT]]([[INTPTR_T]]
+// CHECK: [[N_ADDR:%.+]] = alloca [[INTPTR_T]]
+// CHECK: [[SIZE1:%.+]] = call [[INTPTR_T]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: [[BUFFER2_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE1]]
+// CHECK: [[SIZE2:%.+]] = add
+// CHECK: [[BUFFER1_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]]
+// CHECK: [[CAP_N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_ADDR_REF]]
+// CHECK: [[CAP_SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store i{{[0-9]+}} [[SIZE2]], i{{[0-9]+}}* [[CAP_SIZE2_REF]]
+// CHECK: [[CAP_SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 2
+// CHECK: store i{{[0-9]+}} [[SIZE1]], i{{[0-9]+}}* [[CAP_SIZE1_REF]]
+// CHECK: [[CAP_BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 3
+// CHECK: store [[INTPTR_T]]* [[BUFFER1_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER1_ADDR_REF]]
+// CHECK: [[CAP_BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 4
+// CHECK: store [[INTPTR_T]]* [[BUFFER2_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER2_ADDR_REF]]
+// CHECK: call void [[B_INT_LAMBDA:@.+]]([[CAP_TYPE3]]* [[CAP_ARG]])
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+// CHECK: define {{.*}} void [[B_INT_LAMBDA]]([[CAP_TYPE3]]*
+// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[SIZE2:%.+]] = load i{{[0-9]+}}* [[SIZE2_REF]]
+// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[SIZE1:%.+]] = load i{{[0-9]+}}* [[SIZE1_REF]]
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[BUFFER1_ADDR:%.+]] = load [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
+// CHECK: [[ELEM_OFFSET:%.+]] = mul {{.*}} i{{[0-9]+}} [[N]], [[SIZE1]]
+// CHECK: [[ELEM_ADDR:%.+]] = getelementptr inbounds [[INTPTR_T]]* [[BUFFER1_ADDR]], i{{[0-9]+}} [[ELEM_OFFSET]]
+// CHECK: [[SIZEOF:%.+]] = mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[SIZE1]]
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: store [[INTPTR_T]] {{%.+}}, [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR_ORIG:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF_ORIG]]
+// CHECK: store [[INTPTR_T]]* [[N_ADDR_ORIG]], [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: store i{{[0-9]+}} [[SIZE1]], i{{[0-9]+}}* [[SIZE1_REF]]
+// CHECK: [[BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[BUFFER2_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[BUFFER2_ADDR_ORIG:%.+]] = load [[INTPTR_T]]** [[BUFFER2_ADDR_REF_ORIG]]
+// CHECK: store [[INTPTR_T]]* [[BUFFER2_ADDR_ORIG]], [[INTPTR_T]]** [[BUFFER2_ADDR_REF]]
+// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: store i{{[0-9]+}} [[SIZE2]], i{{[0-9]+}}* [[SIZE2_REF]]
+// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[BUFFER1_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[BUFFER1_ADDR_ORIG:%.+]] = load [[INTPTR_T]]** [[BUFFER1_ADDR_REF_ORIG]]
+// CHECK: store [[INTPTR_T]]* [[BUFFER1_ADDR_ORIG]], [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
+// CHECK: call void [[B_INT_LAMBDA_LAMBDA:@.+]]([[CAP_TYPE4]]* [[CAP]])
+// CHECK: ret void
+
+// CHECK: define {{.*}} void [[B_INT_LAMBDA_LAMBDA]]([[CAP_TYPE4]]*
+// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[SIZE1:%.+]] = load i{{[0-9]+}}* [[SIZE1_REF]]
+// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[SIZE2:%.+]] = load i{{[0-9]+}}* [[SIZE2_REF]]
+// CHECK: [[BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[BUFFER2_ADDR:%.+]] = load [[INTPTR_T]]** [[BUFFER2_ADDR_REF]]
+// CHECK: [[SIZEOF_BUFFER2:%.+]] = mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[SIZE1]]
+// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[BUFFER1_ADDR:%.+]] = load [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
+// CHECK: [[MUL:%.+]] = mul {{.*}} i{{[0-9]+}} [[SIZE2]], [[SIZE1]]
+// CHECK: mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[MUL]]
+// CHECK: ret void
+
+// CHECK: void [[F_INT_LAMBDA]]([[CAP_TYPE2]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE2]]**
+// CHECK: [[SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
+// CHECK: [[SIZE:%.+]] = load [[INTPTR_T]]* [[SIZE_REF]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+#endif

Propchange: cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Propchange: cfe/trunk/test/CodeGenCXX/vla-lambda-capturing.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaTemplate/instantiate-typeof.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-typeof.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-typeof.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-typeof.cpp Wed Aug 27 23:28:19 2014
@@ -1,10 +1,11 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
 
 // Make sure we correctly treat __typeof as potentially-evaluated when appropriate
 template<typename T> void f(T n) {
-  int buffer[n]; // expected-note {{declared here}}
-  [] { __typeof(buffer) x; }(); // expected-error {{variable 'buffer' with variably modified type cannot be captured in a lambda expression}}
+  int buffer[n];
+  [&buffer] { __typeof(buffer) x; }();
 }
 int main() {
-  f<int>(1); // expected-note {{in instantiation}}
+  f<int>(1);
 }

Modified: cfe/trunk/tools/libclang/IndexBody.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/IndexBody.cpp?rev=216649&r1=216648&r2=216649&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/IndexBody.cpp (original)
+++ cfe/trunk/tools/libclang/IndexBody.cpp Wed Aug 27 23:28:19 2014
@@ -156,7 +156,7 @@ public:
   }
 
   bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) {
-    if (C->capturesThis())
+    if (C->capturesThis() || C->capturesVLAType())
       return true;
 
     if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())





More information about the cfe-commits mailing list