re PR c++/49107 ([C++0x][4.7 Regression] incomplete type regression with std::pair)

PR c++/49107
	* cp-tree.def (DEFERRED_NOEXCEPT): New.
	* cp-tree.h (struct tree_deferred_noexcept): New.
	(DEFERRED_NOEXCEPT_PATTERN, DEFERRED_NOEXCEPT_ARGS): New.
	(DEFERRED_NOEXCEPT_SPEC_P): New.
	(enum cp_tree_node_structure_enum): Add TS_CP_DEFERRED_NOEXCEPT.
	(union lang_tree_node): Add tree_deferred_noexcept.
	(maybe_instantiate_noexcept): Declare.
	* cp-objcp-common.c (cp_tree_size): Handle DEFERRED_NOEXCEPT.
	* error.c (dump_exception_spec): Likewise.
	* cxx-pretty-print.c (pp_cxx_exception_specification): Likewise.
	* ptree.c (cxx_print_xnode): Likewise.
	* tree.c (cp_tree_equal): Likewise.
	* decl.c (cp_tree_node_structure): Likewise.
	(duplicate_decls): Call maybe_instantiate_noexcept.
	* except.c (build_noexcept_spec): Handle DEFERRED_NOEXCEPT.
	(nothrow_spec_p, type_noexcept_p, type_throw_all_p): Check
	DEFERRED_NOEXCEPT_SPEC_P.
	* typeck2.c (merge_exception_specifiers): Likewise.
	* decl2.c (mark_used): Call maybe_instantiate_noexcept.
	* method.c (process_subob_fn, defaulted_late_check): Likewise.
	* pt.c (tsubst_exception_specification): Add defer_ok parm.
	Build DEFERRED_NOEXCEPT.
	(maybe_instantiate_noexcept): New.
	(tsubst, regenerate_decl_from_template, instantiate_decl): Adjust.
	* search.c (check_final_overrider): Call maybe_instantiate_noexcept.

From-SVN: r174820
This commit is contained in:
Jason Merrill 2011-06-08 17:35:02 -04:00 committed by Jason Merrill
parent 535fb6eb20
commit 1026172832
19 changed files with 253 additions and 20 deletions

View File

@ -1,5 +1,32 @@
2011-06-08 Jason Merrill <jason@redhat.com>
PR c++/49107
* cp-tree.def (DEFERRED_NOEXCEPT): New.
* cp-tree.h (struct tree_deferred_noexcept): New.
(DEFERRED_NOEXCEPT_PATTERN, DEFERRED_NOEXCEPT_ARGS): New.
(DEFERRED_NOEXCEPT_SPEC_P): New.
(enum cp_tree_node_structure_enum): Add TS_CP_DEFERRED_NOEXCEPT.
(union lang_tree_node): Add tree_deferred_noexcept.
(maybe_instantiate_noexcept): Declare.
* cp-objcp-common.c (cp_tree_size): Handle DEFERRED_NOEXCEPT.
* error.c (dump_exception_spec): Likewise.
* cxx-pretty-print.c (pp_cxx_exception_specification): Likewise.
* ptree.c (cxx_print_xnode): Likewise.
* tree.c (cp_tree_equal): Likewise.
* decl.c (cp_tree_node_structure): Likewise.
(duplicate_decls): Call maybe_instantiate_noexcept.
* except.c (build_noexcept_spec): Handle DEFERRED_NOEXCEPT.
(nothrow_spec_p, type_noexcept_p, type_throw_all_p): Check
DEFERRED_NOEXCEPT_SPEC_P.
* typeck2.c (merge_exception_specifiers): Likewise.
* decl2.c (mark_used): Call maybe_instantiate_noexcept.
* method.c (process_subob_fn, defaulted_late_check): Likewise.
* pt.c (tsubst_exception_specification): Add defer_ok parm.
Build DEFERRED_NOEXCEPT.
(maybe_instantiate_noexcept): New.
(tsubst, regenerate_decl_from_template, instantiate_decl): Adjust.
* search.c (check_final_overrider): Call maybe_instantiate_noexcept.
* semantics.c (potential_constant_expression_1): Handle destructor
call.

