vsk updated this revision to Diff 161536.
vsk added a comment.

- Here is a GIF that might help illustrate the bug: 
http://net.vedantk.com/static/llvm/lambda-implicit-capture-bug.gif
- Update test/SemaCXX/uninitialized.cpp to highlight the behavior change which 
comes from using getBeginOrDeclLoc().


https://reviews.llvm.org/D50927

Files:
  clang/include/clang/AST/Expr.h
  clang/lib/AST/Expr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/test/CodeGenCXX/debug-info-lambda.cpp
  clang/test/SemaCXX/uninitialized.cpp
  clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp

Index: clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
===================================================================
--- clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
+++ clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
@@ -75,11 +75,14 @@
 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 the "i" in the lambda to be visited just once (for the
+  // DeclRefExpr for the use of "i" inside the lambda).
+  //
+  // Previously, the DeclRefExpr in the implicit lambda capture initialization
+  // (whose source code location is set to the first use of the variable) was
+  // also matched. This behavior was removed because it resulted in poor debug
+  // info.
+  Visitor.ExpectMatch("i", 1, 24, /*Times=*/1);
   EXPECT_TRUE(Visitor.runOver(
     "void f() { int i; [=]{ i; }; }",
     DeclRefExprVisitor::Lang_CXX11));
Index: clang/test/SemaCXX/uninitialized.cpp
===================================================================
--- clang/test/SemaCXX/uninitialized.cpp
+++ clang/test/SemaCXX/uninitialized.cpp
@@ -884,8 +884,10 @@
     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: clang/test/CodeGenCXX/debug-info-lambda.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/debug-info-lambda.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm \
+// RUN:   -debug-info-kind=line-tables-only -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 [[init_sequence_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]]
+    ++ref;              // CHECK: [[init_sequence_loc]] = !DILocation(line: 0
+  };
+  helper();             // CHECK: [[lambda_call_loc]] = !DILocation(line: [[@LINE]]
+}
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1392,13 +1392,13 @@
   Class->addDecl(Conversion);
 }
 
-static ExprResult performLambdaVarCaptureInitialization(Sema &S,
-                                                        const Capture &Capture,
-                                                        FieldDecl *Field) {
+static ExprResult performLambdaVarCaptureInitialization(
+    Sema &S, const Capture &Capture, FieldDecl *Field, bool IsImplicitCapture) {
   assert(Capture.isVariableCapture() && "not a variable capture");
 
   auto *Var = Capture.getVariable();
   SourceLocation Loc = Capture.getLocation();
+  SourceLocation InitLoc = IsImplicitCapture ? SourceLocation() : Loc;
 
   // C++11 [expr.prim.lambda]p21:
   //   When the lambda-expression is evaluated, the entities that
@@ -1413,7 +1413,7 @@
   //   An entity captured by a lambda-expression is odr-used (3.2) in
   //   the scope containing the lambda-expression.
   ExprResult RefResult = S.BuildDeclarationNameExpr(
-      CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
+      CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), InitLoc), Var);
   if (RefResult.isInvalid())
     return ExprError();
   Expr *Ref = RefResult.get();
@@ -1607,8 +1607,8 @@
                                        Var, From.getEllipsisLoc()));
       Expr *Init = From.getInitExpr();
       if (!Init) {
-        auto InitResult =
-            performLambdaVarCaptureInitialization(*this, From, *CurField);
+        auto InitResult = performLambdaVarCaptureInitialization(
+            *this, From, *CurField, IsImplicit);
         if (InitResult.isInvalid())
           return ExprError();
         Init = InitResult.get();
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -10686,7 +10686,7 @@
         return;
       }
 
-      S.DiagRuntimeBehavior(DRE->getBeginLoc(), DRE,
+      S.DiagRuntimeBehavior(DRE->getBeginOrDeclLoc(), DRE,
                             S.PDiag(diag)
                                 << DRE->getDecl() << OrigDecl->getLocation()
                                 << DRE->getSourceRange());
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -457,6 +457,12 @@
     return getRAngleLoc();
   return getNameInfo().getEndLoc();
 }
+SourceLocation DeclRefExpr::getBeginOrDeclLoc() const {
+  SourceLocation BeginLoc = getBeginLoc();
+  if (BeginLoc.isValid())
+    return BeginLoc;
+  return getDecl()->getLocation();
+}
 
 PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT,
                                StringLiteral *SL)
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -1083,6 +1083,11 @@
   }
   SourceLocation getEndLoc() const LLVM_READONLY;
 
+  /// If this declaration reference explicitly appears in the source, return
+  /// its location. Otherwise, return the location of the declaration it refers
+  /// to.
+  SourceLocation getBeginOrDeclLoc() const LLVM_READONLY;
+
   /// Determine whether this declaration reference was preceded by a
   /// C++ nested-name-specifier, e.g., \c N::foo.
   bool hasQualifier() const { return DeclRefExprBits.HasQualifier; }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to