]> granicus.if.org Git - clang/commitdiff
[Sema] Remove location from implicit capture init expr
authorVedant Kumar <vsk@apple.com>
Thu, 13 Sep 2018 23:28:25 +0000 (23:28 +0000)
committerVedant Kumar <vsk@apple.com>
Thu, 13 Sep 2018 23:28:25 +0000 (23:28 +0000)
A lambda's closure is initialized when the lambda is declared. For
implicit captures, the initialization code emitted from EmitLambdaExpr
references source locations *within the lambda body* in the function
containing the lambda. This results in a poor debugging experience: we
step to the line containing the lambda, then into lambda, out again,
over and over, until every capture's field is initialized.

To improve stepping behavior, assign the starting location of the lambda
to expressions which initialize an implicit capture within it.

rdar://39807527

Differential Revision: https://reviews.llvm.org/D50927

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@342194 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaLambda.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
test/CodeGenCXX/debug-info-lambda.cpp [new file with mode: 0644]
test/SemaCXX/uninitialized.cpp
unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp

index 33915676585322f5762b63643f07afed31253faa..8000cb4fbfd07c45232c53488695da643f50d39a 100644 (file)
@@ -1392,13 +1392,14 @@ static void addBlockPointerConversion(Sema &S,
   Class->addDecl(Conversion);
 }
 
-static ExprResult performLambdaVarCaptureInitialization(Sema &S,
-                                                        const Capture &Capture,
-                                                        FieldDecl *Field) {
+static ExprResult performLambdaVarCaptureInitialization(
+    Sema &S, const Capture &Capture, FieldDecl *Field,
+    SourceLocation ImplicitCaptureLoc, bool IsImplicitCapture) {
   assert(Capture.isVariableCapture() && "not a variable capture");
 
   auto *Var = Capture.getVariable();
-  SourceLocation Loc = Capture.getLocation();
+  SourceLocation Loc =
+      IsImplicitCapture ? ImplicitCaptureLoc : Capture.getLocation();
 
   // C++11 [expr.prim.lambda]p21:
   //   When the lambda-expression is evaluated, the entities that
@@ -1607,8 +1608,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
                                        Var, From.getEllipsisLoc()));
       Expr *Init = From.getInitExpr();
       if (!Init) {
-        auto InitResult =
-            performLambdaVarCaptureInitialization(*this, From, *CurField);
+        auto InitResult = performLambdaVarCaptureInitialization(
+            *this, From, *CurField, CaptureDefaultLoc, IsImplicit);
         if (InitResult.isInvalid())
           return ExprError();
         Init = InitResult.get();
index 551c100ff7af3182a7db61b3e89177059d4365a8..7fc86e81092700417cbba9207af91c01792a9b14 100644 (file)
@@ -15,8 +15,8 @@ public:
 
 void capture_by_copy(NonCopyable nc, NonCopyable &ncr, const NonConstCopy nco) {
   (void)[nc] { }; // expected-error{{capture of variable 'nc' as type 'NonCopyable' calls private copy constructor}}
-  (void)[=] {
-    ncr.foo(); // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}} 
+  (void)[=] { // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}}
+    ncr.foo();
   }();
 
   [nco] {}(); // expected-error{{no matching constructor for initialization of 'const NonConstCopy'}}
index 57e555e8d9e9f4333509fbdfc6b0a0658a8245f4..2bb75df7ac6aaab2917e3959cd91366a0917ff89 100644 (file)
@@ -88,8 +88,8 @@ namespace p2 {
   template<typename R, typename T>
   void odr_used2(R &r, Boom<T> boom) {
     const std::type_info &ti
-      = typeid([=,&r] () -> R& {
-          boom.tickle(); // expected-note{{in instantiation of member function}}
+      = typeid([=,&r] () -> R& { // expected-note{{in instantiation of member function 'p2::Boom<float>::Boom' requested here}}
+          boom.tickle();
           return r; 
         }()); 
   }
diff --git a/test/CodeGenCXX/debug-info-lambda.cpp b/test/CodeGenCXX/debug-info-lambda.cpp
new file mode 100644 (file)
index 0000000..1b8f4e3
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm \
+// RUN:   -debug-info-kind=line-tables-only -dwarf-column-info -std=c++11 %s -o - | FileCheck %s
+
+// CHECK-LABEL: define{{.*}}lambda_in_func
+void lambda_in_func(int &ref) {
+  // CHECK: [[ref_slot:%.*]] = getelementptr inbounds %class.anon, %class.anon* {{.*}}, i32 0, i32 0, !dbg [[lambda_decl_loc:![0-9]+]]
+  // CHECK-NEXT: %1 = load i32*, i32** %ref.addr, align 8, !dbg [[capture_init_loc:![0-9]+]]
+  // CHECK-NEXT: store i32* %1, i32** %0, align 8, !dbg [[lambda_decl_loc]]
+  // CHECK-NEXT: call void {{.*}}, !dbg [[lambda_call_loc:![0-9]+]]
+
+  auto helper = [       // CHECK: [[lambda_decl_loc]] = !DILocation(line: [[@LINE]], column: 17
+                 &]() { // CHECK: [[capture_init_loc]] = !DILocation(line: [[@LINE]], column: 18
+    ++ref;
+  };
+  helper();             // CHECK: [[lambda_call_loc]] = !DILocation(line: [[@LINE]]
+}
index f620e1014c3490a511b27339dafbfc51f7b64be5..331a948eb6f1de857e297880981ac7318bb5c237 100644 (file)
@@ -884,8 +884,10 @@ namespace lambdas {
     int x;
   };
   A a0([] { return a0.x; }); // ok
-  void f() { 
-    A a1([=] { return a1.x; }); // expected-warning{{variable 'a1' is uninitialized when used within its own initialization}}
+  void f() {
+    A a1([=] { // expected-warning{{variable 'a1' is uninitialized when used within its own initialization}}
+      return a1.x;
+    });
     A a2([&] { return a2.x; }); // ok
   }
 }
index 67640486efb6f302d5273fd840de53db288d4f34..cd0e4260a8bce24f7e97a0e5d45b4db654dd5c4c 100644 (file)
@@ -75,11 +75,11 @@ TEST(RecursiveASTVisitor, VisitsUseOfImplicitLambdaCapture) {
 TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
   DeclRefExprVisitor Visitor;
   Visitor.setShouldVisitImplicitCode(true);
-  // We're expecting the "i" in the lambda to be visited twice:
-  // - Once for the DeclRefExpr in the lambda capture initialization (whose
-  //   source code location is set to the first use of the variable).
-  // - Once for the DeclRefExpr for the use of "i" inside the lambda.
-  Visitor.ExpectMatch("i", 1, 24, /*Times=*/2);
+  // We're expecting "i" to be visited twice: once for the initialization expr
+  // for the captured variable "i" outside of the lambda body, and again for
+  // the use of "i" inside the lambda.
+  Visitor.ExpectMatch("i", 1, 20, /*Times=*/1);
+  Visitor.ExpectMatch("i", 1, 24, /*Times=*/1);
   EXPECT_TRUE(Visitor.runOver(
     "void f() { int i; [=]{ i; }; }",
     DeclRefExprVisitor::Lang_CXX11));