From b273cdb17474d4d221fda93c6c9936bfd7d0a6ae Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 14 Jun 2011 23:51:59 -0400 Subject: [PATCH] re PR c++/49107 ([C++0x][4.7 Regression] incomplete type regression with std::pair) PR c++/49107 * cp-tree.h (DEFERRED_NOEXCEPT_SPEC_P): Handle overload. * method.c (defaulted_late_check): Only maybe_instantiate_noexcept if the declaration had an exception-specifier. (process_subob_fn): Don't maybe_instantiate_noexcept. * pt.c (maybe_instantiate_noexcept): Handle overload. * typeck2.c (nothrow_spec_p_uninst): New. (merge_exception_specifiers): Add 'fn' parm. Build up overload. * typeck.c (merge_types): Adjust. From-SVN: r175073 --- gcc/cp/ChangeLog | 10 ++++ gcc/cp/cp-tree.h | 10 +++- gcc/cp/method.c | 25 ++++---- gcc/cp/pt.c | 54 ++++++++++++----- gcc/cp/typeck.c | 6 +- gcc/cp/typeck2.c | 76 ++++++++++++++++-------- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/cpp0x/noexcept13.C | 78 +++++++++++++++++++++++++ 8 files changed, 204 insertions(+), 59 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept13.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 01a596fd060..88bb8fb35a0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,15 @@ 2011-06-14 Jason Merrill + PR c++/49107 + * cp-tree.h (DEFERRED_NOEXCEPT_SPEC_P): Handle overload. + * method.c (defaulted_late_check): Only maybe_instantiate_noexcept + if the declaration had an exception-specifier. + (process_subob_fn): Don't maybe_instantiate_noexcept. + * pt.c (maybe_instantiate_noexcept): Handle overload. + * typeck2.c (nothrow_spec_p_uninst): New. + (merge_exception_specifiers): Add 'fn' parm. Build up overload. + * typeck.c (merge_types): Adjust. + * pt.c (deduction_tsubst_fntype): Don't save input_location. (maybe_instantiate_noexcept): Likewise. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 06b5926faa8..ff8b2dc121e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -514,7 +514,8 @@ struct GTY (()) tree_default_arg { (((struct tree_deferred_noexcept *)DEFERRED_NOEXCEPT_CHECK (NODE))->args) #define DEFERRED_NOEXCEPT_SPEC_P(NODE) \ ((NODE) && (TREE_PURPOSE (NODE)) \ - && TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT) + && (TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT \ + || is_overloaded_fn (TREE_PURPOSE (NODE)))) struct GTY (()) tree_deferred_noexcept { struct tree_base base; @@ -1792,7 +1793,10 @@ struct GTY((variable_size)) lang_type { this type can raise. Each TREE_VALUE is a _TYPE. The TREE_VALUE will be NULL_TREE to indicate a throw specification of `()', or no exceptions allowed. For a noexcept specification, TREE_VALUE - is NULL_TREE and TREE_PURPOSE is the constant-expression. */ + is NULL_TREE and TREE_PURPOSE is the constant-expression. For + a deferred noexcept-specification, TREE_PURPOSE is a DEFERRED_NOEXCEPT + (for templates) or an OVERLOAD list of functions (for implicitly + declared functions). */ #define TYPE_RAISES_EXCEPTIONS(NODE) TYPE_LANG_SLOT_1 (NODE) /* For FUNCTION_TYPE or METHOD_TYPE, return 1 iff it is declared `throw()' @@ -5698,7 +5702,7 @@ extern tree build_x_arrow (tree); extern tree build_m_component_ref (tree, tree); extern tree build_functional_cast (tree, tree, tsubst_flags_t); extern tree add_exception_specifier (tree, tree, int); -extern tree merge_exception_specifiers (tree, tree); +extern tree merge_exception_specifiers (tree, tree, tree); /* in mangle.c */ extern void init_mangle (void); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 06e20e27175..48b9c74e78e 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -924,10 +924,8 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, if (spec_p) { - tree raises; - maybe_instantiate_noexcept (fn); - raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); - *spec_p = merge_exception_specifiers (*spec_p, raises); + tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); + *spec_p = merge_exception_specifiers (*spec_p, raises, fn); } if (!trivial_fn_p (fn)) @@ -1561,15 +1559,16 @@ defaulted_late_check (tree fn) it had been implicitly declared. */ if (DECL_DEFAULTED_IN_CLASS_P (fn)) { - tree eh_spec; - maybe_instantiate_noexcept (fn); - eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn)); - if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)) - && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)), - eh_spec, ce_normal)) - error ("function %q+D defaulted on its first declaration " - "with an exception-specification that differs from " - "the implicit declaration %q#D", fn, implicit_fn); + tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn)); + if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) + { + maybe_instantiate_noexcept (fn); + if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)), + eh_spec, ce_normal)) + error ("function %q+D defaulted on its first declaration " + "with an exception-specification that differs from " + "the implicit declaration %q#D", fn, implicit_fn); + } TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec); if (DECL_DECLARED_CONSTEXPR_P (implicit_fn)) /* Hmm...should we do this for out-of-class too? Should it be OK to diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5f53ce88cfc..ff145a263fd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17354,27 +17354,49 @@ always_instantiate_p (tree decl) void maybe_instantiate_noexcept (tree fn) { - tree fntype = TREE_TYPE (fn); - tree spec = TYPE_RAISES_EXCEPTIONS (fntype); - tree noex = NULL_TREE; - tree clone; + tree fntype, spec, noex, clone; + + if (DECL_CLONED_FUNCTION_P (fn)) + fn = DECL_CLONED_FUNCTION (fn); + fntype = TREE_TYPE (fn); + spec = TYPE_RAISES_EXCEPTIONS (fntype); if (!DEFERRED_NOEXCEPT_SPEC_P (spec)) return; + noex = TREE_PURPOSE (spec); - push_tinst_level (fn); - push_access_scope (fn); - input_location = DECL_SOURCE_LOCATION (fn); - noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex), - DEFERRED_NOEXCEPT_ARGS (noex), - tf_warning_or_error, fn, /*function_p=*/false, - /*integral_constant_expression_p=*/true); - pop_access_scope (fn); - pop_tinst_level (); - spec = build_noexcept_spec (noex, tf_warning_or_error); - if (spec == error_mark_node) - spec = noexcept_false_spec; + if (TREE_CODE (noex) == DEFERRED_NOEXCEPT) + { + push_tinst_level (fn); + push_access_scope (fn); + input_location = DECL_SOURCE_LOCATION (fn); + noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex), + DEFERRED_NOEXCEPT_ARGS (noex), + tf_warning_or_error, fn, /*function_p=*/false, + /*integral_constant_expression_p=*/true); + pop_access_scope (fn); + pop_tinst_level (); + spec = build_noexcept_spec (noex, tf_warning_or_error); + if (spec == error_mark_node) + spec = noexcept_false_spec; + } + else + { + /* This is an implicitly declared function, so NOEX is a list of + other functions to evaluate and merge. */ + tree elt; + spec = noexcept_true_spec; + for (elt = noex; elt; elt = OVL_NEXT (elt)) + { + tree fn = OVL_CURRENT (elt); + tree subspec; + maybe_instantiate_noexcept (fn); + subspec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); + spec = merge_exception_specifiers (spec, subspec, NULL_TREE); + } + } + TREE_TYPE (fn) = build_exception_variant (fntype, spec); FOR_EACH_CLONE (clone, fn) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 1bed291617e..39e974bb802 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -830,7 +830,8 @@ merge_types (tree t1, tree t2) gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2)); rval = apply_memfn_quals (rval, type_memfn_quals (t1)); raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1), - TYPE_RAISES_EXCEPTIONS (t2)); + TYPE_RAISES_EXCEPTIONS (t2), + NULL_TREE); t1 = build_exception_variant (rval, raises); break; } @@ -841,7 +842,8 @@ merge_types (tree t1, tree t2) is just the main variant of this. */ tree basetype = class_of_this_parm (t2); tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1), - TYPE_RAISES_EXCEPTIONS (t2)); + TYPE_RAISES_EXCEPTIONS (t2), + NULL_TREE); tree t3; /* If this was a member function type, get back to the diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index d72f57ec937..6d6267e8d72 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1771,12 +1771,24 @@ add_exception_specifier (tree list, tree spec, int complain) return list; } +/* Like nothrow_spec_p, but don't abort on deferred noexcept. */ + +static bool +nothrow_spec_p_uninst (const_tree spec) +{ + if (DEFERRED_NOEXCEPT_SPEC_P (spec)) + return false; + return nothrow_spec_p (spec); +} + /* Combine the two exceptions specifier lists LIST and ADD, and return - their union. */ + their union. If FN is non-null, it's the source of ADD. */ tree -merge_exception_specifiers (tree list, tree add) +merge_exception_specifiers (tree list, tree add, tree fn) { + tree noex, orig_list; + /* No exception-specifier or noexcept(false) are less strict than anything else. Prefer the newer variant (LIST). */ if (!list || list == noexcept_false_spec) @@ -1784,37 +1796,51 @@ merge_exception_specifiers (tree list, tree add) else if (!add || add == noexcept_false_spec) return add; - /* We need to instantiate deferred noexcept before we get here. */ - gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (list) - && !DEFERRED_NOEXCEPT_SPEC_P (add)); - - /* For merging noexcept(true) and throw(), take the more recent one (LIST). - Any other noexcept-spec should only be merged with an equivalent one. - So the !TREE_VALUE code below is correct for all cases. */ - if (!TREE_VALUE (add)) + /* noexcept(true) and throw() are stricter than anything else. + As above, prefer the more recent one (LIST). */ + if (nothrow_spec_p_uninst (add)) return list; - else if (!TREE_VALUE (list)) + + noex = TREE_PURPOSE (list); + if (DEFERRED_NOEXCEPT_SPEC_P (add)) + { + /* If ADD is a deferred noexcept, we must have been called from + process_subob_fn. For implicitly declared functions, we build up + a list of functions to consider at instantiation time. */ + if (noex == boolean_true_node) + noex = NULL_TREE; + gcc_assert (fn && (!noex || is_overloaded_fn (noex))); + noex = build_overload (fn, noex); + } + else if (nothrow_spec_p_uninst (list)) return add; else + gcc_checking_assert (!TREE_PURPOSE (add) + || cp_tree_equal (noex, TREE_PURPOSE (add))); + + /* Combine the dynamic-exception-specifiers, if any. */ + orig_list = list; + for (; add && TREE_VALUE (add); add = TREE_CHAIN (add)) { - tree orig_list = list; + tree spec = TREE_VALUE (add); + tree probe; - for (; add; add = TREE_CHAIN (add)) + for (probe = orig_list; probe && TREE_VALUE (probe); + probe = TREE_CHAIN (probe)) + if (same_type_p (TREE_VALUE (probe), spec)) + break; + if (!probe) { - tree spec = TREE_VALUE (add); - tree probe; - - for (probe = orig_list; probe; probe = TREE_CHAIN (probe)) - if (same_type_p (TREE_VALUE (probe), spec)) - break; - if (!probe) - { - spec = build_tree_list (NULL_TREE, spec); - TREE_CHAIN (spec) = list; - list = spec; - } + spec = build_tree_list (NULL_TREE, spec); + TREE_CHAIN (spec) = list; + list = spec; } } + + /* Keep the noexcept-specifier at the beginning of the list. */ + if (noex != TREE_PURPOSE (list)) + list = tree_cons (noex, TREE_VALUE (list), TREE_CHAIN (list)); + return list; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cecd85bc3f4..265f95daf71 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-06-14 Jason Merrill + + * g++.dg/cpp0x/noexcept13.C: New. + 2011-06-14 Easwaran Raman PR rtl-optimization/44194 diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept13.C b/gcc/testsuite/g++.dg/cpp0x/noexcept13.C new file mode 100644 index 00000000000..7d51c82b549 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept13.C @@ -0,0 +1,78 @@ +// PR c++/49107 +// { dg-options -std=c++0x } + +namespace std +{ + template _Tp&& declval() noexcept; + + struct true_type { static const bool value = true; }; + struct false_type { static const bool value = false; }; + + template + struct __is_direct_constructible_impl + { + template()))> + static true_type __test(int); + + template + static false_type __test(...); + + typedef decltype(__test<_Tp, _Arg>(0)) type; + }; + + template + struct __is_direct_constructible_new_safe + : public __is_direct_constructible_impl<_Tp, _Arg>::type + { }; + + template + struct pair + { + pair() = default; + constexpr pair(const pair&) = default; + + pair(pair&& __p) + noexcept(__is_direct_constructible_new_safe<_T2,_T2&&>::value); + }; +} + +template +struct Vector3 +{ + typedef typename R_::Ray_3 Ray_3; + Vector3() {} + explicit Vector3(const Ray_3& r); +}; + +template < class R_ > class LineC3 +{ + typedef typename R_::Vector_3 Vector_3; + std::pair x; +}; + +template < class R_ > class RayH3 +{ + typedef typename R_::Vector_3 Vector_3; + std::pair x; +}; + +template +struct Homogeneous_base +{ + typedef LineC3 Line_3; + typedef RayH3 Ray_3; +}; + +template < typename RT_> +struct Simple_homogeneous +: public Homogeneous_base< Simple_homogeneous > +{ + typedef Vector3 > Vector_3; +}; + +int main() +{ + typedef Simple_homogeneous R; + R::Line_3 l3; +} -- 2.30.2