[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

Douglas Gregor dgregor at apple.com
Fri Feb 6 09:46:57 PST 2009


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
+    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);
     }
+    
+    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);
 }
-





More information about the cfe-commits mailing list