[cfe-commits] r63939 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/SemaDecl.cpp test/SemaCXX/nested-name-spec.cpp test/SemaCXX/qualified-id-lookup.cpp

Piotr Rak piotr.rak at gmail.com
Fri Feb 6 12:43:09 PST 2009


Hi Doug,

I have two minor comments.

2009/2/6 Douglas Gregor <dgregor at apple.com>:
> Author: dgregor
> Date: Fri Feb  6 11:46:57 2009
> New Revision: 63939
>
> URL: http://llvm.org/viewvc/llvm-project?rev=63939&view=rev
> Log:
> Diagnose attempts to define a namespace member out-of-line when no
> matching member exists. Thanks to Piotr Rak for reporting the problem!
>
> Modified:
>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
>    cfe/trunk/lib/Sema/SemaDecl.cpp
>    cfe/trunk/test/SemaCXX/nested-name-spec.cpp
>    cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=63939&r1=63938&r2=63939&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Fri Feb  6 11:46:57 2009
> @@ -860,6 +860,8 @@
>      "expected a class or namespace")
>  DIAG(err_invalid_declarator_scope, ERROR,
>      "definition or redeclaration of %0 not in a namespace enclosing %1")
> +DIAG(err_invalid_declarator_global_scope, ERROR,
> +     "definition or redeclaration of %0 cannot name the global scope")
>  DIAG(err_invalid_declarator_in_function, ERROR,
>      "definition or redeclaration of %0 not allowed inside a function")
>  DIAG(err_not_tag_in_scope, ERROR,
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=63939&r1=63938&r2=63939&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Feb  6 11:46:57 2009
> @@ -1139,14 +1139,14 @@
>   return DeclarationName();
>  }
>
> -/// isNearlyMatchingMemberFunction - Determine whether the C++ member
> -/// functions Declaration and Definition are "nearly" matching. This
> -/// heuristic is used to improve diagnostics in the case where an
> -/// out-of-line member function definition doesn't match any
> -/// declaration within the class.
> -static bool isNearlyMatchingMemberFunction(ASTContext &Context,
> -                                           FunctionDecl *Declaration,
> -                                           FunctionDecl *Definition) {
> +/// isNearlyMatchingFunction - Determine whether the C++ functions
> +/// Declaration and Definition are "nearly" matching. This heuristic
> +/// is used to improve diagnostics in the case where an out-of-line
> +/// function definition doesn't match any declaration within
> +/// the class or namespace.
> +static bool isNearlyMatchingFunction(ASTContext &Context,
> +                                     FunctionDecl *Declaration,
> +                                     FunctionDecl *Definition) {
>   if (Declaration->param_size() != Definition->param_size())
>     return false;
>   for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) {
> @@ -1219,17 +1219,21 @@
>     // In this case, PrevDecl will point to the overload set
>     // containing the two f's declared in X, but neither of them
>     // matches.
> -    if (!CurContext->Encloses(DC)) {
> +
> +    // First check whether we named the global scope.
> +    if (isa<TranslationUnitDecl>(DC)) {
> +      Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
> +        << Name << D.getCXXScopeSpec().getRange();
> +    } else if (!CurContext->Encloses(DC)) {
>       // The qualifying scope doesn't enclose the original declaration.
>       // Emit diagnostic based on current scope.
>       SourceLocation L = D.getIdentifierLoc();
>       SourceRange R = D.getCXXScopeSpec().getRange();
> -      if (isa<FunctionDecl>(CurContext)) {
> +      if (isa<FunctionDecl>(CurContext))
>         Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
> -      } else {
> +      else
>         Diag(L, diag::err_invalid_declarator_scope)
> -          << Name << cast<NamedDecl>(DC)->getDeclName() << R;
> -      }
> +          << Name << cast<NamedDecl>(DC) << R;
>       InvalidDecl = true;
>     }
>   }
> @@ -1628,10 +1632,9 @@
>
>   // Merge the decl with the existing one if appropriate. Since C functions
>   // are in a flat namespace, make sure we consider decls in outer scopes.
> +  bool Redeclaration = false;
>   if (PrevDecl &&
>       (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
> -    bool Redeclaration = false;
> -
>     // If C++, determine whether NewFD is an overload of PrevDecl or
>     // a declaration that requires merging. If it's an overload,
>     // there's no more work to do here; we'll just add the new
> @@ -1664,40 +1667,46 @@
>         }
>       }
>     }
> +  }
>
> -    if (!Redeclaration && D.getCXXScopeSpec().isSet()) {
> -      // The user tried to provide an out-of-line definition for a
> -      // member function, but there was no such member function
> -      // declared (C++ [class.mfct]p2). For example:
> -      //
> -      // class X {
> -      //   void f() const;
> -      // };
> -      //
> -      // void X::f() { } // ill-formed
> -      //
> -      // 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)
> -        << cast<CXXRecordDecl>(DC)->getDeclName()
> -        << D.getCXXScopeSpec().getRange();
> -      InvalidDecl = true;
> -
> -      LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
> -                                              true);
> -      assert(!Prev.isAmbiguous() &&
> -             "Cannot have an ambiguity in previous-declaration lookup");
> -      for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
> -           Func != FuncEnd; ++Func) {
> -        if (isa<CXXMethodDecl>(*Func) &&
> -            isNearlyMatchingMemberFunction(Context, cast<FunctionDecl>(*Func),
> -                                           NewFD))
> -          Diag((*Func)->getLocation(), diag::note_member_def_close_match);
> -      }
> -
> -      PrevDecl = 0;
> +  if (D.getCXXScopeSpec().isSet() &&
> +      (!PrevDecl || !Redeclaration)) {
> +    // The user tried to provide an out-of-line definition for a
> +    // function that is a member of a class or namespace, but there
> +    // was no such member function declared (C++ [class.mfct]p2,
> +    // C++ [namespace.memdef]p2). For example:
> +    //
> +    // class X {
> +    //   void f() const;
> +    // };
> +    //
> +    // void X::f() { } // ill-formed
> +    //
> +    // 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).
> +    DeclarationName CtxName;
> +    if (DC->isRecord())
> +      CtxName = cast<RecordDecl>(DC)->getDeclName();
> +    else if (DC->isNamespace())
> +      CtxName = cast<NamespaceDecl>(DC)->getDeclName();
> +    // FIXME: global scope

This FIXME is not needed, since D.getCXXScopeSpec().isSet() so is
qualified name lookup and things like:

  void ::f() {}

are already diagnosed. We will never get TranslationUnitDecl here, right?

> +    Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
> +      << CtxName << D.getCXXScopeSpec().getRange();
> +    InvalidDecl = true;
> +
> +    LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
> +                                            true);
> +    assert(!Prev.isAmbiguous() &&
> +           "Cannot have an ambiguity in previous-declaration lookup");
> +    for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
> +         Func != FuncEnd; ++Func) {
> +      if (isa<FunctionDecl>(*Func) &&
> +          isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
> +        Diag((*Func)->getLocation(), diag::note_member_def_close_match);
>     }

This does not display any possible function declarations for case like:

namespace A {
  int f();
  int f(char);
}

void A::f(double) {
}

Is that what we want here? Maybe we should handle case (!Prev)
separatly form (!Redeclaration), and use err_ovl_candidate instead?

> +
> +    PrevDecl = 0;
>   }
>
>   // Handle attributes. We need to have merged decls when handling attributes
>
> Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=63939&r1=63938&r2=63939&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
> +++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Fri Feb  6 11:46:57 2009
> @@ -123,3 +123,28 @@
>  Operators::operator bool() {
>   return true;
>  }
> +
> +namespace A {
> +  void g(int&); // expected-note{{member declaration nearly matches}}
> +}
> +
> +void A::f() {} // expected-error{{out-of-line definition does not match any declaration in 'A'}}
> +
> +void A::g(const int&) { } // expected-error{{out-of-line definition does not match any declaration in 'A'}}
> +
> +struct Struct { };
> +
> +void Struct::f() { } // expected-error{{out-of-line definition does not match any declaration in 'Struct'}}
> +
> +void global_func(int);
> +void global_func2(int);
> +
> +namespace N {
> +  void ::global_func(int) { } // expected-error{{definition or redeclaration of 'global_func' cannot name the global scope}}
> +
> +  void f();
> +  // FIXME: if we move this to a separate definition of N, things break!
> +}
> +void ::global_func2(int) { } // expected-error{{definition or redeclaration of 'global_func2' cannot name the global scope}}
> +
> +void N::f() { } // okay
>
> Modified: cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp?rev=63939&r1=63938&r2=63939&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp (original)
> +++ cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp Fri Feb  6 11:46:57 2009
> @@ -109,4 +109,3 @@
>  int Undef::f() {
>   return sizeof(Undef);
>  }
> -
>

Piotr



More information about the cfe-commits mailing list