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