View File

@ -79,6 +79,7 @@ cp_tree_size (enum tree_code code)
case BASELINK: return sizeof (struct tree_baselink);
case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index);
case DEFAULT_ARG: return sizeof (struct tree_default_arg);
case DEFERRED_NOEXCEPT: return sizeof (struct tree_deferred_noexcept);
case OVERLOAD: return sizeof (struct tree_overload);
case STATIC_ASSERT: return sizeof (struct tree_static_assert);
case TYPE_ARGUMENT_PACK:

View File

@ -214,6 +214,11 @@ DEFTREECODE (USING_STMT, "using_directive", tcc_statement, 1)
parsing had occurred. */
DEFTREECODE (DEFAULT_ARG, "default_arg", tcc_exceptional, 0)
/* An uninstantiated noexcept-specification. DEFERRED_NOEXCEPT_PATTERN is
the pattern from the template, and DEFERRED_NOEXCEPT_ARGS are the
template arguments to substitute into the pattern when needed. */
DEFTREECODE (DEFERRED_NOEXCEPT, "deferred_noexcept", tcc_exceptional, 0)
/* A template-id, like foo<int>. The first operand is the template.
The second is NULL if there are no explicit arguments, or a
TREE_VEC of arguments. The template will be a FUNCTION_DECL,

View File

@ -507,6 +507,22 @@ struct GTY (()) tree_default_arg {
VEC(tree,gc) *instantiations;
};
#define DEFERRED_NOEXCEPT_PATTERN(NODE) \
(((struct tree_deferred_noexcept *)DEFERRED_NOEXCEPT_CHECK (NODE))->pattern)
#define DEFERRED_NOEXCEPT_ARGS(NODE) \
(((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)
struct GTY (()) tree_deferred_noexcept {
struct tree_base base;
tree pattern;
tree args;
};
/* The condition associated with the static assertion. This must be
an integral constant expression. */
#define STATIC_ASSERT_CONDITION(NODE) \
@ -693,6 +709,7 @@ enum cp_tree_node_structure_enum {
TS_CP_BASELINK,
TS_CP_WRAPPER,
TS_CP_DEFAULT_ARG,
TS_CP_DEFERRED_NOEXCEPT,
TS_CP_STATIC_ASSERT,
TS_CP_ARGUMENT_PACK_SELECT,
TS_CP_TRAIT_EXPR,
@ -711,6 +728,7 @@ union GTY((desc ("cp_tree_node_structure (&%h)"),
struct tree_overload GTY ((tag ("TS_CP_OVERLOAD"))) overload;
struct tree_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink;
struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg;
struct tree_deferred_noexcept GTY ((tag ("TS_CP_DEFERRED_NOEXCEPT"))) deferred_noexcept;
struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT")))
static_assertion;
@ -5130,6 +5148,7 @@ extern int more_specialized_fn (tree, tree, int);
extern void do_decl_instantiation (tree, tree);
extern void do_type_instantiation (tree, tree, tsubst_flags_t);
extern bool always_instantiate_p (tree);
extern void maybe_instantiate_noexcept (tree);
extern tree instantiate_decl (tree, int, bool);
extern int comp_template_parms (const_tree, const_tree);
extern bool uses_parameter_packs (tree);

View File

@ -1446,7 +1446,10 @@ pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t)
pp_cxx_ws_string (pp, "noexcept");
pp_cxx_whitespace (pp);
pp_cxx_left_paren (pp);
pp_cxx_expression (pp, TREE_PURPOSE (ex_spec));
if (DEFERRED_NOEXCEPT_SPEC_P (ex_spec))
pp_cxx_ws_string (pp, "<uninstantiated>");
else
pp_cxx_expression (pp, TREE_PURPOSE (ex_spec));
pp_cxx_right_paren (pp);
return;
}

View File

@ -1784,6 +1784,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
tree oldtype = TREE_TYPE (olddecl);
tree newtype;
if (TREE_CODE (newdecl) == FUNCTION_DECL)
maybe_instantiate_noexcept (olddecl);
/* Merge the data types specified in the two decls. */
newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
@ -13665,6 +13668,7 @@ cp_tree_node_structure (union lang_tree_node * t)
switch (TREE_CODE (&t->generic))
{
case DEFAULT_ARG: return TS_CP_DEFAULT_ARG;
case DEFERRED_NOEXCEPT: return TS_CP_DEFERRED_NOEXCEPT;
case IDENTIFIER_NODE: return TS_CP_IDENTIFIER;
case OVERLOAD: return TS_CP_OVERLOAD;
case TEMPLATE_PARM_INDEX: return TS_CP_TPI;

View File

@ -4228,6 +4228,9 @@ mark_used (tree decl)
return;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
maybe_instantiate_noexcept (decl);
/* Normally, we can wait until instantiation-time to synthesize DECL.
However, if DECL is a static data member initialized with a constant
or a constexpr function, we need it right now because a reference to

View File

@ -1438,7 +1438,10 @@ dump_exception_spec (tree t, int flags)
pp_cxx_ws_string (cxx_pp, "noexcept");
pp_cxx_whitespace (cxx_pp);
pp_cxx_left_paren (cxx_pp);
dump_expr (TREE_PURPOSE (t), flags);
if (DEFERRED_NOEXCEPT_SPEC_P (t))
pp_cxx_ws_string (cxx_pp, "<uninstantiated>");
else
dump_expr (TREE_PURPOSE (t), flags);
pp_cxx_right_paren (cxx_pp);
}
else if (t)

View File

@ -1160,6 +1160,7 @@ finish_noexcept_expr (tree expr, tsubst_flags_t complain)
bool
nothrow_spec_p (const_tree spec)
{
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
if (spec == NULL_TREE
|| TREE_VALUE (spec) != NULL_TREE
|| spec == noexcept_false_spec)
@ -1180,6 +1181,7 @@ bool
type_noexcept_p (const_tree type)
{
tree spec = TYPE_RAISES_EXCEPTIONS (type);
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
if (flag_nothrow_opt)
return nothrow_spec_p (spec);
else
@ -1193,6 +1195,7 @@ bool
type_throw_all_p (const_tree type)
{
tree spec = TYPE_RAISES_EXCEPTIONS (type);
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
return spec == NULL_TREE || spec == noexcept_false_spec;
}
@ -1204,7 +1207,7 @@ build_noexcept_spec (tree expr, int complain)
{
/* This isn't part of the signature, so don't bother trying to evaluate
it until instantiation. */
if (!processing_template_decl)
if (!processing_template_decl && TREE_CODE (expr) != DEFERRED_NOEXCEPT)
{
expr = perform_implicit_conversion_flags (boolean_type_node, expr,
complain,
@ -1219,7 +1222,8 @@ build_noexcept_spec (tree expr, int complain)
return error_mark_node;
else
{
gcc_assert (processing_template_decl || expr == error_mark_node);
gcc_assert (processing_template_decl || expr == error_mark_node
|| TREE_CODE (expr) == DEFERRED_NOEXCEPT);
return build_tree_list (expr, NULL_TREE);
}
}

View File

@ -923,7 +923,9 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
if (spec_p)
{
tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
tree raises;
maybe_instantiate_noexcept (fn);
raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
*spec_p = merge_exception_specifiers (*spec_p, raises);
}
@ -1558,7 +1560,9 @@ defaulted_late_check (tree fn)
it had been implicitly declared. */
if (DECL_DEFAULTED_IN_CLASS_P (fn))
{
tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_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))

View File

@ -10342,7 +10342,8 @@ static tree
tsubst_exception_specification (tree fntype,
tree args,
tsubst_flags_t complain,
tree in_decl)
tree in_decl,
bool defer_ok)
{
tree specs;
tree new_specs;
@ -10352,9 +10353,33 @@ tsubst_exception_specification (tree fntype,
if (specs && TREE_PURPOSE (specs))
{
/* A noexcept-specifier. */
new_specs = tsubst_copy_and_build
(TREE_PURPOSE (specs), args, complain, in_decl, /*function_p=*/false,
/*integral_constant_expression_p=*/true);
tree expr = TREE_PURPOSE (specs);
if (expr == boolean_true_node || expr == boolean_false_node)
new_specs = expr;
else if (defer_ok)
{
/* Defer instantiation of noexcept-specifiers to avoid
excessive instantiations (c++/49107). */
new_specs = make_node (DEFERRED_NOEXCEPT);
if (DEFERRED_NOEXCEPT_SPEC_P (specs))
{
/* We already partially instantiated this member template,
so combine the new args with the old. */
DEFERRED_NOEXCEPT_PATTERN (new_specs)
= DEFERRED_NOEXCEPT_PATTERN (expr);
DEFERRED_NOEXCEPT_ARGS (new_specs)
= add_to_template_args (DEFERRED_NOEXCEPT_ARGS (expr), args);
}
else
{
DEFERRED_NOEXCEPT_PATTERN (new_specs) = expr;
DEFERRED_NOEXCEPT_ARGS (new_specs) = args;
}
}
else
new_specs = tsubst_copy_and_build
(expr, args, complain, in_decl, /*function_p=*/false,
/*integral_constant_expression_p=*/true);
new_specs = build_noexcept_spec (new_specs, complain);
}
else if (specs)
@ -10879,7 +10904,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Substitute the exception specification. */
specs = tsubst_exception_specification (t, args, complain,
in_decl);
in_decl, /*defer_ok*/true);
if (specs == error_mark_node)
return error_mark_node;
if (specs)
@ -17159,7 +17184,8 @@ regenerate_decl_from_template (tree decl, tree tmpl)
args = get_innermost_template_args (args, parms_depth);
specs = tsubst_exception_specification (TREE_TYPE (code_pattern),
args, tf_error, NULL_TREE);
args, tf_error, NULL_TREE,
/*defer_ok*/false);
if (specs)
TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl),
specs);
@ -17324,6 +17350,46 @@ always_instantiate_p (tree decl)
&& decl_maybe_constant_var_p (decl)));
}
/* If FN has a noexcept-specifier that hasn't been instantiated yet,
instantiate it now, modifying TREE_TYPE (fn). */
void
maybe_instantiate_noexcept (tree fn)
{
tree fntype = TREE_TYPE (fn);
tree spec = TYPE_RAISES_EXCEPTIONS (fntype);
tree noex = NULL_TREE;
location_t saved_loc = input_location;
tree clone;
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);
input_location = saved_loc;
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;
TREE_TYPE (fn) = build_exception_variant (fntype, spec);
FOR_EACH_CLONE (clone, fn)
{
if (TREE_TYPE (clone) == fntype)
TREE_TYPE (clone) = TREE_TYPE (fn);
else
TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec);
}
}
/* Produce the definition of D, a _DECL generated from a template. If
DEFER_OK is nonzero, then we don't have to actually do the
instantiation now; we just have to do it sometime. Normally it is
@ -17460,6 +17526,9 @@ instantiate_decl (tree d, int defer_ok,
SET_DECL_IMPLICIT_INSTANTIATION (d);
}
if (TREE_CODE (d) == FUNCTION_DECL)
maybe_instantiate_noexcept (d);
/* Recheck the substitutions to obtain any warning messages
about ignoring cv qualifiers. Don't do this for artificial decls,
as it breaks the context-sensitive substitution for lambda op(). */
@ -17477,7 +17546,7 @@ instantiate_decl (tree d, int defer_ok,
{
tsubst (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
tsubst_exception_specification (type, gen_args, tf_warning_or_error,
d);
d, /*defer_ok*/true);
/* Don't simply tsubst the function type, as that will give
duplicate warnings about poor parameter qualifications.
The function arguments are the same as the decl_arguments

View File

@ -227,6 +227,10 @@ cxx_print_xnode (FILE *file, tree node, int indent)
indent_to (file, indent + 3);
fprintf (file, "index %d", ARGUMENT_PACK_SELECT_INDEX (node));
break;
case DEFERRED_NOEXCEPT:
print_node (file, "pattern", DEFERRED_NOEXCEPT_PATTERN (node), indent+4);
print_node (file, "args", DEFERRED_NOEXCEPT_ARGS (node), indent+4);
break;
default:
break;
}

View File

@ -1803,8 +1803,8 @@ check_final_overrider (tree overrider, tree basefn)
tree base_type = TREE_TYPE (basefn);
tree over_return = TREE_TYPE (over_type);
tree base_return = TREE_TYPE (base_type);
tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
tree over_throw, base_throw;
int fail = 0;
if (DECL_INVALID_OVERRIDER_P (overrider))
@ -1888,6 +1888,11 @@ check_final_overrider (tree overrider, tree basefn)
}
/* Check throw specifier is at least as strict. */
maybe_instantiate_noexcept (basefn);
maybe_instantiate_noexcept (overrider);
base_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (basefn));
over_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (overrider));
if (!comp_except_specs (base_throw, over_throw, ce_derived))
{
error ("looser throw specifier for %q+#F", overrider);

View File

@ -2340,6 +2340,13 @@ cp_tree_equal (tree t1, tree t2)
/* Now compare operands as usual. */
break;
case DEFERRED_NOEXCEPT:
return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1),
DEFERRED_NOEXCEPT_PATTERN (t2))
&& comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
DEFERRED_NOEXCEPT_ARGS (t2)));
break;
default:
break;
}

