Hi doug.gregor, rsmith, gribozavr, hfinkel,

http://reviews.llvm.org/D4368

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/ScopeInfo.h
  include/clang/Sema/Sema.h
  lib/CodeGen/CodeGenFunction.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaLambda.cpp
  test/CodeGenCXX/instantiate-typeof-vla.cpp
  test/SemaTemplate/instantiate-typeof.cpp
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5319,9 +5319,6 @@
     "'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">;
Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -622,6 +622,9 @@
   /// its list of array index variables.
   SmallVector<unsigned, 4> ArrayIndexStarts;
   
+  /// \brief Expressions used in declarations of VLA types.
+  SmallVector<Expr *, 4> VLAUsedExprs;
+
   /// \brief If this is a generic lambda, use this as the depth of 
   /// each 'auto' parameter, during initial AST construction.
   unsigned AutoTemplateParameterDepth;
@@ -781,6 +784,9 @@
                                   PotentialThisCaptureLocation.isValid(); 
   }
 
+  ArrayRef<Expr *> getVLAUsedExpressions() const { return VLAUsedExprs; }
+  void clearVLAUsedExpressions() { VLAUsedExprs.clear(); }
+
   // When passed the index, returns the VarDecl and Expr associated
   // with the index.
   void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -596,6 +596,23 @@
     }
   };
 
+  bool CaptureVLAUsedVars;
+  /// \brief RAII for capturing non odr-used variables in VLA.
+  class RAIICaptureVLAUsedVarsTy {
+    Sema &S;
+    bool PrevCaptureVLAUsedVars;
+
+  public:
+    RAIICaptureVLAUsedVarsTy(Sema &S)
+        : S(S), PrevCaptureVLAUsedVars(S.CaptureVLAUsedVars) {
+      S.CaptureVLAUsedVars = true;
+    }
+
+    ~RAIICaptureVLAUsedVarsTy() {
+      S.CaptureVLAUsedVars = PrevCaptureVLAUsedVars;
+    }
+  };
+
   /// WeakUndeclaredIdentifiers - Identifiers contained in
   /// \#pragma weak before declared. rare. may alias another
   /// identifier, declared or undeclared
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -522,6 +522,22 @@
   return false;
 }
 
+static void InitVLACaptures(CodeGenFunction &CGF, const CXXRecordDecl *D) {
+  for (auto &C : D->captures()) {
+    if (C.capturesVariable()) {
+      QualType QTy;
+      auto VD = C.getCapturedVar();
+      if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD))
+        QTy = PVD->getOriginalType();
+      else
+        QTy = VD->getType();
+      if (QTy->isVariablyModifiedType()) {
+        CGF.EmitVariablyModifiedType(QTy);
+      }
+    }
+  }
+}
+
 void CodeGenFunction::StartFunction(GlobalDecl GD,
                                     QualType RetTy,
                                     llvm::Function *Fn,
@@ -668,6 +684,7 @@
         CXXThisValue = EmitLoadOfLValue(ThisLValue,
                                         SourceLocation()).getScalarVal();
       }
+      InitVLACaptures(*this, MD->getParent());
     } else {
       // Not in a lambda; just use 'this' from the method.
       // FIXME: Should we generate a new load for each use of 'this'?  The
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -74,38 +74,33 @@
 }
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
-           TranslationUnitKind TUKind,
-           CodeCompleteConsumer *CodeCompleter)
-  : ExternalSource(nullptr),
-    isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
-    LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
-    Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
-    CollectStats(false), CodeCompleter(CodeCompleter),
-    CurContext(nullptr), OriginalLexicalContext(nullptr),
-    PackContext(nullptr), MSStructPragmaOn(false),
-    MSPointerToMemberRepresentationMethod(
-        LangOpts.getMSPointerToMemberRepresentationMethod()),
-    VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
-    DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
-    CodeSegStack(nullptr), VisContext(nullptr),
-    IsBuildingRecoveryCallExpr(false),
-    ExprNeedsCleanups(false), LateTemplateParser(nullptr),
-    OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr),
-    CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
-    NSNumberDecl(nullptr),
-    NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
-    NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
-    NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
-    GlobalNewDeleteDeclared(false),
-    TUKind(TUKind),
-    NumSFINAEErrors(0),
-    AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
-    NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
-    CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
-    TyposCorrected(0), AnalysisWarnings(*this),
-    VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
-    Ident_super(nullptr), Ident___float128(nullptr)
-{
+           TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
+    : ExternalSource(nullptr), isMultiplexExternalSource(false),
+      FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
+      Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
+      SourceMgr(PP.getSourceManager()), CollectStats(false),
+      CodeCompleter(CodeCompleter), CurContext(nullptr),
+      OriginalLexicalContext(nullptr), PackContext(nullptr),
+      MSStructPragmaOn(false),
+      MSPointerToMemberRepresentationMethod(
+          LangOpts.getMSPointerToMemberRepresentationMethod()),
+      VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
+      DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+      CodeSegStack(nullptr), VisContext(nullptr),
+      IsBuildingRecoveryCallExpr(false), ExprNeedsCleanups(false),
+      LateTemplateParser(nullptr), OpaqueParser(nullptr),
+      CaptureVLAUsedVars(false), IdResolver(pp), StdInitializerList(nullptr),
+      CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr),
+      NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
+      NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
+      NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
+      GlobalNewDeleteDeclared(false), TUKind(TUKind), NumSFINAEErrors(0),
+      AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
+      NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
+      CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
+      TyposCorrected(0), AnalysisWarnings(*this),
+      VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
+      Ident_super(nullptr), Ident___float128(nullptr) {
   TUScope = nullptr;
 
   LoadedExternalKnownNamespaces = false;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11668,12 +11668,9 @@
   }
 
   // Prohibit variably-modified types; they're difficult to deal with.
-  if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) {
+  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();
     }
@@ -11989,6 +11986,7 @@
   } else {
     ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
   }
+  ByRef |= S.CaptureVLAUsedVars;
     
   // Compute the type of the field that will capture this variable.
   if (ByRef) {
@@ -12139,7 +12137,7 @@
     // during either a lambdas transformation or initial parsing
     // should be used. 
     if (isGenericLambdaCallOperatorSpecialization(DC)) {
-      if (BuildAndDiagnose) {
+      if (BuildAndDiagnose && !CaptureVLAUsedVars) {
         LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);   
         if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
           Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
@@ -12218,8 +12216,15 @@
 
           // 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))
+              // Use late var capturing for lambdas to give a chance to capture
+              // variables explicitly or by default.
+              LSI->VLAUsedExprs.push_back(Size);
+            else
+              // Immediately mark all referenced vars for CapturedStatements,
+              // they all are captured by reference.
+              MarkDeclarationsReferencedInExpr(Size);
           }
           QTy = Vat->getElementType();
           break;
@@ -12256,7 +12261,8 @@
       } while (!QTy.isNull() && QTy->isVariablyModifiedType());
     }
 
-    if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
+    if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit &&
+        !CaptureVLAUsedVars) {
       // No capture-default, and this is not an explicit capture 
       // so cannot capture this variable.  
       if (BuildAndDiagnose) {
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -1389,6 +1389,12 @@
   SmallVector<unsigned, 4> ArrayIndexStarts;
   {
     LambdaScopeInfo *LSI = getCurLambda();
+    {
+      RAIICaptureVLAUsedVarsTy RAII(*this);
+      for (auto E : LSI->getVLAUsedExpressions())
+        this->MarkDeclarationsReferencedInExpr(E);
+      LSI->clearVLAUsedExpressions();
+    }
     CallOperator = LSI->CallOperator;
     Class = LSI->Lambda;
     IntroducerRange = LSI->IntroducerRange;
Index: test/CodeGenCXX/instantiate-typeof-vla.cpp
===================================================================
--- test/CodeGenCXX/instantiate-typeof-vla.cpp
+++ test/CodeGenCXX/instantiate-typeof-vla.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG:   [[CAP_TYPE1:%.+]] = type { [[INTPTR_T:i.+]], [[INTPTR_T]]* }
+// CHECK-DAG:   [[CAP_TYPE2:%.+]] = type { [[INTPTR_T]]*, [[INTPTR_T]]* }
+
+
+
+// CHECK:       define void [[G:@.+]](
+// CHECK:       [[N_ADDR:%.+]] = alloca [[INTPTR_T]]
+// CHECK:       store [[INTPTR_T]] %{{.+}}, [[INTPTR_T]]* [[N_ADDR]]
+// CHECK:       [[CAP_N_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK:       [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK:       store [[INTPTR_T]] [[N]], [[INTPTR_T]]* [[CAP_N_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:       call void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]])
+// CHECK:       ret void
+void g(intptr_t n) {
+  intptr_t buffer[n];
+  [n, &buffer]() {
+    __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) {
+  intptr_t buffer[n];
+  [&buffer]() {
+    __typeof(buffer) x;
+  }();
+}
+
+// CHECK-LABEL: @main
+int main() {
+// CHECK:       call void [[G]]([[INTPTR_T]] 1)
+  g((intptr_t)1);
+// CHECK:       call void [[F_INT:@.+]]([[INTPTR_T]] 1)
+  f((intptr_t)1);
+// CHECK:       ret i32 0
+  return 0;
+}
+
+// CHECK: void [[F_INT]]([[INTPTR_T]]
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR:%.+]],
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: [[BUFFER_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[N]]
+// CHECK: [[CAP_BUFFER_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]]* [[BUFFER_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER_ADDR_REF]]
+// CHECK: [[CAP_N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_ADDR_REF]]
+// CHECK: call void [[F_INT_LAMBDA:@.+]]([[CAP_TYPE2]]* [[CAP_ARG]])
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+// CHECK: void [[F_INT_LAMBDA]]([[CAP_TYPE2]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE2]]**
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[THIS]], i{{.+}} 0, i{{.+}} 1
+// CHECK: [[N_REF:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_REF]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[N]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
Index: test/SemaTemplate/instantiate-typeof.cpp
===================================================================
--- test/SemaTemplate/instantiate-typeof.cpp
+++ test/SemaTemplate/instantiate-typeof.cpp
@@ -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);
 }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to