Commit b273cdb1 by Jason Merrill Committed by Jason Merrill

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
parent f1608bfc
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.
......
......@@ -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);
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
......@@ -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;
}
......
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
......
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment