PR14141 (part of DR1351): An implicitly-deduced "any" exception specification
produces an exception of 'noexcept(false)' and is thus compatible with an
explicit exception specification of 'noexcept(false)'.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166404 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index df9433e..ecbcbb0 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3376,18 +3376,11 @@
// Pointer to allow copying
Sema *Self;
// We order exception specifications thus:
- // noexcept is the most restrictive, but is only used in C++0x.
+ // noexcept is the most restrictive, but is only used in C++11.
// throw() comes next.
// Then a throw(collected exceptions)
- // Finally no specification.
+ // Finally no specification, which is expressed as noexcept(false).
// throw(...) is used instead if any called function uses it.
- //
- // If this exception specification cannot be known yet (for instance,
- // because this is the exception specification for a defaulted default
- // constructor and we haven't finished parsing the deferred parts of the
- // class yet), the C++0x standard does not specify how to behave. We
- // record this as an 'unknown' exception specification, which overrules
- // any other specification (even 'none', to keep this rule simple).
ExceptionSpecificationType ComputedEST;
llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
SmallVector<QualType, 4> Exceptions;
@@ -3427,8 +3420,17 @@
/// computed exception specification.
void getEPI(FunctionProtoType::ExtProtoInfo &EPI) const {
EPI.ExceptionSpecType = getExceptionSpecType();
- EPI.NumExceptions = size();
- EPI.Exceptions = data();
+ if (EPI.ExceptionSpecType == EST_Dynamic) {
+ EPI.NumExceptions = size();
+ EPI.Exceptions = data();
+ } else if (EPI.ExceptionSpecType == EST_None) {
+ /// C++11 [except.spec]p14:
+ /// The exception-specification is noexcept(false) if the set of
+ /// potential exceptions of the special member function contains "any"
+ EPI.ExceptionSpecType = EST_ComputedNoexcept;
+ EPI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(),
+ tok::kw_false).take();
+ }
}
FunctionProtoType::ExtProtoInfo getEPI() const {
FunctionProtoType::ExtProtoInfo EPI;
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 81745c6..5f43fbc 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -977,6 +977,16 @@
setFlag("const", T->isConst());
setFlag("volatile", T->isVolatile());
setFlag("restrict", T->isRestrict());
+ switch (T->getExceptionSpecType()) {
+ case EST_None: break;
+ case EST_DynamicNone: set("exception_spec", "throw()"); break;
+ case EST_Dynamic: set("exception_spec", "throw(T)"); break;
+ case EST_MSAny: set("exception_spec", "throw(...)"); break;
+ case EST_BasicNoexcept: set("exception_spec", "noexcept"); break;
+ case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break;
+ case EST_Unevaluated: set("exception_spec", "unevaluated"); break;
+ case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break;
+ }
}
void visitFunctionProtoTypeChildren(FunctionProtoType *T) {
push("parameters");
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index 4f50afb..ff21ab8 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -63,3 +63,41 @@
static_assert(!noexcept(X(X::val())), "");
static_assert(!noexcept(X::ref() = X::val()), "");
}
+
+namespace PR14141 {
+ // Part of DR1351: the implicit exception-specification is noexcept(false) if
+ // the set of potential exceptions of the special member function contains
+ // "any". Hence it is compatible with noexcept(false).
+ struct ThrowingBase {
+ ThrowingBase() noexcept(false);
+ ThrowingBase(const ThrowingBase&) noexcept(false);
+ ThrowingBase(ThrowingBase&&) noexcept(false);
+ ThrowingBase &operator=(const ThrowingBase&) noexcept(false);
+ ThrowingBase &operator=(ThrowingBase&&) noexcept(false);
+ ~ThrowingBase() noexcept(false);
+ };
+ struct Derived : ThrowingBase {
+ Derived() noexcept(false) = default;
+ Derived(const Derived&) noexcept(false) = default;
+ Derived(Derived&&) noexcept(false) = default;
+ Derived &operator=(const Derived&) noexcept(false) = default;
+ Derived &operator=(Derived&&) noexcept(false) = default;
+ ~Derived() noexcept(false) = default;
+ };
+ struct Derived2 : ThrowingBase {
+ Derived2() = default;
+ Derived2(const Derived2&) = default;
+ Derived2(Derived2&&) = default;
+ Derived2 &operator=(const Derived2&) = default;
+ Derived2 &operator=(Derived2&&) = default;
+ ~Derived2() = default;
+ };
+ struct Derived3 : ThrowingBase {
+ Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3(const Derived3&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3(Derived3&&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3 &operator=(const Derived3&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3 &operator=(Derived3&&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ ~Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
+ };
+}