[cfe-commits] r137966 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/SemaCXX/function-redecl.cpp

Kaelyn Uhrain rikka at google.com
Thu Aug 18 14:40:09 PDT 2011


On Thu, Aug 18, 2011 at 2:16 PM, Chandler Carruth <chandlerc at google.com>wrote:

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

I suspect the reason the qualifiers aren't being shown is that A::f is
visible through B (doesn't need to be qualified), but it isn't valid for
redeclaration. I *think* the fix is to not accept typo corrections where the
only difference is in the qualifier, i.e. where the typo-corrected
identifier is the same as the uncorrected identifier.


>
>>
>> struct A { int f(); };
>> struct B : public A {};
>> int B::f() { return 3; }
>>
>> <stdin>:3:8: error: out-of-line definition of 'f' does not match any
>> declaration in 'B'; did you mean 'f'
>> int B::f() { return 3; }
>>       ^
>>       f
>> <stdin>:1:16: note: 'f' declared here
>> struct A { int f(); };
>>               ^
>> 1 error generated.
>>
>> -Eli
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110818/95d2567a/attachment.html>


More information about the cfe-commits mailing list