From: David Blaikie Date: Wed, 17 Oct 2012 00:47:58 +0000 (+0000) Subject: Implement C++ 10.3p16 - overrides involving deleted functions must match. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5708c18904304ed4e39abed8131fcad5e2fc0896;p=clang Implement C++ 10.3p16 - overrides involving deleted functions must match. Only deleted functions may override deleted functions and non-deleted functions may only override non-deleted functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166082 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8389e4e10f..3c420b9d2b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -865,6 +865,12 @@ def note_pure_virtual_function : Note< def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; +def err_deleted_override : Error< + "deleted function %0 cannot override a non-deleted function">; + +def err_non_deleted_override : Error< + "non-deleted function %0 cannot override a deleted function">; + def warn_weak_vtable : Warning< "%0 has no out-of-line virtual method definitions; its vtable will be " "emitted in every translation unit">, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4161078d65..6791273384 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4733,6 +4733,31 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } +namespace { + enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; +} +/// \brief Report an error regarding overriding, along with any relevant +/// overriden methods. +/// +/// \param DiagID the primary error to report. +/// \param MD the overriding method. +/// \param OEK which overrides to include as notes. +static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, + OverrideErrorKind OEK = OEK_All) { + S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) { + // This check (& the OEK parameter) could be replaced by a predicate, but + // without lambdas that would be overkill. This is still nicer than writing + // out the diag loop 3 times. + if ((OEK == OEK_All) || + (OEK == OEK_NonDeleted && !(*I)->isDeleted()) || + (OEK == OEK_Deleted && (*I)->isDeleted())) + S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function); + } +} + /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4741,6 +4766,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; + bool hasDeletedOverridenMethods = false; + bool hasNonDeletedOverridenMethods = false; bool AddedAny = false; if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), @@ -4750,12 +4777,21 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { + hasDeletedOverridenMethods |= OldMD->isDeleted(); + hasNonDeletedOverridenMethods |= !OldMD->isDeleted(); AddedAny = true; } } } } - + + if (hasDeletedOverridenMethods && !MD->isDeleted()) { + ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted); + } + if (hasNonDeletedOverridenMethods && MD->isDeleted()) { + ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted); + } + return AddedAny; } @@ -6068,16 +6104,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, 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); - } + ReportOverrides(*this, diag::err_static_overrides_virtual, Method); } } } diff --git a/test/CXX/class.derived/class.abstract/p16.cpp b/test/CXX/class.derived/class.abstract/p16.cpp new file mode 100644 index 0000000000..93f905cd33 --- /dev/null +++ b/test/CXX/class.derived/class.abstract/p16.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s + +struct A { + virtual void a(); // expected-note{{overridden virtual function is here}} + virtual void b() = delete; // expected-note{{overridden virtual function is here}} +}; + +struct B: A { + virtual void a() = delete; // expected-error{{deleted function 'a' cannot override a non-deleted function}} + virtual void b(); // expected-error{{non-deleted function 'b' cannot override a deleted function}} +}; + +struct C: A { + virtual void a(); + virtual void b() = delete; +};