summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog30
-rw-r--r--gcc/cp/class.c6
-rw-r--r--gcc/cp/cp-tree.def9
-rw-r--r--gcc/cp/cp-tree.h19
-rw-r--r--gcc/cp/decl.c32
-rw-r--r--gcc/cp/decl2.c6
-rw-r--r--gcc/cp/except.c12
-rw-r--r--gcc/cp/init.c65
-rw-r--r--gcc/cp/method.c101
-rw-r--r--gcc/cp/parser.c15
-rw-r--r--gcc/cp/parser.h6
-rw-r--r--gcc/cp/pt.c28
-rw-r--r--gcc/cp/typeck.c6
-rw-r--r--gcc/cp/typeck2.c30
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C2
17 files changed, 251 insertions, 127 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a5f3829d705..b2018255b18 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,33 @@
+2014-04-29 Jason Merrill <jason@redhat.com>
+
+ DR 1351
+ Represent the unevaluated exception specification of an implicitly
+ declared or deleted function with a simple placeholder, not a list
+ of functions.
+ * cp-tree.h (UNEVALUATED_NOEXCEPT_SPEC_P): New.
+ * except.c (unevaluated_noexcept_spec): New.
+ * class.c (deduce_noexcept_on_destructor): Use it.
+ * decl.c (check_redeclaration_exception_specification): Call
+ maybe_instantiate_noexcept.
+ (duplicate_decls): Call it before merge_types.
+ (start_preparsed_function): Call maybe_instantiate_noexcept.
+ * decl2.c (mark_used): Call maybe_instantiate_noexcept earlier.
+ * init.c (get_nsdmi): Factor out of perform_member_init.
+ * method.c (process_subob_fn): Call maybe_instantiate_noexcept.
+ (walk_field_subobs): Consider NSDMI for EH spec.
+ (get_defaulted_eh_spec): New.
+ (implicitly_declare_fn): Use unevaluated_noexcept_spec.
+ (defaulted_late_check): Defer EH checking in non-template classes.
+ (after_nsdmi_defaulted_late_checks): New.
+ * parser.c (cp_parser_class_specifier_1): Use it.
+ (unparsed_classes): New macro.
+ * parser.h (cp_unparsed_functions_entry_d): Add classes field.
+ * pt.c (maybe_instantiate_noexcept): Use get_defaulted_eh_spec.
+ Remove list-of-functions handling.
+ * typeck2.c (merge_exception_specifiers): Remove list-of-functions
+ handling and FN parameter.
+ * typeck.c (merge_types): Adjust.
+
2014-04-28 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/59120
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 334bfd5eee7..5cac488ee95 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4725,11 +4725,7 @@ deduce_noexcept_on_destructor (tree dtor)
{
if (!TYPE_RAISES_EXCEPTIONS (TREE_TYPE (dtor)))
{
- tree ctx = DECL_CONTEXT (dtor);
- tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
- /*const_p=*/false,
- NULL, NULL);
- tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+ tree eh_spec = unevaluated_noexcept_spec ();
TREE_TYPE (dtor) = build_exception_variant (TREE_TYPE (dtor), eh_spec);
}
}
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 057e7ea5ef7..b4a72d6e30a 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -212,9 +212,12 @@ DEFTREECODE (USING_STMT, "using_stmt", 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. */
+/* An uninstantiated/unevaluated noexcept-specification. For the
+ uninstantiated case, DEFERRED_NOEXCEPT_PATTERN is the pattern from the
+ template, and DEFERRED_NOEXCEPT_ARGS are the template arguments to
+ substitute into the pattern when needed. For the unevaluated case,
+ those slots are NULL_TREE and we use get_defaulted_eh_spec to find
+ the exception-specification. */
DEFTREECODE (DEFERRED_NOEXCEPT, "deferred_noexcept", tcc_exceptional, 0)
/* A template-id, like foo<int>. The first operand is the template.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f459e55bc84..55ecc4e5b5f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -579,8 +579,10 @@ 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 \
- || is_overloaded_fn (TREE_PURPOSE (NODE))))
+ && (TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT))
+#define UNEVALUATED_NOEXCEPT_SPEC_P(NODE) \
+ (DEFERRED_NOEXCEPT_SPEC_P (NODE) \
+ && DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (NODE)) == NULL_TREE)
struct GTY (()) tree_deferred_noexcept {
struct tree_base base;
@@ -4359,8 +4361,6 @@ extern int comparing_specializations;
sizeof can be nested. */
extern int cp_unevaluated_operand;
-extern tree cp_convert_range_for (tree, tree, tree, bool);
-extern bool parsing_nsdmi (void);
/* in pt.c */
@@ -5420,6 +5420,7 @@ extern tree get_type_value (tree);
extern tree build_zero_init (tree, tree, bool);
extern tree build_value_init (tree, tsubst_flags_t);
extern tree build_value_init_noctor (tree, tsubst_flags_t);
+extern tree get_nsdmi (tree, bool);
extern tree build_offset_ref (tree, tree, bool,
tsubst_flags_t);
extern tree throw_bad_array_new_length (void);
@@ -5468,6 +5469,9 @@ extern tree make_thunk (tree, bool, tree, tree);
extern void finish_thunk (tree);
extern void use_thunk (tree, bool);
extern bool trivial_fn_p (tree);
+extern tree get_defaulted_eh_spec (tree);
+extern tree unevaluated_noexcept_spec (void);
+extern void after_nsdmi_defaulted_late_checks (tree);
extern bool maybe_explain_implicit_delete (tree);
extern void explain_implicit_non_constexpr (tree);
extern void deduce_inheriting_ctor (tree);
@@ -5489,6 +5493,11 @@ extern tree implicitly_declare_fn (special_function_kind, tree,
/* In optimize.c */
extern bool maybe_clone_body (tree);
+/* In parser.c */
+extern tree cp_convert_range_for (tree, tree, tree, bool);
+extern bool parsing_nsdmi (void);
+extern void inject_this_parameter (tree, cp_cv_quals);
+
/* in pt.c */
extern bool check_template_shadow (tree);
extern tree get_innermost_template_args (tree, int);
@@ -6162,7 +6171,7 @@ extern tree build_x_arrow (location_t, tree,
extern tree build_m_component_ref (tree, tree, tsubst_flags_t);
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, tree);
+extern tree merge_exception_specifiers (tree, tree);
/* in mangle.c */
extern void init_mangle (void);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7ce55c87d77..202db35d3c8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1167,15 +1167,18 @@ static void
check_redeclaration_exception_specification (tree new_decl,
tree old_decl)
{
- tree new_type;
- tree old_type;
- tree new_exceptions;
- tree old_exceptions;
+ tree new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl));
+ tree old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl));
- new_type = TREE_TYPE (new_decl);
- new_exceptions = TYPE_RAISES_EXCEPTIONS (new_type);
- old_type = TREE_TYPE (old_decl);
- old_exceptions = TYPE_RAISES_EXCEPTIONS (old_type);
+ /* Two default specs are equivalent, don't force evaluation. */
+ if (UNEVALUATED_NOEXCEPT_SPEC_P (new_exceptions)
+ && UNEVALUATED_NOEXCEPT_SPEC_P (old_exceptions))
+ return;
+
+ maybe_instantiate_noexcept (new_decl);
+ maybe_instantiate_noexcept (old_decl);
+ new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl));
+ old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl));
/* [except.spec]
@@ -1915,13 +1918,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
if (types_match)
{
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ check_redeclaration_exception_specification (newdecl, olddecl);
+
/* Automatically handles default parameters. */
tree oldtype = TREE_TYPE (olddecl);
tree newtype;
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
- maybe_instantiate_noexcept (olddecl);
-
/* For typedefs use the old type, as the new type's DECL_NAME points
at newdecl, which will be ggc_freed. */
if (TREE_CODE (newdecl) == TYPE_DECL)
@@ -1952,10 +1955,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
}
}
- /* Do this after calling `merge_types' so that default
- parameters don't confuse us. */
- else if (TREE_CODE (newdecl) == FUNCTION_DECL)
- check_redeclaration_exception_specification (newdecl, olddecl);
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -13435,6 +13434,9 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
if (!DECL_CLONED_FUNCTION_P (decl1))
determine_visibility (decl1);
+ if (!processing_template_decl)
+ maybe_instantiate_noexcept (decl1);
+
begin_scope (sk_function_parms, decl1);
++function_depth;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8a7a8369f19..918ea2fc6d0 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4806,6 +4806,9 @@ mark_used (tree decl, tsubst_flags_t complain)
if (TREE_CODE (decl) == CONST_DECL)
used_types_insert (DECL_CONTEXT (decl));
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ maybe_instantiate_noexcept (decl);
+
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DELETED_FN (decl))
{
@@ -4860,9 +4863,6 @@ mark_used (tree decl, tsubst_flags_t complain)
return true;
}
- 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
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 221971ac956..ead889c0658 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1342,6 +1342,18 @@ build_noexcept_spec (tree expr, int complain)
}
}
+/* Returns a noexcept-specifier to be evaluated later, for an
+ implicitly-declared or explicitly defaulted special member function. */
+
+tree
+unevaluated_noexcept_spec (void)
+{
+ static tree spec;
+ if (spec == NULL_TREE)
+ spec = build_noexcept_spec (make_node (DEFERRED_NOEXCEPT), tf_none);
+ return spec;
+}
+
/* Returns a TRY_CATCH_EXPR that will put TRY_LIST and CATCH_LIST in the
TRY and CATCH locations. CATCH_LIST must be a STATEMENT_LIST */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index fdc1011f198..8b9405c54ed 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -521,6 +521,45 @@ perform_target_ctor (tree init)
}
}
+/* Return the non-static data initializer for FIELD_DECL MEMBER. */
+
+tree
+get_nsdmi (tree member, bool in_ctor)
+{
+ tree init;
+ tree save_ccp = current_class_ptr;
+ tree save_ccr = current_class_ref;
+ if (!in_ctor)
+ inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
+ if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
+ /* Do deferred instantiation of the NSDMI. */
+ init = (tsubst_copy_and_build
+ (DECL_INITIAL (DECL_TI_TEMPLATE (member)),
+ DECL_TI_ARGS (member),
+ tf_warning_or_error, member, /*function_p=*/false,
+ /*integral_constant_expression_p=*/false));
+ else
+ {
+ init = DECL_INITIAL (member);
+ if (init && TREE_CODE (init) == DEFAULT_ARG)
+ {
+ error ("constructor required before non-static data member "
+ "for %qD has been parsed", member);
+ DECL_INITIAL (member) = error_mark_node;
+ init = NULL_TREE;
+ }
+ /* Strip redundant TARGET_EXPR so we don't need to remap it, and
+ so the aggregate init code below will see a CONSTRUCTOR. */
+ if (init && TREE_CODE (init) == TARGET_EXPR
+ && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init))))
+ init = TARGET_EXPR_INITIAL (init);
+ init = break_out_target_exprs (init);
+ }
+ current_class_ptr = save_ccp;
+ current_class_ref = save_ccr;
+ return init;
+}
+
/* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
arguments. If TREE_LIST is void_type_node, an empty initializer
list was given; if NULL_TREE no initializer was given. */
@@ -534,31 +573,7 @@ perform_member_init (tree member, tree init)
/* Use the non-static data member initializer if there was no
mem-initializer for this field. */
if (init == NULL_TREE)
- {
- if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
- /* Do deferred instantiation of the NSDMI. */
- init = (tsubst_copy_and_build
- (DECL_INITIAL (DECL_TI_TEMPLATE (member)),
- DECL_TI_ARGS (member),
- tf_warning_or_error, member, /*function_p=*/false,
- /*integral_constant_expression_p=*/false));
- else
- {
- init = DECL_INITIAL (member);
- if (init && TREE_CODE (init) == DEFAULT_ARG)
- {
- error ("constructor required before non-static data member "
- "for %qD has been parsed", member);
- init = NULL_TREE;
- }
- /* Strip redundant TARGET_EXPR so we don't need to remap it, and
- so the aggregate init code below will see a CONSTRUCTOR. */
- if (init && TREE_CODE (init) == TARGET_EXPR
- && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init))))
- init = TARGET_EXPR_INITIAL (init);
- init = break_out_target_exprs (init);
- }
- }
+ init = get_nsdmi (member, /*ctor*/true);
if (init == error_mark_node)
return;
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 11bff7f4587..f8fc01ff531 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1003,8 +1003,9 @@ process_subob_fn (tree fn, tree *spec_p, bool *trivial_p,
if (spec_p)
{
+ maybe_instantiate_noexcept (fn);
tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
- *spec_p = merge_exception_specifiers (*spec_p, raises, fn);
+ *spec_p = merge_exception_specifiers (*spec_p, raises);
}
if (!trivial_fn_p (fn))
@@ -1090,17 +1091,14 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
inform (0, "initializer for %q+#D is invalid", field);
if (trivial_p)
*trivial_p = false;
-#if 0
/* Core 1351: If the field has an NSDMI that could throw, the
- default constructor is noexcept(false). FIXME this is
- broken by deferred parsing and 1360 saying we can't lazily
- declare a non-trivial default constructor. Also this
- needs to do deferred instantiation. Disable until the
- conflict between 1351 and 1360 is resolved. */
- if (spec_p && !expr_noexcept_p (DECL_INITIAL (field), complain))
- *spec_p = noexcept_false_spec;
-#endif
-
+ default constructor is noexcept(false). */
+ if (spec_p)
+ {
+ tree nsdmi = get_nsdmi (field, /*ctor*/false);
+ if (!expr_noexcept_p (nsdmi, complain))
+ *spec_p = noexcept_false_spec;
+ }
/* Don't do the normal processing. */
continue;
}
@@ -1438,6 +1436,26 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
--c_inhibit_evaluation_warnings;
}
+/* DECL is a defaulted function whose exception specification is now
+ needed. Return what it should be. */
+
+tree
+get_defaulted_eh_spec (tree decl)
+{
+ if (DECL_CLONED_FUNCTION_P (decl))
+ decl = DECL_CLONED_FUNCTION (decl);
+ special_function_kind sfk = special_function_p (decl);
+ tree ctype = DECL_CONTEXT (decl);
+ tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
+ tree parm_type = TREE_VALUE (parms);
+ bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
+ tree spec = empty_except_spec;
+ synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL,
+ NULL, false, DECL_INHERITED_CTOR_BASE (decl),
+ parms);
+ return spec;
+}
+
/* DECL is a deleted function. If it's implicitly deleted, explain why and
return true; else return false. */
@@ -1675,6 +1693,13 @@ implicitly_declare_fn (special_function_kind kind, tree type,
deleted_p = DECL_DELETED_FN (inherited_ctor);
constexpr_p = DECL_DECLARED_CONSTEXPR_P (inherited_ctor);
}
+ else if (cxx_dialect >= cxx11)
+ {
+ raises = unevaluated_noexcept_spec ();
+ synthesized_method_walk (type, kind, const_p, NULL, &trivial_p,
+ &deleted_p, &constexpr_p, false,
+ inherited_base, inherited_parms);
+ }
else
synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
&deleted_p, &constexpr_p, false,
@@ -1826,25 +1851,33 @@ defaulted_late_check (tree fn)
is explicitly defaulted on its first declaration, (...) it is
implicitly considered to have the same exception-specification as if
it had been implicitly declared. */
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+ tree fn_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+ if (!fn_spec)
{
- maybe_instantiate_noexcept (fn);
- if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
- eh_spec, ce_normal))
+ if (DECL_DEFAULTED_IN_CLASS_P (fn))
+ TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
+ }
+ else if (UNEVALUATED_NOEXCEPT_SPEC_P (fn_spec))
+ /* Equivalent to the implicit spec. */;
+ else if (DECL_DEFAULTED_IN_CLASS_P (fn)
+ && !CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
+ /* We can't compare an explicit exception-specification on a
+ constructor defaulted in the class body to the implicit
+ exception-specification until after we've parsed any NSDMI; see
+ after_nsdmi_defaulted_late_checks. */;
+ else
+ {
+ tree eh_spec = get_defaulted_eh_spec (fn);
+ if (!comp_except_specs (fn_spec, eh_spec, ce_normal))
{
if (DECL_DEFAULTED_IN_CLASS_P (fn))
- {
- DECL_DELETED_FN (fn) = true;
- eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
- }
+ DECL_DELETED_FN (fn) = true;
else
error ("function %q+D defaulted on its redeclaration "
"with an exception-specification that differs from "
- "the implicit declaration %q#D", fn, implicit_fn);
+ "the implicit exception-specification %qX", fn, eh_spec);
}
}
- if (DECL_DEFAULTED_IN_CLASS_P (fn))
- TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
if (DECL_DEFAULTED_IN_CLASS_P (fn)
&& DECL_DECLARED_CONSTEXPR_P (implicit_fn))
@@ -1874,6 +1907,30 @@ defaulted_late_check (tree fn)
DECL_DELETED_FN (fn) = 1;
}
+/* OK, we've parsed the NSDMI for class T, now we can check any explicit
+ exception-specifications on functions defaulted in the class body. */
+
+void
+after_nsdmi_defaulted_late_checks (tree t)
+{
+ if (uses_template_parms (t))
+ return;
+ if (t == error_mark_node)
+ return;
+ for (tree fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
+ if (!DECL_ARTIFICIAL (fn) && DECL_DEFAULTED_IN_CLASS_P (fn))
+ {
+ tree fn_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+ if (UNEVALUATED_NOEXCEPT_SPEC_P (fn_spec))
+ continue;
+
+ tree eh_spec = get_defaulted_eh_spec (fn);
+ if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
+ eh_spec, ce_normal))
+ DECL_DELETED_FN (fn) = true;
+ }
+}
+
/* Returns true iff FN can be explicitly defaulted, and gives any
errors if defaulting FN is ill-formed. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 962cacedf80..5542dcd9ba3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1848,11 +1848,13 @@ cp_parser_context_new (cp_parser_context* next)
parser->unparsed_queues->last ().funs_with_definitions
#define unparsed_nsdmis \
parser->unparsed_queues->last ().nsdmis
+#define unparsed_classes \
+ parser->unparsed_queues->last ().classes
static void
push_unparsed_function_queues (cp_parser *parser)
{
- cp_unparsed_functions_entry e = {NULL, make_tree_vector (), NULL};
+ cp_unparsed_functions_entry e = {NULL, make_tree_vector (), NULL, NULL};
vec_safe_push (parser->unparsed_queues, e);
}
@@ -17834,7 +17836,7 @@ cp_parser_virt_specifier_seq_opt (cp_parser* parser)
/* Used by handling of trailing-return-types and NSDMI, in which 'this'
is in scope even though it isn't real. */
-static void
+void
inject_this_parameter (tree ctype, cp_cv_quals quals)
{
tree this_parm;
@@ -19505,6 +19507,13 @@ cp_parser_class_specifier_1 (cp_parser* parser)
current_class_ref = save_ccr;
if (pushed_scope)
pop_scope (pushed_scope);
+
+ /* Now do some post-NSDMI bookkeeping. */
+ FOR_EACH_VEC_SAFE_ELT (unparsed_classes, ix, class_type)
+ after_nsdmi_defaulted_late_checks (class_type);
+ vec_safe_truncate (unparsed_classes, 0);
+ after_nsdmi_defaulted_late_checks (type);
+
/* Now parse the body of the functions. */
if (flag_openmp)
{
@@ -19521,6 +19530,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
cp_parser_late_parsing_for_member (parser, decl);
vec_safe_truncate (unparsed_funs_with_definitions, 0);
}
+ else
+ vec_safe_push (unparsed_classes, type);
/* Put back any saved access checks. */
pop_deferring_access_checks ();
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 758c6df3c27..96a84534045 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -149,7 +149,7 @@ typedef struct GTY(()) cp_default_arg_entry_d {
} cp_default_arg_entry;
-/* An entry in a stack for member functions of local classes. */
+/* An entry in a stack for member functions defined within their classes. */
typedef struct GTY(()) cp_unparsed_functions_entry_d {
/* Functions with default arguments that require post-processing.
@@ -163,6 +163,10 @@ typedef struct GTY(()) cp_unparsed_functions_entry_d {
/* Non-static data members with initializers that require post-processing.
FIELD_DECLs appear in this list in declaration order. */
vec<tree, va_gc> *nsdmis;
+
+ /* Nested classes go in this vector, so that we can do some final
+ processing after parsing any NSDMIs. */
+ vec<tree, va_gc> *classes;
} cp_unparsed_functions_entry;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c74e7ae7586..48cc2a9e9cf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19470,14 +19470,16 @@ maybe_instantiate_noexcept (tree fn)
fntype = TREE_TYPE (fn);
spec = TYPE_RAISES_EXCEPTIONS (fntype);
- if (!DEFERRED_NOEXCEPT_SPEC_P (spec))
+ if (!spec || !TREE_PURPOSE (spec))
return;
noex = TREE_PURPOSE (spec);
if (TREE_CODE (noex) == DEFERRED_NOEXCEPT)
{
- if (push_tinst_level (fn))
+ if (DEFERRED_NOEXCEPT_PATTERN (noex) == NULL_TREE)
+ spec = get_defaulted_eh_spec (fn);
+ else if (push_tinst_level (fn))
{
push_access_scope (fn);
push_deferring_access_checks (dk_no_deferred);
@@ -19496,24 +19498,9 @@ maybe_instantiate_noexcept (tree fn)
}
else
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);
+ TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+ }
FOR_EACH_CLONE (clone, fn)
{
@@ -19664,9 +19651,6 @@ instantiate_decl (tree d, int defer_ok,
SET_DECL_IMPLICIT_INSTANTIATION (d);
}
- if (TREE_CODE (d) == FUNCTION_DECL)
- maybe_instantiate_noexcept (d);
-
/* Defer all other templates, unless we have been explicitly
forbidden from doing so. */
if (/* If there is no definition, we cannot instantiate the
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9a80727dd8e..ae7fa776eb8 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -840,8 +840,7 @@ merge_types (tree t1, tree t2)
type_memfn_quals (t1),
type_memfn_rqual (t1));
raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
- TYPE_RAISES_EXCEPTIONS (t2),
- NULL_TREE);
+ TYPE_RAISES_EXCEPTIONS (t2));
t1 = build_exception_variant (rval, raises);
break;
}
@@ -852,8 +851,7 @@ 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),
- NULL_TREE);
+ TYPE_RAISES_EXCEPTIONS (t2));
cp_ref_qualifier rqual = type_memfn_rqual (t1);
tree t3;
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 68e518a5c73..5bbc2efd5e6 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1989,10 +1989,10 @@ nothrow_spec_p_uninst (const_tree spec)
}
/* Combine the two exceptions specifier lists LIST and ADD, and return
- their union. If FN is non-null, it's the source of ADD. */
+ their union. */
tree
-merge_exception_specifiers (tree list, tree add, tree fn)
+merge_exception_specifiers (tree list, tree add)
{
tree noex, orig_list;
@@ -2008,22 +2008,18 @@ merge_exception_specifiers (tree list, tree add, tree fn)
if (nothrow_spec_p_uninst (add))
return 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 && operand_equal_p (noex, boolean_true_node, 0))
- noex = NULL_TREE;
- gcc_assert (fn && (!noex || is_overloaded_fn (noex)));
- noex = build_overload (fn, noex);
- }
- else if (nothrow_spec_p_uninst (list))
+ /* Two implicit noexcept specs (e.g. on a destructor) are equivalent. */
+ if (UNEVALUATED_NOEXCEPT_SPEC_P (add)
+ && UNEVALUATED_NOEXCEPT_SPEC_P (list))
+ return list;
+ /* We should have instantiated other deferred noexcept specs by now. */
+ gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (add));
+
+ if (nothrow_spec_p_uninst (list))
return add;
- else
- gcc_checking_assert (!TREE_PURPOSE (add)
- || cp_tree_equal (noex, TREE_PURPOSE (add)));
+ noex = TREE_PURPOSE (list);
+ gcc_checking_assert (!TREE_PURPOSE (add)
+ || cp_tree_equal (noex, TREE_PURPOSE (add)));
/* Combine the dynamic-exception-specifiers, if any. */
orig_list = list;
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
index 033c14264dd..0f06343958b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
@@ -1,8 +1,8 @@
// { dg-do compile { target c++11 } }
-struct A // { dg-error "non-static data member" }
+struct A
{
- int i = (A(), 42); // { dg-message "required here" }
+ int i = (A(), 42); // { dg-error "constructor required" }
};
A a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C
new file mode 100644
index 00000000000..061af8b8c29
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C
@@ -0,0 +1,7 @@
+// DR 1397
+// { dg-require-effective-target c++11 }
+
+struct A
+{
+ int i = sizeof(A{}); // { dg-error "" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
index edcf5887db1..9bc632c4bc7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
@@ -1,5 +1,5 @@
// Core issue 1351
-// { dg-do run { xfail *-*-* } }
+// { dg-do run }
// { dg-require-effective-target c++11 }
bool fail;