Index: include/clang/Sema/TemplateDeduction.h =================================================================== --- include/clang/Sema/TemplateDeduction.h +++ include/clang/Sema/TemplateDeduction.h @@ -68,8 +68,10 @@ /// \brief Take ownership of the SFINAE diagnostic. void takeSFINAEDiagnostic(PartialDiagnosticAt &PD) { assert(HasSFINAEDiagnostic); - PD.first = SuppressedDiagnostics.front().first; - PD.second.swap(SuppressedDiagnostics.front().second); + unsigned NumberOfDiagnostics = SuppressedDiagnostics.size(); + PartialDiagnosticAt &PDiag = SuppressedDiagnostics[((NumberOfDiagnostics == 2) ? 1 : 0)]; + PD.first = PDiag.first; + PD.second.swap(PDiag.second); SuppressedDiagnostics.clear(); HasSFINAEDiagnostic = false; } @@ -98,8 +100,6 @@ /// \brief Add a new diagnostic to the set of diagnostics void addSuppressedDiagnostic(SourceLocation Loc, PartialDiagnostic PD) { - if (HasSFINAEDiagnostic) - return; SuppressedDiagnostics.emplace_back(Loc, std::move(PD)); } Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -9105,6 +9105,16 @@ return; } + // If the diagnsotics is already for overload candidate substitution + // failure, then just emit the diagnostics as is. + if (PDiag && (PDiag->second.getDiagID() == + diag::note_ovl_candidate_substitution_failure || + PDiag->second.getDiagID() == + diag::note_ovl_candidate_disabled_by_enable_if)) { + S.Diag(PDiag->first, PDiag->second); + return; + } + // Format the SFINAE diagnostic into the argument string. // FIXME: Add a general mechanism to include a PartialDiagnostic *'s // formatted message in another diagnostic. @@ -9116,7 +9126,7 @@ PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString); } - S.Diag(Templated->getLocation(), + S.Diag(PDiag->first, diag::note_ovl_candidate_substitution_failure) << TemplateArgString << SFINAEArgString << R; MaybeEmitInheritedConstructorNote(S, Templated); Index: test/SemaCXX/sfinae-error-overload.cpp =================================================================== --- test/SemaCXX/sfinae-error-overload.cpp +++ test/SemaCXX/sfinae-error-overload.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 2>&1 | FileCheck %s +template auto h(T x)->decltype(x.smurf()){return x.smurf();} +void h() {} +template auto g(T x)->decltype(h(x)){return h(x);} +template auto f(T x)->decltype(g(x)){return g(x);} +int main(){ + f(3); +} + +// CHECK: sfinae-error-overload.cpp:7:3: error: no matching function for call to 'f' +// CHECK-NEXT: f(3); +// CHECK: sfinae-error-overload.cpp:4:41: note: candidate template ignored: substitution failure [with T = int]: no matching function for call to 'h' +// CHECK-NEXT: template auto g(T x)->decltype(h(x)){return h(x);} + Index: test/SemaCXX/sfinae-error.cpp =================================================================== --- test/SemaCXX/sfinae-error.cpp +++ test/SemaCXX/sfinae-error.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 2>&1 | FileCheck --check-prefix=CHECK1 %s +template auto h(T x)->decltype(x.smurf()){return x.smurf();} +template auto g(T x)->decltype(h(x)){return h(x);} +template auto f(T x)->decltype(g(x)){return g(x);} +int main(){ + f(3); +} + +// CHECK1: sfinae-error.cpp:6:3: error: no matching function for call to 'f' +// CHECK1: f(3); +// CHECK1: sfinae-error.cpp:2:42: note: candidate template ignored: substitution failure [with T = int]: member reference base type 'int' is not a structure or union +// CHECK1-NEXT: template auto h(T x)->decltype(x.smurf()){return x.smurf();} +