From patchwork Fri May 20 20:39:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 96667 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E8B24B719E for ; Sat, 21 May 2011 06:39:31 +1000 (EST) Received: (qmail 14385 invoked by alias); 20 May 2011 20:39:30 -0000 Received: (qmail 14377 invoked by uid 22791); 20 May 2011 20:39:29 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 20 May 2011 20:39:15 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p4KKdFpu011989 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 20 May 2011 16:39:15 -0400 Received: from [127.0.0.1] (ovpn-113-120.phx2.redhat.com [10.3.113.120]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p4KKdFcg003164 for ; Fri, 20 May 2011 16:39:15 -0400 Message-ID: <4DD6D172.7050500@redhat.com> Date: Fri, 20 May 2011 16:39:14 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b2 Thunderbird/3.1.10 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/49082 (wrong merging of noexcept(false)) and DR 1073 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org In my earlier change to support noexcept in merge_exception_specifiers, I failed to consider the case of combining noexcept(false) with noexcept(true) in the context of implicitly declared member functions; that combination needs to result in noexcept(false), not noexcept(true). While I was looking at this I also implemented DR 1073, which dropped compatibility between noexcept(false) and a dynamic-exception-specification. Tested x86_64-pc-linux-gnu, applying to trunk. commit a69bb0ad268ae28dd1a15617d733b4d9cf10f493 Author: Jason Merrill Date: Fri May 20 15:34:15 2011 -0400 DR 1073 PR c++/49082 * typeck.c (comp_except_specs): noexcept(false) is not compatible with throw(type-list). * typeck2.c (merge_exception_specifiers): noexcept(false) beats any more limited specification. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d98c62b..7791efc 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -986,14 +986,14 @@ comp_except_specs (const_tree t1, const_tree t2, int exact) /* First handle noexcept. */ if (exact < ce_exact) { - /* noexcept(false) is compatible with any throwing dynamic-exc-spec + /* noexcept(false) is compatible with no exception-specification, and stricter than any spec. */ if (t1 == noexcept_false_spec) - return !nothrow_spec_p (t2) || exact == ce_derived; - /* Even a derived noexcept(false) is compatible with a throwing - dynamic spec. */ + return t2 == NULL_TREE || exact == ce_derived; + /* Even a derived noexcept(false) is compatible with no + exception-specification. */ if (t2 == noexcept_false_spec) - return !nothrow_spec_p (t1); + return t1 == NULL_TREE; /* Otherwise, if we aren't looking for an exact match, noexcept is equivalent to throw(). */ diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 26b9816..c2eff9e 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1756,10 +1756,13 @@ add_exception_specifier (tree list, tree spec, int complain) tree merge_exception_specifiers (tree list, tree add) { - if (!list || !add) - return NULL_TREE; + /* No exception-specifier or noexcept(false) are less strict than + anything else. Prefer the newer variant (LIST). */ + if (!list || list == noexcept_false_spec) + return list; + else if (!add || add == noexcept_false_spec) + return add; /* For merging noexcept(true) and throw(), take the more recent one (LIST). - A throw(type-list) spec takes precedence over a noexcept(false) spec. Any other noexcept-spec should only be merged with an equivalent one. So the !TREE_VALUE code below is correct for all cases. */ else if (!TREE_VALUE (add)) diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept02.C b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C index 60015e7..ffbb091 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept02.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C @@ -10,9 +10,9 @@ void f(); SA(!noexcept(f())); -void g() throw (int); -void g() noexcept(false); // { dg-error "previous declaration" } -void g(); // { dg-error "different exception" } +void g() throw (int); // { dg-error "previous declaration" } +void g() noexcept(false); // { dg-error "different exception" } +void g(); void h() throw(); void h() noexcept; diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept03.C b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C index c759f6f..54e04f3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept03.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C @@ -36,19 +36,6 @@ void f2(T a) noexcept (noexcept (f (a))) struct A { A() { } }; // { dg-warning "does not throw" } -// throw(int) overrides noexcept(false) in either order. -void h() throw (int, std::bad_exception); -void h() noexcept (false) -{ - throw 1.0; -} - -void i() noexcept (false); -void i() throw (int, std::bad_exception) -{ - throw 1.0; -} - int main() { // noexcept(false) allows throw. @@ -57,10 +44,6 @@ int main() try { f(A()); } catch (int) { } try { f2(A()); } catch (int) { } - std::set_unexpected (my_unexpected); - try { h(); } catch (std::bad_exception) { } - try { i(); } catch (std::bad_exception) { } - std::set_terminate (my_terminate); // noexcept(noexcept(int())) == noexcept(true). try { f2(1); } catch (...) { } diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept08.C b/gcc/testsuite/g++.dg/cpp0x/noexcept08.C index c450332..1df85ef 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept08.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept08.C @@ -34,7 +34,7 @@ struct D: A void g() noexcept(false); // { dg-error "looser" } void h() noexcept(false); // { dg-error "looser" } void i() noexcept(false); - void j() noexcept(false); // compatible; treated as throw(int) + void j() noexcept(false); // { dg-error "looser" } }; struct E: A diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept10.C b/gcc/testsuite/g++.dg/cpp0x/noexcept10.C new file mode 100644 index 0000000..058a387 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept10.C @@ -0,0 +1,27 @@ +// PR c++/49082 +// { dg-options -std=c++0x } + +namespace std { template T&& declval() noexcept; } + +struct Base +{ + Base(const Base&) noexcept(false); + Base(Base&&) noexcept(false); + ~Base() noexcept(false); +}; + +struct Derived +: Base +{ + // Derived(const Derived&) = default; + // Derived(Derived&&) = default; +}; + +static_assert(!noexcept(Base(std::declval())), "Error"); +static_assert(!noexcept(Derived(std::declval())), "Error"); // Error + +static_assert(!noexcept(Base(std::declval())), "Error"); +static_assert(!noexcept(Derived(std::declval())), "Error"); // Error + +static_assert(!noexcept(std::declval().~Base()), "Error"); // OK +static_assert(!noexcept(std::declval().~Derived()), "Error"); // Error