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> 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 * semantics.c (potential_constant_expression_1): Handle destructor
call. call.

View File

@ -79,6 +79,7 @@ cp_tree_size (enum tree_code code)
case BASELINK: return sizeof (struct tree_baselink); case BASELINK: return sizeof (struct tree_baselink);
case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index); case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index);
case DEFAULT_ARG: return sizeof (struct tree_default_arg); 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 OVERLOAD: return sizeof (struct tree_overload);
case STATIC_ASSERT: return sizeof (struct tree_static_assert); case STATIC_ASSERT: return sizeof (struct tree_static_assert);
case TYPE_ARGUMENT_PACK: case TYPE_ARGUMENT_PACK:

View File

@ -214,6 +214,11 @@ DEFTREECODE (USING_STMT, "using_directive", tcc_statement, 1)
parsing had occurred. */ parsing had occurred. */
DEFTREECODE (DEFAULT_ARG, "default_arg", tcc_exceptional, 0) 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. /* A template-id, like foo<int>. The first operand is the template.
The second is NULL if there are no explicit arguments, or a The second is NULL if there are no explicit arguments, or a
TREE_VEC of arguments. The template will be a FUNCTION_DECL, 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; 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 /* The condition associated with the static assertion. This must be
an integral constant expression. */ an integral constant expression. */
#define STATIC_ASSERT_CONDITION(NODE) \ #define STATIC_ASSERT_CONDITION(NODE) \
@ -693,6 +709,7 @@ enum cp_tree_node_structure_enum {
TS_CP_BASELINK, TS_CP_BASELINK,
TS_CP_WRAPPER, TS_CP_WRAPPER,
TS_CP_DEFAULT_ARG, TS_CP_DEFAULT_ARG,
TS_CP_DEFERRED_NOEXCEPT,
TS_CP_STATIC_ASSERT, TS_CP_STATIC_ASSERT,
TS_CP_ARGUMENT_PACK_SELECT, TS_CP_ARGUMENT_PACK_SELECT,
TS_CP_TRAIT_EXPR, 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_overload GTY ((tag ("TS_CP_OVERLOAD"))) overload;
struct tree_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink; struct tree_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink;
struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg; 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 lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT"))) struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT")))
static_assertion; static_assertion;
@ -5130,6 +5148,7 @@ extern int more_specialized_fn (tree, tree, int);
extern void do_decl_instantiation (tree, tree); extern void do_decl_instantiation (tree, tree);
extern void do_type_instantiation (tree, tree, tsubst_flags_t); extern void do_type_instantiation (tree, tree, tsubst_flags_t);
extern bool always_instantiate_p (tree); extern bool always_instantiate_p (tree);
extern void maybe_instantiate_noexcept (tree);
extern tree instantiate_decl (tree, int, bool); extern tree instantiate_decl (tree, int, bool);
extern int comp_template_parms (const_tree, const_tree); extern int comp_template_parms (const_tree, const_tree);
extern bool uses_parameter_packs (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_ws_string (pp, "noexcept");
pp_cxx_whitespace (pp); pp_cxx_whitespace (pp);
pp_cxx_left_paren (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); pp_cxx_right_paren (pp);
return; return;
} }

View File

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

View File

@ -4228,6 +4228,9 @@ mark_used (tree decl)
return; return;
} }
if (TREE_CODE (decl) == FUNCTION_DECL)
maybe_instantiate_noexcept (decl);
/* Normally, we can wait until instantiation-time to synthesize DECL. /* Normally, we can wait until instantiation-time to synthesize DECL.
However, if DECL is a static data member initialized with a constant 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 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_ws_string (cxx_pp, "noexcept");
pp_cxx_whitespace (cxx_pp); pp_cxx_whitespace (cxx_pp);
pp_cxx_left_paren (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); pp_cxx_right_paren (cxx_pp);
} }
else if (t) else if (t)

View File

@ -1160,6 +1160,7 @@ finish_noexcept_expr (tree expr, tsubst_flags_t complain)
bool bool
nothrow_spec_p (const_tree spec) nothrow_spec_p (const_tree spec)
{ {
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
if (spec == NULL_TREE if (spec == NULL_TREE
|| TREE_VALUE (spec) != NULL_TREE || TREE_VALUE (spec) != NULL_TREE
|| spec == noexcept_false_spec) || spec == noexcept_false_spec)
@ -1180,6 +1181,7 @@ bool
type_noexcept_p (const_tree type) type_noexcept_p (const_tree type)
{ {
tree spec = TYPE_RAISES_EXCEPTIONS (type); tree spec = TYPE_RAISES_EXCEPTIONS (type);
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
if (flag_nothrow_opt) if (flag_nothrow_opt)
return nothrow_spec_p (spec); return nothrow_spec_p (spec);
else else
@ -1193,6 +1195,7 @@ bool
type_throw_all_p (const_tree type) type_throw_all_p (const_tree type)
{ {
tree spec = TYPE_RAISES_EXCEPTIONS (type); tree spec = TYPE_RAISES_EXCEPTIONS (type);
gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
return spec == NULL_TREE || spec == noexcept_false_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 /* This isn't part of the signature, so don't bother trying to evaluate
it until instantiation. */ 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, expr = perform_implicit_conversion_flags (boolean_type_node, expr,
complain, complain,
@ -1219,7 +1222,8 @@ build_noexcept_spec (tree expr, int complain)
return error_mark_node; return error_mark_node;
else 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); 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) 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); *spec_p = merge_exception_specifiers (*spec_p, raises);
} }
@ -1558,7 +1560,9 @@ defaulted_late_check (tree fn)
it had been implicitly declared. */ it had been implicitly declared. */
if (DECL_DEFAULTED_IN_CLASS_P (fn)) 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)) if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))
&& !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)), && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
eh_spec, ce_normal)) eh_spec, ce_normal))

