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; } 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/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/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/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/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/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));