From 01f8e7c6bbc6bba8dacd5640a497771c4d44f710 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 22 Nov 2014 03:09:05 +0000 Subject: [PATCH] Delay checking overrides for exception specifications if the overridden specification has not yet been parsed. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222603 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 11 +++++------ lib/Sema/Sema.cpp | 2 +- lib/Sema/SemaDeclCXX.cpp | 22 ++++++++-------------- lib/Sema/SemaExceptionSpec.cpp | 19 +++++++++++++------ test/CXX/except/except.spec/p5-delayed.cpp | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 test/CXX/except/except.spec/p5-delayed.cpp diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8b13b9d32a..92a4a472f3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -458,12 +458,11 @@ public: /// cycle detection at the end of the TU. DelegatingCtorDeclsType DelegatingCtorDecls; - /// \brief All the overriding destructors seen during a class definition - /// (there could be multiple due to nested classes) that had their exception - /// spec checks delayed, plus the overridden destructor. - SmallVector, 2> - DelayedDestructorExceptionSpecChecks; + /// \brief All the overriding functions seen during a class definition + /// that had their exception spec checks delayed, plus the overridden + /// function. + SmallVector, 2> + DelayedExceptionSpecChecks; /// \brief All the members seen during a class definition which were both /// explicitly defaulted and had explicitly-specified exception diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 61ee7702c0..b9aaf1616d 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -680,7 +680,7 @@ void Sema::ActOnEndOfTranslationUnit() { // All delayed member exception specs should be checked or we end up accepting // incompatible declarations. assert(DelayedDefaultedMemberExceptionSpecs.empty()); - assert(DelayedDestructorExceptionSpecChecks.empty()); + assert(DelayedExceptionSpecChecks.empty()); // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase( diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 90ca97b5ca..ec625346e8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5340,27 +5340,21 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( } void Sema::CheckDelayedMemberExceptionSpecs() { - SmallVector, - 2> Checks; - SmallVector, 2> Specs; + decltype(DelayedExceptionSpecChecks) Checks; + decltype(DelayedDefaultedMemberExceptionSpecs) Specs; - std::swap(Checks, DelayedDestructorExceptionSpecChecks); + std::swap(Checks, DelayedExceptionSpecChecks); std::swap(Specs, DelayedDefaultedMemberExceptionSpecs); // Perform any deferred checking of exception specifications for virtual // destructors. - for (unsigned i = 0, e = Checks.size(); i != e; ++i) { - const CXXDestructorDecl *Dtor = Checks[i].first; - assert(!Dtor->getParent()->isDependentType() && - "Should not ever add destructors of templates into the list."); - CheckOverridingFunctionExceptionSpec(Dtor, Checks[i].second); - } + for (auto &Check : Checks) + CheckOverridingFunctionExceptionSpec(Check.first, Check.second); // Check that any explicitly-defaulted methods have exception specifications // compatible with their implicit exception specifications. - for (unsigned I = 0, N = Specs.size(); I != N; ++I) - CheckExplicitlyDefaultedMemberExceptionSpec(Specs[I].first, - Specs[I].second); + for (auto &Spec : Specs) + CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second); } namespace { @@ -9298,7 +9292,7 @@ void Sema::ActOnFinishCXXMemberDecls() { if (CXXRecordDecl *Record = dyn_cast(CurContext)) { if (Record->isInvalidDecl()) { DelayedDefaultedMemberExceptionSpecs.clear(); - DelayedDestructorExceptionSpecChecks.clear(); + DelayedExceptionSpecChecks.clear(); return; } } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 7175c01673..2387325be4 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -801,6 +801,11 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { + // If the new exception specification hasn't been parsed yet, skip the check. + // We'll get called again once it's been parsed. + if (New->getType()->castAs()->getExceptionSpecType() == + EST_Unparsed) + return false; if (getLangOpts().CPlusPlus11 && isa(New)) { // Don't check uninstantiated template destructors at all. We can only // synthesize correct specs after the template is instantiated. @@ -809,16 +814,18 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, if (New->getParent()->isBeingDefined()) { // The destructor might be updated once the definition is finished. So // remember it and check later. - DelayedDestructorExceptionSpecChecks.push_back(std::make_pair( - cast(New), cast(Old))); + DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old)); return false; } } - // If the exception specification hasn't been parsed yet, skip the check. - // We'll get called again once it's been parsed. - if (New->getType()->castAs()->getExceptionSpecType() == - EST_Unparsed) + // If the old exception specification hasn't been parsed yet, remember that + // we need to perform this check when we get to the end of the outermost + // lexically-surrounding class. + if (Old->getType()->castAs()->getExceptionSpecType() == + EST_Unparsed) { + DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old)); return false; + } unsigned DiagID = diag::err_override_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::ext_override_exception_spec; diff --git a/test/CXX/except/except.spec/p5-delayed.cpp b/test/CXX/except/except.spec/p5-delayed.cpp new file mode 100644 index 0000000000..99c0e2de31 --- /dev/null +++ b/test/CXX/except/except.spec/p5-delayed.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s -fexceptions -fcxx-exceptions + +struct A { struct X { virtual ~X() throw(Y); }; struct Y : X {}; }; +struct B { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(Y); }; }; +struct C { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(); }; }; +struct D { struct X { virtual void f() throw(Y); }; struct Y : X { void f() noexcept; }; }; +struct E { struct Y; struct X { virtual Y &operator=(const Y&) throw(Y); }; struct Y : X {}; }; +struct F { + struct X { + virtual void f() throw(Y); // expected-note {{here}} + }; + struct Y : X { + void f() throw(int); // expected-error {{more lax}} + }; +}; -- 2.40.0