From 81ef625080cb7097044b4461fee0ac5567a44c75 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 3 Jun 2019 18:36:26 +0000 Subject: [PATCH] Permit Exception Spec mismatch with NoThrow on inherited Virtual As reported here: https://bugs.llvm.org/show_bug.cgi?id=42100 This fairly common pattern ends up being an error in MinGW, so relax it in all cases to a warning. llvm-svn: 362434 --- clang/include/clang/Sema/Sema.h | 1 + clang/lib/Sema/SemaExceptionSpec.cpp | 18 +++++++++++++++--- clang/test/SemaCXX/nothrow-vs-exception-specs.cpp | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7bccaf7..0c487725 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1564,6 +1564,7 @@ public: bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, + const PartialDiagnostic &NoThrowDiagID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 8f3ebc2..5274532 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -744,6 +744,7 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, + const PartialDiagnostic &NoThrowDiagID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, @@ -790,6 +791,16 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, Subset, SubLoc); + // Allow __declspec(nothrow) to be missing on redeclaration as an extension in + // some cases. + if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can && + SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) { + Diag(SubLoc, NoThrowDiagID); + if (NoteID.getDiagID() != 0) + Diag(SuperLoc, NoteID); + return true; + } + // If the subset contains everything or the superset contains nothing, we've // failed. if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) || @@ -919,9 +930,9 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { // void (*q)(void (*) throw(int)) = p; // } // ... because it might be instantiated with T=int. - return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(), - ToFunc, From->getSourceRange().getBegin(), - FromFunc, SourceLocation()) && + return CheckExceptionSpecSubset( + PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc, + From->getSourceRange().getBegin(), FromFunc, SourceLocation()) && !getLangOpts().CPlusPlus17; } @@ -953,6 +964,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(diag::err_deep_exception_specs_differ), PDiag(diag::note_overridden_virtual_function), + PDiag(diag::ext_override_exception_spec), Old->getType()->getAs(), Old->getLocation(), New->getType()->getAs(), diff --git a/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp b/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp index 78416d8..7a00783 100644 --- a/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp +++ b/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp @@ -69,3 +69,22 @@ struct S { __declspec(nothrow) void f4() noexcept(true); __declspec(nothrow) void f5() noexcept(false); }; + +namespace PR42100 { +class Base { +public: + // expected-note@+1{{overridden virtual function is here}} + virtual __declspec(nothrow) void foo() = 0; + // expected-note@+1{{previous declaration is here}} + __declspec(nothrow) void bar(); +}; + +// expected-warning@+1{{'bar' is missing exception specification '__attribute__((nothrow))'}} +void Base::bar() {} + +class Sub : public Base { +public: + // expected-warning@+1{{exception specification of overriding function is more lax than base version}} + void foo() {} +}; +} -- 2.7.4