Index: clang/include/clang/Sema/Lookup.h =================================================================== --- clang/include/clang/Sema/Lookup.h +++ clang/include/clang/Sema/Lookup.h @@ -633,6 +633,10 @@ return NameInfo.getLoc(); } + SourceRange getNameRange() const { + return SourceRange(NameInfo.getBeginLoc(), NameInfo.getEndLoc()); + } + /// Get the Sema object that this lookup result is searching /// with. Sema &getSema() const { return *SemaPtr; } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -2173,7 +2173,7 @@ static void emitEmptyLookupTypoDiagnostic( const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS, - DeclarationName Typo, SourceLocation TypoLoc, ArrayRef Args, + DeclarationName Typo, SourceRange TypoRange, ArrayRef Args, unsigned DiagnosticID, unsigned DiagnosticSuggestID) { DeclContext *Ctx = SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false); @@ -2181,10 +2181,10 @@ // Emit a special diagnostic for failed member lookups. // FIXME: computing the declaration context might fail here (?) if (Ctx) - SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx - << SS.getRange(); + SemaRef.Diag(TypoRange.getBegin(), diag::err_no_member) + << Typo << Ctx << TypoRange; else - SemaRef.Diag(TypoLoc, DiagnosticID) << Typo; + SemaRef.Diag(TypoRange.getEnd(), DiagnosticID) << Typo << TypoRange; return; } @@ -2198,9 +2198,9 @@ SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo, SemaRef.PDiag(NoteID)); else - SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) - << Typo << Ctx << DroppedSpecifier - << SS.getRange(), + SemaRef.diagnoseTypo(TC, + SemaRef.PDiag(diag::err_no_member_suggest) + << Typo << Ctx << DroppedSpecifier << TypoRange, SemaRef.PDiag(NoteID)); } @@ -2324,16 +2324,16 @@ DC = DC->getLookupParent(); } + SourceRange TypoRange = R.getNameRange(); // We didn't find anything, so try to correct for a typo. TypoCorrection Corrected; if (S && Out) { - SourceLocation TypoLoc = R.getNameLoc(); assert(!ExplicitTemplateArgs && "Diagnosing an empty lookup with explicit template args!"); *Out = CorrectTypoDelayed( R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, [=](const TypoCorrection &TC) { - emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, + emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoRange, Args, diagnostic, diagnostic_suggest); }, nullptr, CTK_ErrorRecovery); @@ -2436,7 +2436,7 @@ } // Give up, we can't recover. - Diag(R.getNameLoc(), diagnostic) << Name; + Diag(R.getNameLoc(), diagnostic) << Name << TypoRange; return true; } Index: clang/test/Misc/reduced-diags-macros-backtrace.cpp =================================================================== --- clang/test/Misc/reduced-diags-macros-backtrace.cpp +++ clang/test/Misc/reduced-diags-macros-backtrace.cpp @@ -11,37 +11,69 @@ int a = LEVEL1(b); + // ALL: {{.*}}:12:9: error: use of undeclared identifier 'p' // ALL-NEXT: int a = LEVEL1(b); -// ALL-NEXT: ^ +// ALL-NEXT: ^~~~~~~~~ // ALL-NEXT: {{.*}}:10:19: note: expanded from macro 'LEVEL1' // ALL-NEXT: #define LEVEL1(x) LEVEL2(x) -// ALL-NEXT: ^ +// ALL-NEXT: ^~~~~~~~~ // ALL-NEXT: {{.*}}:9:19: note: expanded from macro 'LEVEL2' // ALL-NEXT: #define LEVEL2(x) LEVEL3(x) -// ALL-NEXT: ^ +// ALL-NEXT: ^~~~~~~~~ // ALL-NEXT: {{.*}}:8:19: note: expanded from macro 'LEVEL3' // ALL-NEXT: #define LEVEL3(x) LEVEL4(x) -// ALL-NEXT: ^ +// ALL-NEXT: ^~~~~~~~~ // ALL-NEXT: {{.*}}:7:23: note: expanded from macro 'LEVEL4' // ALL-NEXT: #define LEVEL4(x) ADD(p,x) // ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:6:20: note: expanded from macro 'ADD' +// ALL-NEXT: #define ADD(x,y) G(x) + y +// ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:5:16: note: expanded from macro 'G' +// ALL-NEXT: #define G(x) F(x) + 2 +// ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:4:14: note: expanded from macro 'F' +// ALL-NEXT: #define F(x) x + 1 +// ALL-NEXT: ^ // ALL-NEXT: {{.*}}:12:16: error: use of undeclared identifier 'b' // ALL-NEXT: int a = LEVEL1(b); // ALL-NEXT: ^ -// ALL-NEXT: 2 errors generated. +// ALL-NEXT: {{.*}}:10:26: note: expanded from macro 'LEVEL1' +// ALL-NEXT: #define LEVEL1(x) LEVEL2(x) +// ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:9:26: note: expanded from macro 'LEVEL2' +// ALL-NEXT: #define LEVEL2(x) LEVEL3(x) +// ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:8:26: note: expanded from macro 'LEVEL3' +// ALL-NEXT: #define LEVEL3(x) LEVEL4(x) +// ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:7:25: note: expanded from macro 'LEVEL4' +// ALL-NEXT: #define LEVEL4(x) ADD(p,x) +// ALL-NEXT: ^ +// ALL-NEXT: {{.*}}:6:25: note: expanded from macro 'ADD' +// ALL-NEXT: #define ADD(x,y) G(x) + y +// ALL-NEXT: ^ + // ALL-NEXT: 2 errors generated. // SKIP: {{.*}}:12:9: error: use of undeclared identifier 'p' // SKIP-NEXT: int a = LEVEL1(b); -// SKIP-NEXT: ^ +// SKIP-NEXT: ^~~~~~~~~ // SKIP-NEXT: {{.*}}:10:19: note: expanded from macro 'LEVEL1' // SKIP-NEXT: #define LEVEL1(x) LEVEL2(x) -// SKIP-NEXT: ^ -// SKIP-NEXT: note: (skipping 2 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) -// SKIP-NEXT: {{.*}}:7:23: note: expanded from macro 'LEVEL4' -// SKIP-NEXT: #define LEVEL4(x) ADD(p,x) -// SKIP-NEXT: ^ +// SKIP-NEXT: ^~~~~~~~~ +// SKIP-NEXT: note: (skipping 5 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) +// SKIP-NEXT: {{.*}}:4:14: note: expanded from macro 'F' +// SKIP-NEXT: #define F(x) x + 1 +// SKIP-NEXT: ^ // SKIP-NEXT: {{.*}}:12:16: error: use of undeclared identifier 'b' // SKIP-NEXT: int a = LEVEL1(b); // SKIP-NEXT: ^ +// SKIP-NEXT: {{.*}}:10:26: note: expanded from macro 'LEVEL1' +// SKIP-NEXT: #define LEVEL1(x) LEVEL2(x) +// SKIP-NEXT: ^ +// SKIP-NEXT: note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) +// SKIP-NEXT: {{.*}}:6:25: note: expanded from macro 'ADD' +// SKIP-NEXT: #define ADD(x,y) G(x) + y +// SKIP-NEXT: ^ // SKIP-NEXT: 2 errors generated.