From a6c1e3a56afb76876cd06e3646fd7ca57a38d4bb Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 13 Oct 2010 22:55:32 +0000 Subject: [PATCH] Diagnose when a 'static' member function overrides a virtual function 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 | 2 ++ include/clang/Sema/Sema.h | 2 +- lib/Sema/SemaDecl.cpp | 30 +++++++++++++++++----- test/SemaCXX/virtual-override.cpp | 12 +++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index bff8c054f1..ef6d05b505 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d9057a1e0d..b1cd5628a7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 10785270e5..6f0a7da450 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(*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(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]). diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp index b1d2a3a05c..ba2b80dacd 100644 --- a/test/SemaCXX/virtual-override.cpp +++ b/test/SemaCXX/virtual-override.cpp @@ -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}} + }; +} -- 2.40.0