diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c7a948fd3fae5..5b50cf3e6f6fc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -799,6 +799,11 @@ Bug Fixes to C++ Support completes (except deduction guides). Fixes: (`#59827 `_) +- Clang now reports error when overriden method's non-class return type drops + qualifiers, or qualifiers of class return type are not subset of super method's. + Fixes: + (`#18233 `_) + - Fix crash when parsing nested requirement. Fixes: (`#73112 `_) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6dfb2d7195203..e08ebe7652bef 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2112,10 +2112,6 @@ def err_covariant_return_incomplete : Error< def err_covariant_return_type_different_qualifications : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 has different qualifiers than %2)">; -def err_covariant_return_type_class_type_more_qualified : Error< - "return type of virtual function %0 is not covariant with the return type of " - "the function it overrides (class type %1 is more qualified than class " - "type %2">; // C++ implicit special member functions def note_in_declaration_of_implicit_special_member : Note< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7385eac48d8c8..354b6bc7e01df 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18448,11 +18448,26 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return true; } - + // C++ [class.virtual]p8: + // The return type of an overriding function shall be either identical to + // the return type of the overridden function or [covariant] // The new class type must have the same or less qualifiers as the old type. - if (NewClassTy.isMoreQualifiedThan(OldClassTy)) { + if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy)) { Diag(New->getLocation(), - diag::err_covariant_return_type_class_type_more_qualified) + diag::err_covariant_return_type_different_qualifications) + << New->getDeclName() << NewTy << OldTy + << New->getReturnTypeSourceRange(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); + return true; + } + + // Non-class return types should not drop qualifiers in overriden method. + if (!OldClassTy->isStructureOrClassType() && + OldClassTy.getLocalCVRQualifiers() != + NewClassTy.getLocalCVRQualifiers()) { + Diag(New->getLocation(), + diag::err_covariant_return_type_different_qualifications) << New->getDeclName() << NewTy << OldTy << New->getReturnTypeSourceRange(); Diag(Old->getLocation(), diag::note_overridden_virtual_function) diff --git a/clang/test/SemaCXX/virtual-override.cpp b/clang/test/SemaCXX/virtual-override.cpp index 72abfc3cf51e1..3a10e15a663a5 100644 --- a/clang/test/SemaCXX/virtual-override.cpp +++ b/clang/test/SemaCXX/virtual-override.cpp @@ -87,7 +87,7 @@ class A { class B : A { virtual a* f(); - virtual const a* g(); // expected-error{{return type of virtual function 'g' is not covariant with the return type of the function it overrides (class type 'const a *' is more qualified than class type 'a *'}} + virtual const a* g(); // expected-error{{return type of virtual function 'g' is not covariant with the return type of the function it overrides ('const a *' has different qualifiers than 'a *')}} }; } @@ -289,3 +289,29 @@ namespace PR8168 { static void foo() {} // expected-error{{'static' member function 'foo' overrides a virtual function}} }; } + +namespace T13 { + class A { + public: + virtual const int* foo(); // expected-note{{overridden virtual function is here}} + }; + + class B: public A { + public: + virtual int* foo(); // expected-error{{return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('int *' has different qualifiers than 'const int *')}} + }; +} + +namespace T14 { + struct a {}; + + class A { + public: + virtual const a* foo(); // expected-note{{overridden virtual function is here}} + }; + + class B: public A { + public: + virtual volatile a* foo(); // expected-error{{return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('volatile a *' has different qualifiers than 'const a *')}} + }; +}