diff options
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 19 | ||||
| -rw-r--r-- | clang/test/CXX/except/except.spec/p5-delayed.cpp | 15 |
5 files changed, 42 insertions, 27 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8b13b9d32a5..92a4a472f36 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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<std::pair<const CXXDestructorDecl*, - const CXXDestructorDecl*>, 2> - DelayedDestructorExceptionSpecChecks; + /// \brief All the overriding functions seen during a class definition + /// that had their exception spec checks delayed, plus the overridden + /// function. + SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2> + DelayedExceptionSpecChecks; /// \brief All the members seen during a class definition which were both /// explicitly defaulted and had explicitly-specified exception diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 61ee7702c07..b9aaf1616d6 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 90ca97b5ca0..ec625346e82 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5340,27 +5340,21 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( } void Sema::CheckDelayedMemberExceptionSpecs() { - SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>, - 2> Checks; - SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 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<CXXRecordDecl>(CurContext)) { if (Record->isInvalidDecl()) { DelayedDefaultedMemberExceptionSpecs.clear(); - DelayedDestructorExceptionSpecChecks.clear(); + DelayedExceptionSpecChecks.clear(); return; } } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 7175c016734..2387325be43 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/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<FunctionProtoType>()->getExceptionSpecType() == + EST_Unparsed) + return false; if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(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<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(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<FunctionProtoType>()->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<FunctionProtoType>()->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/clang/test/CXX/except/except.spec/p5-delayed.cpp b/clang/test/CXX/except/except.spec/p5-delayed.cpp new file mode 100644 index 00000000000..99c0e2de31a --- /dev/null +++ b/clang/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}} + }; +}; |

