diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 47 | ||||
-rw-r--r-- | clang/test/SemaTemplate/exception-spec-crash.cpp | 30 |
4 files changed, 61 insertions, 24 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 76999801231..65f07a88763 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4790,7 +4790,7 @@ public: void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, const FunctionProtoType *T); - void CheckDelayedExplicitlyDefaultedMemberExceptionSpecs(); + void CheckDelayedMemberExceptionSpecs(); //===--------------------------------------------------------------------===// // C++ Derived Classes diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 59648441a6d..41f72a68a38 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -604,8 +604,14 @@ void Sema::ActOnEndOfTranslationUnit() { // valid, but we could do better by diagnosing if an instantiation uses a // name that was not visible at its first point of instantiation. PerformPendingInstantiations(); + CheckDelayedMemberExceptionSpecs(); } + // All delayed member exception specs should be checked or we end up accepting + // incompatible declarations. + assert(DelayedDefaultedMemberExceptionSpecs.empty()); + assert(DelayedDestructorExceptionSpecChecks.empty()); + // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase( std::remove_if(UnusedFileScopedDecls.begin(0, true), diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 81283e1f782..ed5724b88fb 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4873,14 +4873,28 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( SpecifiedType, MD->getLocation()); } -void Sema::CheckDelayedExplicitlyDefaultedMemberExceptionSpecs() { - for (unsigned I = 0, N = DelayedDefaultedMemberExceptionSpecs.size(); - I != N; ++I) - CheckExplicitlyDefaultedMemberExceptionSpec( - DelayedDefaultedMemberExceptionSpecs[I].first, - DelayedDefaultedMemberExceptionSpecs[I].second); +void Sema::CheckDelayedMemberExceptionSpecs() { + SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>, + 2> Checks; + SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 2> Specs; - DelayedDefaultedMemberExceptionSpecs.clear(); + std::swap(Checks, DelayedDestructorExceptionSpecChecks); + 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); + } + + // 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); } namespace { @@ -8191,9 +8205,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { - // Check that any explicitly-defaulted methods have exception specifications - // compatible with their implicit exception specifications. - CheckDelayedExplicitlyDefaultedMemberExceptionSpecs(); + // Perform any delayed checks on exception specifications. + CheckDelayedMemberExceptionSpecs(); // Once all the member initializers are processed, perform checks to see if // any unintialized use is happeneing. @@ -8716,23 +8729,11 @@ void Sema::ActOnFinishCXXMemberDecls() { // If the context is an invalid C++ class, just suppress these checks. if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) { if (Record->isInvalidDecl()) { + DelayedDefaultedMemberExceptionSpecs.clear(); DelayedDestructorExceptionSpecChecks.clear(); return; } } - - // Perform any deferred checking of exception specifications for virtual - // destructors. - for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size(); - i != e; ++i) { - const CXXDestructorDecl *Dtor = - DelayedDestructorExceptionSpecChecks[i].first; - assert(!Dtor->getParent()->isDependentType() && - "Should not ever add destructors of templates into the list."); - CheckOverridingFunctionExceptionSpec(Dtor, - DelayedDestructorExceptionSpecChecks[i].second); - } - DelayedDestructorExceptionSpecChecks.clear(); } void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, diff --git a/clang/test/SemaTemplate/exception-spec-crash.cpp b/clang/test/SemaTemplate/exception-spec-crash.cpp new file mode 100644 index 00000000000..4d9355974c9 --- /dev/null +++ b/clang/test/SemaTemplate/exception-spec-crash.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -DCXX_EXCEPTIONS -fsyntax-only -verify %s + +template <class _Tp> struct is_nothrow_move_constructible { + static const bool value = false; +}; + +template <class _Tp> +class allocator; + +template <> +class allocator<char> {}; + +template <class _Allocator> +class basic_string { + typedef _Allocator allocator_type; + basic_string(basic_string &&__str) + noexcept(is_nothrow_move_constructible<allocator_type>::value); +}; + +class Foo { + Foo(Foo &&) noexcept = default; +#ifdef CXX_EXCEPTIONS +// expected-error@-2 {{does not match the calculated}} +#else +// expected-no-diagnostics +#endif + Foo &operator=(Foo &&) noexcept = default; + basic_string<allocator<char> > vectorFoo_; +}; |