]> granicus.if.org Git - clang/commitdiff
Diagnose when a 'static' member function overrides a virtual function
authorDouglas Gregor <dgregor@apple.com>
Wed, 13 Oct 2010 22:55:32 +0000 (22:55 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 13 Oct 2010 22:55:32 +0000 (22:55 +0000)
in a base class. Fixes PR8168.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116448 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/SemaCXX/virtual-override.cpp

index bff8c054f1de0bd0f0a788f1a917a04be6af8a68..ef6d05b505021881c36a08f5ad2c4d9428e9a91f 100644 (file)
@@ -608,6 +608,8 @@ def err_virtual_non_function : Error<
   "'virtual' can only appear on non-static member functions">;
 def err_virtual_out_of_class : Error<
   "'virtual' can only be specified inside the class definition">;
+def err_static_overrides_virtual : Error<
+  "'static' member function %0 overrides a virtual function in a base class">;
 def err_explicit_non_function : Error<
   "'explicit' can only appear on non-static member functions">;
 def err_explicit_out_of_class : Error<
index d9057a1e0d7c9da32cd37f6708f62d8e87049ca7..b1cd5628a70f691de5878bae48e53a9d19a8611c 100644 (file)
@@ -712,7 +712,7 @@ public:
                                      MultiTemplateParamsArg TemplateParamLists,
                                      bool IsFunctionDefinition,
                                      bool &Redeclaration);
-  void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
+  bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
   void CheckFunctionDeclaration(Scope *S,
                                 FunctionDecl *NewFD, LookupResult &Previous,
                                 bool IsExplicitSpecialization,
index 10785270e5b2d53c24f99df8e6d8c8b9c690579f..6f0a7da45059bcb6ded6bb24346df0c34c299445 100644 (file)
@@ -3153,23 +3153,28 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
 
 /// AddOverriddenMethods - See if a method overrides any in the base classes,
 /// and if so, check that it's a valid override and remember it.
-void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
+bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
   // Look for virtual methods in base classes that this method might override.
   CXXBasePaths Paths;
   FindOverriddenMethodData Data;
   Data.Method = MD;
   Data.S = this;
+  bool AddedAny = false;
   if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) {
     for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
          E = Paths.found_decls_end(); I != E; ++I) {
       if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
         if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
             !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
-            !CheckOverridingFunctionAttributes(MD, OldMD))
+            !CheckOverridingFunctionAttributes(MD, OldMD)) {
           MD->addOverriddenMethod(OldMD->getCanonicalDecl());
+          AddedAny = true;
+        }
       }
     }
   }
+  
+  return AddedAny;
 }
 
 static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {
@@ -3964,8 +3969,6 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
         DeclarationName Name
           = Context.DeclarationNames.getCXXDestructorName(
                                         Context.getCanonicalType(ClassType));
-//         NewFD->getDeclName().dump();
-//         Name.dump();
         if (NewFD->getDeclName() != Name) {
           Diag(NewFD->getLocation(), diag::err_destructor_name);
           return NewFD->setInvalidDecl();
@@ -3979,8 +3982,23 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
     // Find any virtual functions that this function overrides.
     if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) {
       if (!Method->isFunctionTemplateSpecialization() && 
-          !Method->getDescribedFunctionTemplate())
-        AddOverriddenMethods(Method->getParent(), Method);
+          !Method->getDescribedFunctionTemplate()) {
+        if (AddOverriddenMethods(Method->getParent(), Method)) {
+          // If the function was marked as "static", we have a problem.
+          if (NewFD->getStorageClass() == SC_Static) {
+            Diag(NewFD->getLocation(), diag::err_static_overrides_virtual)
+              << NewFD->getDeclName();
+            for (CXXMethodDecl::method_iterator 
+                      Overridden = Method->begin_overridden_methods(),
+                   OverriddenEnd = Method->end_overridden_methods();
+                 Overridden != OverriddenEnd;
+                 ++Overridden) {
+              Diag((*Overridden)->getLocation(), 
+                   diag::note_overridden_virtual_function);
+            }
+          }
+        }        
+      }
     }
 
     // Extra checking for C++ overloaded operators (C++ [over.oper]).
index b1d2a3a05c7cadf36482f77ed7b9dfb05727c0aa..ba2b80dacd0f168e7473d64fbba43ab8d1e3a612 100644 (file)
@@ -276,3 +276,15 @@ namespace T12 {
     virtual B& f(); // expected-error {{virtual function 'f' has a different return type ('T12::B &') than the function it overrides (which has return type 'T12::A &&')}}
   };
 };
+
+namespace PR8168 {
+  class A {
+  public:
+    virtual void foo() {} // expected-note{{overridden virtual function is here}}
+  };
+
+  class B : public A {
+  public:
+    static void foo() {} // expected-error{{'static' member function 'foo' overrides a virtual function}}
+  };
+}