Hi,
On 06/28/2013 02:52 AM, Jason Merrill wrote:
On 06/19/2013 08:22 PM, Paolo Carlini wrote:
If, in check_bases_and_members, I simply move
deduce_noexcept_on_destructors after check_methods and nothing else, all
the new testcases are fine + the tests added for Core/1123, but there
are regressions, for example for testcases involving virtual
destructors, eg, debug/dwarf2/non-virtual-thunk.C.
Probably because we need to update the exception specification before
we check for overrides, since that check will look at the exception
specification.
Let's move
if (DECL_DESTRUCTOR_P (x) && user_provided_p (x))
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
to the top of the loop in check_methods, and call
deduce_noexcept_on_destructor under the same if.
Thanks. If I do that, noexcept21.C is fine but there are regressions, of
the same kind, for two testcases which by now I know well:
cpp0x/defaulted33.C and defaulted38.C. For example:
defaulted33.C: In instantiation of ‘class ArrayNHD<int, 1u>’:
defaulted33.C:31:10: required from here
defaulted33.C:22:3: error: looser throw specifier for ‘ArrayNHD<T,
N>::~ArrayNHD() [with T = int; unsigned int N = 1u]’
~ArrayNHD() = default;
^
defaulted33.C:15:7: error: overriding ‘virtual IOHD::~IOHD() noexcept
(true)’
class IOHD : public InputHD, public OutputHD
^
Note that check_for_override itself does set
TYPE_HAS_NONTRIVIAL_DESTRUCTOR, when it sees virtual destructors. If I
hack the if above to something like:
if (DECL_DESTRUCTOR_P (x)
&& (user_provided_p (x) || DECL_VIRTUAL_P (x))
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
then defaulted38.C doesn't regress anymore. However defaulted33.C still
fails, it has a base class with a virtual destructor but then the
derived class has simply ~ArrayNHD() = default; Should we detect this
latter case too?
Finally, I must admit that I'm a little confused about the real meaning
of TYPE_HAS_NONTRIVIAL_DESTRUCTOR, which is also the very predicate that
we use for the semantics of __has_trivial_destructor. It looks like that
in some cases we *cannot* set it to its final value *before* having
called deduce_noexcept_on_destructor. Consider:
#define SA(X) static_assert ((X), #X)
struct Thrower
{
~Thrower() noexcept(false);
};
struct C
{
// Thrower t;
~C() = default;
};
SA(__has_trivial_destructor(C));
If you like, this is the rationale behind my last patch: save its
current value, set it only to force a thorough
deduce_noexcept_on_destructor on everything (admittedly, I don't
understand all the details of this), and then restore it, don't fiddle
at this stage with the code we have got setting it to its final value.
Did I explain this well enough?
Thanks,
Paolo.