aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/cp-tree.h10
-rw-r--r--gcc/cp/method.c25
-rw-r--r--gcc/cp/pt.c54
-rw-r--r--gcc/cp/typeck.c6
-rw-r--r--gcc/cp/typeck2.c76
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/noexcept13.C78
8 files changed, 204 insertions, 59 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 01a596f..88bb8fb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,15 @@
2011-06-14 Jason Merrill <jason@redhat.com>
+ 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 06b5926..ff8b2dc 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 06e20e2..48b9c74 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 5f53ce8..ff145a26 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 1bed291..39e974b 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 d72f57e..6d6267e 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 cecd85b..265f95d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2011-06-14 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/noexcept13.C: New.
+
2011-06-14 Easwaran Raman <eraman@google.com>
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 0000000..7d51c82
--- /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<typename _Tp> _Tp&& declval() noexcept;
+
+ struct true_type { static const bool value = true; };
+ struct false_type { static const bool value = false; };
+
+ template<typename _Tp, typename _Arg>
+ struct __is_direct_constructible_impl
+ {
+ template<typename _Tp2, typename _Arg2, typename
+ = decltype(::new _Tp2(declval<_Arg2>()))>
+ static true_type __test(int);
+
+ template<typename, typename>
+ static false_type __test(...);
+
+ typedef decltype(__test<_Tp, _Arg>(0)) type;
+ };
+
+ template<typename _Tp, typename _Arg>
+ struct __is_direct_constructible_new_safe
+ : public __is_direct_constructible_impl<_Tp, _Arg>::type
+ { };
+
+ template<class _T1, class _T2>
+ struct pair
+ {
+ pair() = default;
+ constexpr pair(const pair&) = default;
+
+ pair(pair&& __p)
+ noexcept(__is_direct_constructible_new_safe<_T2,_T2&&>::value);
+ };
+}
+
+template <class R_>
+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<int, Vector_3> x;
+};
+
+template < class R_ > class RayH3
+{
+ typedef typename R_::Vector_3 Vector_3;
+ std::pair<int, Vector_3> x;
+};
+
+template <typename Kernel >
+struct Homogeneous_base
+{
+ typedef LineC3<Kernel> Line_3;
+ typedef RayH3<Kernel> Ray_3;
+};
+
+template < typename RT_>
+struct Simple_homogeneous
+: public Homogeneous_base< Simple_homogeneous<RT_> >
+{
+ typedef Vector3<Simple_homogeneous<RT_> > Vector_3;
+};
+
+int main()
+{
+ typedef Simple_homogeneous<double> R;
+ R::Line_3 l3;
+}