<br><div class="gmail_quote">On Thu, Aug 18, 2011 at 1:38 PM, Eli Friedman <span dir="ltr"><<a href="mailto:eli.friedman@gmail.com">eli.friedman@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div><div></div><div class="h5">On Thu, Aug 18, 2011 at 11:19 AM, Kaelyn Uhrain <<a href="mailto:rikka@google.com">rikka@google.com</a>> wrote:<br>
> Author: rikka<br>
> Date: Thu Aug 18 13:19:12 2011<br>
> New Revision: 137966<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=137966&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=137966&view=rev</a><br>
> Log:<br>
> Rework DiagnoseInvalidRedeclaration to add the ability to correct typos when<br>
> diagnosing invalid function redeclarations.<br>
><br>
> Modified:<br>
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> cfe/trunk/lib/Sema/SemaDecl.cpp<br>
> cfe/trunk/test/SemaCXX/function-redecl.cpp<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=137966&r1=137965&r2=137966&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=137966&r1=137965&r2=137966&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 18 13:19:12 2011<br>
> @@ -610,6 +610,8 @@<br>
> "friend type templates must use an elaborated type">;<br>
> def err_no_matching_local_friend : Error<<br>
> "no matching function found in local scope">;<br>
> +def err_no_matching_local_friend_suggest : Error<<br>
> + "no matching function %0 found in local scope; did you mean %2">;<br>
> def err_partial_specialization_friend : Error<<br>
> "partial specialization cannot be declared as a friend">;<br>
><br>
> @@ -3038,6 +3040,9 @@<br>
> "out-of-line definition of %0 from class %1 without definition">;<br>
> def err_member_def_does_not_match : Error<<br>
> "out-of-line definition of %0 does not match any declaration in %1">;<br>
> +def err_member_def_does_not_match_suggest : Error<<br>
> + "out-of-line definition of %0 does not match any declaration in %1; "<br>
> + "did you mean %2">;<br>
> def err_member_def_does_not_match_ret_type : Error<<br>
> "out-of-line definition of %q0 differs from the declaration in the return type">;<br>
> def err_nonstatic_member_out_of_line : Error<<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=137966&r1=137965&r2=137966&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=137966&r1=137965&r2=137966&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 18 13:19:12 2011<br>
> @@ -4204,28 +4204,79 @@<br>
> return AddedAny;<br>
> }<br>
><br>
> -static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {<br>
> - LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(),<br>
> +static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD,<br>
> + bool isFriendDecl) {<br>
> + DeclarationName Name = NewFD->getDeclName();<br>
> + DeclContext *DC = NewFD->getDeclContext();<br>
> + LookupResult Prev(S, Name, NewFD->getLocation(),<br>
> Sema::LookupOrdinaryName, Sema::ForRedeclaration);<br>
> llvm::SmallVector<unsigned, 1> MismatchedParams;<br>
> - S.LookupQualifiedName(Prev, NewFD->getDeclContext());<br>
> + llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;<br>
> + TypoCorrection Correction;<br>
> + unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend<br>
> + : diag::err_member_def_does_not_match;<br>
> +<br>
> + NewFD->setInvalidDecl();<br>
> + S.LookupQualifiedName(Prev, DC);<br>
> assert(!Prev.isAmbiguous() &&<br>
> "Cannot have an ambiguity in previous-declaration lookup");<br>
> - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();<br>
> - Func != FuncEnd; ++Func) {<br>
> - FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);<br>
> - if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,<br>
> - MismatchedParams)) {<br>
> - if (MismatchedParams.size() > 0) {<br>
> - unsigned Idx = MismatchedParams.front();<br>
> - ParmVarDecl *FDParam = FD->getParamDecl(Idx);<br>
> - S.Diag(FDParam->getTypeSpecStartLoc(),<br>
> - diag::note_member_def_close_param_match)<br>
> - << Idx+1 << FDParam->getType() << NewFD->getParamDecl(Idx)->getType();<br>
> - } else<br>
> - S.Diag(FD->getLocation(), diag::note_member_def_close_match);<br>
> + if (!Prev.empty()) {<br>
> + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();<br>
> + Func != FuncEnd; ++Func) {<br>
> + FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);<br>
> + if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,<br>
> + MismatchedParams)) {<br>
> + // Add 1 to the index so that 0 can mean the mismatch didn't<br>
> + // involve a parameter<br>
> + unsigned ParamNum =<br>
> + MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;<br>
> + NearMatches.push_back(std::make_pair(FD, ParamNum));<br>
> + }<br>
> + }<br>
> + // If the qualified name lookup yielded nothing, try typo correction<br>
> + } else if ((Correction = S.CorrectTypo(Prev.getLookupNameInfo(),<br>
> + Prev.getLookupKind(), 0, 0, DC))) {<br>
> + DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest<br>
> + : diag::err_member_def_does_not_match_suggest;<br>
> + for (TypoCorrection::decl_iterator CDecl = Correction.begin(),<br>
> + CDeclEnd = Correction.end();<br>
> + CDecl != CDeclEnd; ++CDecl) {<br>
> + FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);<br>
> + if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,<br>
> + MismatchedParams)) {<br>
> + // Add 1 to the index so that 0 can mean the mismatch didn't<br>
> + // involve a parameter<br>
> + unsigned ParamNum =<br>
> + MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;<br>
> + NearMatches.push_back(std::make_pair(FD, ParamNum));<br>
> + }<br>
> }<br>
> }<br>
> +<br>
> + if (Correction)<br>
> + S.Diag(NewFD->getLocation(), DiagMsg)<br>
> + << Name << DC << Correction.getQuoted(S.getLangOptions())<br>
> + << FixItHint::CreateReplacement(<br>
> + NewFD->getLocation(), Correction.getAsString(S.getLangOptions()));<br>
> + else<br>
> + S.Diag(NewFD->getLocation(), DiagMsg) << Name << DC << NewFD->getLocation();<br>
> +<br>
> + for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator<br>
> + NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();<br>
> + NearMatch != NearMatchEnd; ++NearMatch) {<br>
> + FunctionDecl *FD = NearMatch->first;<br>
> +<br>
> + if (unsigned Idx = NearMatch->second) {<br>
> + ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);<br>
> + S.Diag(FDParam->getTypeSpecStartLoc(),<br>
> + diag::note_member_def_close_param_match)<br>
> + << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();<br>
> + } else if (Correction) {<br>
> + S.Diag(FD->getLocation(), diag::note_previous_decl)<br>
> + << Correction.getQuoted(S.getLangOptions());<br>
> + } else<br>
> + S.Diag(FD->getLocation(), diag::note_member_def_close_match);<br>
> + }<br>
> }<br>
><br>
> NamedDecl*<br>
> @@ -4939,19 +4990,14 @@<br>
> // Complain about this problem, and attempt to suggest close<br>
> // matches (e.g., those that differ only in cv-qualifiers and<br>
> // whether the parameter types are references).<br>
> - Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)<br>
> - << Name << DC << D.getCXXScopeSpec().getRange();<br>
> - NewFD->setInvalidDecl();<br>
><br>
> - DiagnoseInvalidRedeclaration(*this, NewFD);<br>
> + DiagnoseInvalidRedeclaration(*this, NewFD, false);<br>
> }<br>
><br>
> // Unqualified local friend declarations are required to resolve<br>
> // to something.<br>
> } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {<br>
> - Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend);<br>
> - NewFD->setInvalidDecl();<br>
> - DiagnoseInvalidRedeclaration(*this, NewFD);<br>
> + DiagnoseInvalidRedeclaration(*this, NewFD, true);<br>
> }<br>
><br>
> } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/function-redecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=137966&r1=137965&r2=137966&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=137966&r1=137965&r2=137966&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/function-redecl.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/function-redecl.cpp Thu Aug 18 13:19:12 2011<br>
> @@ -24,3 +24,29 @@<br>
> }<br>
> }<br>
> }<br>
> +<br>
> +class A {<br>
> + void typocorrection(); // expected-note {{'typocorrection' declared here}}<br>
> +};<br>
> +<br>
> +void A::Notypocorrection() { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'A'; did you mean 'typocorrection'}}<br>
> +}<br>
> +<br>
> +<br>
> +namespace test0 {<br>
> + void dummy() {<br>
> + void Bar(); // expected-note {{'Bar' declared here}}<br>
> + class A {<br>
> + friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean 'Bar'}}<br>
> + };<br>
> + }<br>
> +}<br>
> +<br>
> +<br>
> +class B {<br>
> + void typocorrection(const int); // expected-note {{type of 1st parameter of member declaration does not match definition}}<br>
> + void typocorrection(double);<br>
> +};<br>
> +<br>
> +void B::Notypocorrection(int) { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'B'; did you mean 'typocorrection'}}<br>
> +}<br>
<br>
</div></div>This is giving an extremely strange-looking error for the following:<br>
<br>
struct A { int f(); };<br>
struct B : public A {};<br>
int B::f() { return 3; }<br>
<br>
<stdin>:3:8: error: out-of-line definition of 'f' does not match any<br>
declaration in 'B'; did you mean 'f'<br>
int B::f() { return 3; }<br>
^<br>
f<br>
<stdin>:1:16: note: 'f' declared here<br>
struct A { int f(); };<br>
^<br>
1 error generated.<br>
<font color="#888888"><br>
-Eli<br>
</font></blockquote></div><br>This issue is fixed by r137987. I'm looking into the issue Jordy brought up now.<br><br>Cheers,<br>Kaelyn<br>