From patchwork Tue Jun 22 04:26:58 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: C++0x PATCH to comparison of noexcept specifications Date: Mon, 21 Jun 2010 18:26:58 -0000 From: Jason Merrill X-Patchwork-Id: 56397 Message-Id: <4C203B92.8060401@redhat.com> To: gcc-patches List While working on implicit move constructors, I've been running the testsuite with -std=gnu++0x, which turned up a bug whereby overriding a base method which can throw any exception with a derived method which is noexcept was giving an error about a looser exception spec. Fixed thus. Tested x86_64-pc-linux-gnu, applied to trunk. commit cc07b6735584fe5ee4f692c05d7a0a6abe1a4dbd Author: Jason Merrill Date: Mon Jun 21 22:04:14 2010 -0400 * typeck.c (comp_except_specs): Fix ce_derived with noexcept. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index beef388..4383ef5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -993,35 +993,37 @@ comp_except_specs (const_tree t1, const_tree t2, int exact) const_tree probe; const_tree base; int length = 0; - const_tree noexcept_spec = NULL_TREE; - const_tree other_spec; if (t1 == t2) return true; - /* First test noexcept compatibility. */ - if (t1 && TREE_PURPOSE (t1)) - noexcept_spec = t1, other_spec = t2; - else if (t2 && TREE_PURPOSE (t2)) - noexcept_spec = t2, other_spec = t1; - if (noexcept_spec) - { - tree p = TREE_PURPOSE (noexcept_spec); - /* Two noexcept-specs are equivalent iff their exprs are. */ - if (other_spec && TREE_PURPOSE (other_spec)) - return cp_tree_equal (p, TREE_PURPOSE (other_spec)); - /* noexcept(true) is compatible with throw(). */ - else if (exact < ce_exact && p == boolean_true_node) - return nothrow_spec_p (other_spec); - /* noexcept(false) is compatible with any throwing - dynamic-exception-spec. */ - else if (exact < ce_exact && p == boolean_false_node) - return !nothrow_spec_p (other_spec); - /* A dependent noexcept-spec is not compatible with any - dynamic-exception-spec. */ - else - return false; - } + /* First handle noexcept. */ + if (exact < ce_exact) + { + /* noexcept(false) is compatible with any throwing dynamic-exc-spec + 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. */ + if (t2 == noexcept_false_spec) + return !nothrow_spec_p (t1); + + /* Otherwise, if we aren't looking for an exact match, noexcept is + equivalent to throw(). */ + if (t1 == noexcept_true_spec) + t1 = empty_except_spec; + if (t2 == noexcept_true_spec) + t2 = empty_except_spec; + } + + /* If any noexcept is left, it is only comparable to itself; + either we're looking for an exact match or we're redeclaring a + template with dependent noexcept. */ + if ((t1 && TREE_PURPOSE (t1)) + || (t2 && TREE_PURPOSE (t2))) + return (t1 && t2 + && cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))); if (t1 == NULL_TREE) /* T1 is ... */ return t2 == NULL_TREE || exact == ce_derived; diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept08.C b/gcc/testsuite/g++.dg/cpp0x/noexcept08.C new file mode 100644 index 0000000..c450332 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept08.C @@ -0,0 +1,56 @@ +// { dg-options "-std=c++0x" } +// { dg-prune-output "overriding" } + +struct A +{ + virtual void f(); + virtual void g() throw(); + virtual void h() noexcept; + virtual void i() noexcept(false); + virtual void j() throw(int); +}; + +struct B: A +{ + void f() noexcept; + void g() noexcept; + void h() noexcept; + void i() noexcept; + void j() noexcept; +}; + +struct C: A +{ + void f() throw(); + void g() throw(); + void h() throw(); + void i() throw(); + void j() throw(); +}; + +struct D: A +{ + void f() noexcept(false); + 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) +}; + +struct E: A +{ + void f() throw(int); + void g() throw(int); // { dg-error "looser" } + void h() throw(int); // { dg-error "looser" } + void i() throw(int); + void j() throw(int); +}; + +struct F: A +{ + void f(); + void g(); // { dg-error "looser" } + void h(); // { dg-error "looser" } + void i(); + void j(); // { dg-error "looser" } +};