View File

@ -1769,10 +1769,15 @@ merge_exception_specifiers (tree list, tree add)
return list;
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. */
else if (!TREE_VALUE (add))
if (!TREE_VALUE (add))
return list;
else if (!TREE_VALUE (list))
return add;

View File

@ -1,3 +1,9 @@
2011-06-08 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/noexcept11.C: New.
* g++.dg/cpp0x/noexcept12.C: New.
* g++.dg/cpp0x/sfinae11.C: Adjust.
2011-06-08 Jakub Jelinek <jakub@redhat.com>
PR testsuite/49323

View File

@ -0,0 +1,53 @@
// PR c++/49107
// { dg-options -std=c++0x }
template<typename _Tp>
_Tp declval() noexcept;
template<typename _Tp , typename = decltype(_Tp(declval<_Tp&&>()))>
struct trait
{
static const bool value=true;
};
template<class _T2>
struct pair
{
_T2 second;
void swap(pair& __p)
noexcept(trait<_T2>::value);
};
template < class R_ >
struct Main
{
Main() {}
Main(const typename R_::Sub1T& r) ;
Main(const typename R_::Sub2T& l) ;
};
template < class R_ >
class Sub1
{
typedef pair<typename R_::MainT> Rep;
Rep base;
};
template < class R_ >
struct Sub2
{
typedef pair<typename R_::MainT> Rep;
Rep base;
};
struct Kernel
{
typedef Main<Kernel> MainT;
typedef Sub1<Kernel> Sub1T;
typedef Sub2<Kernel> Sub2T;
};
Main<Kernel> f()
{
return Main<Kernel> ();
}

View File

@ -0,0 +1,11 @@
// Test that we handle merging with deferred noexcept.
// { dg-options -std=c++0x }
template <class U>
struct O
{
template <class T>
void f() noexcept(noexcept(T()));
};
template<> template<> void O<int>::f<int>() noexcept { }

View File

@ -6,7 +6,7 @@ template<class T>
T&& declval() noexcept;
template< class T >
inline void f1( T& x ) noexcept( noexcept( declval<T&>().foo() ) )
inline void f1( T& x ) noexcept( noexcept( declval<T&>().foo() ) ) // { dg-error "Z" }
{
x.foo();
}
@ -21,7 +21,7 @@ inline void f2( T& x ) noexcept( Noexcept )
// a common and trivial mistake
template< class T >
inline void f3( T& x ) noexcept( declval<T&>().foo() )
inline void f3( T& x ) noexcept( declval<T&>().foo() ) // { dg-error "Z" }
{
x.foo();
}
@ -50,7 +50,7 @@ int main()
static_assert( noexcept( f2(y) ), "OK." );
// static_assert( noexcept( f3(y) ), "shall be ill-formed(OK)." );
static_assert( noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "no match" }
noexcept( f1(z) ); // { dg-message "required" }
static_assert( noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" }
static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "no match" }
noexcept( f3(z) ); // { dg-message "required" }
}