From: Richard Smith Date: Sun, 21 Oct 2012 23:00:34 +0000 (+0000) Subject: PR14141 (part of DR1351): An implicitly-deduced "any" exception specification X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=03e6fda61f48a6f11fb3c9459d5ac3d5b1db2809;p=clang 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 df9433e0db..ecbcbb00fb 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3376,18 +3376,11 @@ public: // 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 ExceptionsSeen; SmallVector Exceptions; @@ -3427,8 +3420,17 @@ public: /// 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 81745c614c..5f43fbc251 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -977,6 +977,16 @@ struct XMLDumper : public XMLDeclVisitor, 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 4f50afb548..ff21ab8e56 100644 --- a/test/CXX/except/except.spec/p14.cpp +++ b/test/CXX/except/except.spec/p14.cpp @@ -63,3 +63,41 @@ namespace PR13381 { 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}} + }; +}