summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Sema/Sema.h2
-rw-r--r--clang/lib/Sema/Sema.cpp6
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp47
-rw-r--r--clang/test/SemaTemplate/exception-spec-crash.cpp30
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_;
+};
OpenPOWER on IntegriCloud