diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 74 | ||||
-rw-r--r-- | clang/test/CXX/class.derived/class.virtual/p3-0x.cpp | 49 |
3 files changed, 91 insertions, 38 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c0de5f7a93c..80e4692c068 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4379,12 +4379,12 @@ public: bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); - /// CheckOverrideControl - Check C++0x override control semantics. - void CheckOverrideControl(const Decl *D); + /// CheckOverrideControl - Check C++11 override control semantics. + void CheckOverrideControl(Decl *D); /// CheckForFunctionMarkedFinal - Checks whether a virtual member function /// overrides a virtual member function marked 'final', according to - /// C++0x [class.virtual]p3. + /// C++11 [class.virtual]p4. bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9933bd10e1f..71c72da93d0 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1405,32 +1405,50 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, return ProcessAccessDeclAttributeList(ASDecl, Attrs); } -/// CheckOverrideControl - Check C++0x override control semantics. -void Sema::CheckOverrideControl(const Decl *D) { +/// CheckOverrideControl - Check C++11 override control semantics. +void Sema::CheckOverrideControl(Decl *D) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); - if (!MD || !MD->isVirtual()) + + // Do we know which functions this declaration might be overriding? + bool OverridesAreKnown = !MD || + (!MD->getParent()->hasAnyDependentBases() && + !MD->getType()->isDependentType()); + + if (!MD || !MD->isVirtual()) { + if (OverridesAreKnown) { + if (OverrideAttr *OA = D->getAttr<OverrideAttr>()) { + Diag(OA->getLocation(), + diag::override_keyword_only_allowed_on_virtual_member_functions) + << "override" << FixItHint::CreateRemoval(OA->getLocation()); + D->dropAttr<OverrideAttr>(); + } + if (FinalAttr *FA = D->getAttr<FinalAttr>()) { + Diag(FA->getLocation(), + diag::override_keyword_only_allowed_on_virtual_member_functions) + << "final" << FixItHint::CreateRemoval(FA->getLocation()); + D->dropAttr<FinalAttr>(); + } + } return; + } - if (MD->isDependentContext()) + if (!OverridesAreKnown) return; - // C++0x [class.virtual]p3: - // If a virtual function is marked with the virt-specifier override and does - // not override a member function of a base class, - // the program is ill-formed. - bool HasOverriddenMethods = + // C++11 [class.virtual]p5: + // If a virtual function is marked with the virt-specifier override and + // does not override a member function of a base class, the program is + // ill-formed. + bool HasOverriddenMethods = MD->begin_overridden_methods() != MD->end_overridden_methods(); - if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) { - Diag(MD->getLocation(), - diag::err_function_marked_override_not_overriding) + if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) + Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding) << MD->getDeclName(); - return; - } } -/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member +/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member /// function overrides a virtual member function marked 'final', according to -/// C++0x [class.virtual]p3. +/// C++11 [class.virtual]p4. bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old) { if (!Old->hasAttr<FinalAttr>()) @@ -1609,31 +1627,17 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, FunTmpl->getTemplatedDecl()->setAccess(AS); } - if (VS.isOverrideSpecified()) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); - if (!MD || !MD->isVirtual()) { - Diag(Member->getLocStart(), - diag::override_keyword_only_allowed_on_virtual_member_functions) - << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc()); - } else - MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); - } - if (VS.isFinalSpecified()) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); - if (!MD || !MD->isVirtual()) { - Diag(Member->getLocStart(), - diag::override_keyword_only_allowed_on_virtual_member_functions) - << "final" << FixItHint::CreateRemoval(VS.getFinalLoc()); - } else - MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); - } + if (VS.isOverrideSpecified()) + Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); + if (VS.isFinalSpecified()) + Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member)) MD->setRangeEnd(VS.getLastLocation()); } - + CheckOverrideControl(Member); assert((Name || isInstField) && "No identifier for non-field ?"); diff --git a/clang/test/CXX/class.derived/class.virtual/p3-0x.cpp b/clang/test/CXX/class.derived/class.virtual/p3-0x.cpp index c4a401bb27c..16f98280ed8 100644 --- a/clang/test/CXX/class.derived/class.virtual/p3-0x.cpp +++ b/clang/test/CXX/class.derived/class.virtual/p3-0x.cpp @@ -20,9 +20,15 @@ struct A { template<typename T> struct B : A { + // FIXME: Diagnose this. virtual void f(T) override; }; +template<typename T> +struct C : A { + virtual void f(int) override; // expected-error {{does not override}} +}; + } namespace Test3 { @@ -51,3 +57,46 @@ struct D : B { }; } + +namespace PR13499 { + struct X { + virtual void f(); + virtual void h(); + }; + template<typename T> struct A : X { + void f() override; + void h() final; + }; + template<typename T> struct B : X { + void g() override; // expected-error {{only virtual member functions can be marked 'override'}} + void i() final; // expected-error {{only virtual member functions can be marked 'final'}} + }; + B<int> b; // no-note + template<typename T> struct C : T { + void g() override; + void i() final; + }; + template<typename T> struct D : X { + virtual void g() override; // expected-error {{does not override}} + virtual void i() final; + }; + template<typename...T> struct E : X { + void f(T...) override; + void g(T...) override; // expected-error {{only virtual member functions can be marked 'override'}} + void h(T...) final; + void i(T...) final; // expected-error {{only virtual member functions can be marked 'final'}} + }; + // FIXME: Diagnose these in the template definition, not in the instantiation. + E<> e; // expected-note {{in instantiation of}} + + template<typename T> struct Y : T { + void f() override; + void h() final; + }; + template<typename T> struct Z : T { + void g() override; // expected-error {{only virtual member functions can be marked 'override'}} + void i() final; // expected-error {{only virtual member functions can be marked 'final'}} + }; + Y<X> y; + Z<X> z; // expected-note {{in instantiation of}} +} |