View File

@ -10342,7 +10342,8 @@ static tree
tsubst_exception_specification (tree fntype, tsubst_exception_specification (tree fntype,
tree args, tree args,
tsubst_flags_t complain, tsubst_flags_t complain,
tree in_decl) tree in_decl,
bool defer_ok)
{ {
tree specs; tree specs;
tree new_specs; tree new_specs;
@ -10352,9 +10353,33 @@ tsubst_exception_specification (tree fntype,
if (specs && TREE_PURPOSE (specs)) if (specs && TREE_PURPOSE (specs))
{ {
/* A noexcept-specifier. */ /* A noexcept-specifier. */
new_specs = tsubst_copy_and_build tree expr = TREE_PURPOSE (specs);
(TREE_PURPOSE (specs), args, complain, in_decl, /*function_p=*/false, if (expr == boolean_true_node || expr == boolean_false_node)
/*integral_constant_expression_p=*/true); 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); new_specs = build_noexcept_spec (new_specs, complain);
} }
else if (specs) else if (specs)
@ -10879,7 +10904,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Substitute the exception specification. */ /* Substitute the exception specification. */
specs = tsubst_exception_specification (t, args, complain, specs = tsubst_exception_specification (t, args, complain,
in_decl); in_decl, /*defer_ok*/true);
if (specs == error_mark_node) if (specs == error_mark_node)
return error_mark_node; return error_mark_node;
if (specs) if (specs)
@ -17159,7 +17184,8 @@ regenerate_decl_from_template (tree decl, tree tmpl)
args = get_innermost_template_args (args, parms_depth); args = get_innermost_template_args (args, parms_depth);
specs = tsubst_exception_specification (TREE_TYPE (code_pattern), specs = tsubst_exception_specification (TREE_TYPE (code_pattern),
args, tf_error, NULL_TREE); args, tf_error, NULL_TREE,
/*defer_ok*/false);
if (specs) if (specs)
TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl),
specs); specs);
@ -17324,6 +17350,46 @@ always_instantiate_p (tree decl)
&& decl_maybe_constant_var_p (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 /* 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 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 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); SET_DECL_IMPLICIT_INSTANTIATION (d);
} }
if (TREE_CODE (d) == FUNCTION_DECL)
maybe_instantiate_noexcept (d);
/* Recheck the substitutions to obtain any warning messages /* Recheck the substitutions to obtain any warning messages
about ignoring cv qualifiers. Don't do this for artificial decls, about ignoring cv qualifiers. Don't do this for artificial decls,
as it breaks the context-sensitive substitution for lambda op(). */ 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 (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
tsubst_exception_specification (type, gen_args, tf_warning_or_error, 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 /* Don't simply tsubst the function type, as that will give
duplicate warnings about poor parameter qualifications. duplicate warnings about poor parameter qualifications.
The function arguments are the same as the decl_arguments 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); indent_to (file, indent + 3);
fprintf (file, "index %d", ARGUMENT_PACK_SELECT_INDEX (node)); fprintf (file, "index %d", ARGUMENT_PACK_SELECT_INDEX (node));
break; 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: default:
break; break;
} }

View File

@ -1803,8 +1803,8 @@ check_final_overrider (tree overrider, tree basefn)
tree base_type = TREE_TYPE (basefn); tree base_type = TREE_TYPE (basefn);
tree over_return = TREE_TYPE (over_type); tree over_return = TREE_TYPE (over_type);
tree base_return = TREE_TYPE (base_type); tree base_return = TREE_TYPE (base_type);
tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type); tree over_throw, base_throw;
tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
int fail = 0; int fail = 0;
if (DECL_INVALID_OVERRIDER_P (overrider)) 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. */ /* 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)) if (!comp_except_specs (base_throw, over_throw, ce_derived))
{ {
error ("looser throw specifier for %q+#F", overrider); 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. */ /* Now compare operands as usual. */
break; 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: default:
break; break;
} }

View File

@ -1769,10 +1769,15 @@ merge_exception_specifiers (tree list, tree add)
return list; return list;
else if (!add || add == noexcept_false_spec) else if (!add || add == noexcept_false_spec)
return add; 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). /* For merging noexcept(true) and throw(), take the more recent one (LIST).
Any other noexcept-spec should only be merged with an equivalent one. Any other noexcept-spec should only be merged with an equivalent one.
So the !TREE_VALUE code below is correct for all cases. */ So the !TREE_VALUE code below is correct for all cases. */
else if (!TREE_VALUE (add)) if (!TREE_VALUE (add))
return list; return list;
else if (!TREE_VALUE (list)) else if (!TREE_VALUE (list))
return add; 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> 2011-06-08 Jakub Jelinek <jakub@redhat.com>
PR testsuite/49323 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; T&& declval() noexcept;
template< class T > 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(); x.foo();
} }
@ -21,7 +21,7 @@ inline void f2( T& x ) noexcept( Noexcept )
// a common and trivial mistake // a common and trivial mistake
template< class T > 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(); x.foo();
} }
@ -50,7 +50,7 @@ int main()
static_assert( noexcept( f2(y) ), "OK." ); static_assert( noexcept( f2(y) ), "OK." );
// static_assert( noexcept( f3(y) ), "shall be ill-formed(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( 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" }
} }