From: Jason Merrill Date: Wed, 9 Aug 2017 18:32:02 +0000 (-0400) Subject: PR c++/81359 - Unparsed NSDMI error from SFINAE context. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9fb82e652cee118b5c9d77e1e60a351a37a55dc8;p=gcc.git PR c++/81359 - Unparsed NSDMI error from SFINAE context. * init.c (get_nsdmi): Add complain parm. * typeck2.c (digest_nsdmi_init): Add complain parm. (process_init_constructor_record): Pass complain to get_nsdmi. * pt.c (maybe_instantiate_noexcept): Add complain parm, return bool. * method.c (get_defaulted_eh_spec): Add complain parm. Pass it into synthesized_method_walk. (synthesized_method_walk): Adjust. (walk_field_subobs): Pass complain to get_nsdmi. (defaulted_late_check): Skip other checks if deleted. * decl2.c (mark_used): Pass complain to maybe_instantiate_noexcept. * call.c (build_aggr_conv): Pass complain to get_nsdmi. * parser.c (defarg_location): New. * error.c (location_of): Use it. From-SVN: r250994 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c28336f45d7..5476c1135b6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2017-08-09 Jason Merrill + + PR c++/81359 - Unparsed NSDMI error from SFINAE context. + * init.c (get_nsdmi): Add complain parm. + * typeck2.c (digest_nsdmi_init): Add complain parm. + (process_init_constructor_record): Pass complain to get_nsdmi. + * pt.c (maybe_instantiate_noexcept): Add complain parm, return bool. + * method.c (get_defaulted_eh_spec): Add complain parm. Pass it into + synthesized_method_walk. + (synthesized_method_walk): Adjust. + (walk_field_subobs): Pass complain to get_nsdmi. + (defaulted_late_check): Skip other checks if deleted. + * decl2.c (mark_used): Pass complain to maybe_instantiate_noexcept. + * call.c (build_aggr_conv): Pass complain to get_nsdmi. + * parser.c (defarg_location): New. + * error.c (location_of): Use it. + 2017-08-09 Marek Polacek * parser.c (cp_parser_perform_range_for_lookup): Use false instead of 0. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index fdd373116e0..4903119adca 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -916,7 +916,7 @@ build_aggr_conv (tree type, tree ctor, int flags, tsubst_flags_t complain) if (i < CONSTRUCTOR_NELTS (ctor)) val = CONSTRUCTOR_ELT (ctor, i)->value; else if (DECL_INITIAL (field)) - val = get_nsdmi (field, /*ctor*/false); + val = get_nsdmi (field, /*ctor*/false, complain); else if (TREE_CODE (ftype) == REFERENCE_TYPE) /* Value-initialization of reference is ill-formed. */ return NULL; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 508570bdb04..94738bd8f78 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -8093,8 +8093,9 @@ resolve_address_of_overloaded_function (tree target_type, continue; /* In C++17 we need the noexcept-qualifier to compare types. */ - if (flag_noexcept_type) - maybe_instantiate_noexcept (fn); + if (flag_noexcept_type + && !maybe_instantiate_noexcept (fn, complain)) + continue; /* See if there's a match. */ tree fntype = static_fn_type (fn); @@ -8176,7 +8177,7 @@ resolve_address_of_overloaded_function (tree target_type, /* In C++17 we need the noexcept-qualifier to compare types. */ if (flag_noexcept_type) - maybe_instantiate_noexcept (instantiation); + maybe_instantiate_noexcept (instantiation, complain); /* See if there's a match. */ tree fntype = static_fn_type (instantiation); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 115cdaff61e..3a0bd1687e8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6297,7 +6297,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 get_nsdmi (tree, bool, tsubst_flags_t); extern tree build_offset_ref (tree, tree, bool, tsubst_flags_t); extern tree throw_bad_array_new_length (void); @@ -6355,7 +6355,7 @@ extern bool trivial_fn_p (tree); extern tree forward_parm (tree); extern bool is_trivially_xible (enum tree_code, tree, tree); extern bool is_xible (enum tree_code, tree, tree); -extern tree get_defaulted_eh_spec (tree); +extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); extern void after_nsdmi_defaulted_late_checks (tree); extern bool maybe_explain_implicit_delete (tree); extern void explain_implicit_non_constexpr (tree); @@ -6385,6 +6385,7 @@ extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool); extern bool parsing_nsdmi (void); extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); +extern location_t defarg_location (tree); /* in pt.c */ extern bool check_template_shadow (tree); @@ -6448,7 +6449,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 bool maybe_instantiate_noexcept (tree, tsubst_flags_t = tf_warning_or_error); extern tree instantiate_decl (tree, bool, bool); extern int comp_template_parms (const_tree, const_tree); extern bool builtin_pack_fn_p (tree); @@ -7166,7 +7167,7 @@ extern tree split_nonconstant_init (tree, tree); extern bool check_narrowing (tree, tree, tsubst_flags_t); extern tree digest_init (tree, tree, tsubst_flags_t); extern tree digest_init_flags (tree, tree, int, tsubst_flags_t); -extern tree digest_nsdmi_init (tree, tree); +extern tree digest_nsdmi_init (tree, tree, tsubst_flags_t); extern tree build_scoped_ref (tree, tree, tree *); extern tree build_x_arrow (location_t, tree, tsubst_flags_t); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2a52f8ca3e2..8187ab9317d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4988,8 +4988,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 + && !maybe_instantiate_noexcept (decl, complain)) + return false; if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DELETED_FN (decl)) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 2497c7f6d23..31ca8fe1eb2 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3046,6 +3046,8 @@ location_of (tree t) if (DECL_P (t)) return DECL_SOURCE_LOCATION (t); + if (TREE_CODE (t) == DEFAULT_ARG) + return defarg_location (t); return EXPR_LOC_OR_LOC (t, input_location); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 81804112fd0..83e685c0011 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -536,7 +536,7 @@ perform_target_ctor (tree init) /* Return the non-static data initializer for FIELD_DECL MEMBER. */ tree -get_nsdmi (tree member, bool in_ctor) +get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) { tree init; tree save_ccp = current_class_ptr; @@ -554,50 +554,54 @@ get_nsdmi (tree member, bool in_ctor) { init = DECL_INITIAL (DECL_TI_TEMPLATE (member)); if (TREE_CODE (init) == DEFAULT_ARG) - goto unparsed; - + /* Unparsed. */; /* Check recursive instantiation. */ - if (DECL_INSTANTIATING_NSDMI_P (member)) + else if (DECL_INSTANTIATING_NSDMI_P (member)) { - error ("recursive instantiation of non-static data member " - "initializer for %qD", member); + if (complain & tf_error) + error ("recursive instantiation of default member " + "initializer for %qD", member); init = error_mark_node; } else { DECL_INSTANTIATING_NSDMI_P (member) = 1; - + /* Do deferred instantiation of the NSDMI. */ init = (tsubst_copy_and_build (init, DECL_TI_ARGS (member), - tf_warning_or_error, member, /*function_p=*/false, + complain, member, /*function_p=*/false, /*integral_constant_expression_p=*/false)); - init = digest_nsdmi_init (member, init); + init = digest_nsdmi_init (member, init, complain); DECL_INSTANTIATING_NSDMI_P (member) = 0; } } else + init = DECL_INITIAL (member); + + if (init && TREE_CODE (init) == DEFAULT_ARG) { - init = DECL_INITIAL (member); - if (init && TREE_CODE (init) == DEFAULT_ARG) + if (complain & tf_error) { - unparsed: - error ("constructor required before non-static data member " - "for %qD has been parsed", member); + error ("default member initializer for %qD required before the end " + "of its enclosing class", member); + inform (location_of (init), "defined here"); DECL_INITIAL (member) = error_mark_node; - init = error_mark_node; } - /* Strip redundant TARGET_EXPR so we don't need to remap it, and - so the aggregate init code below will see a CONSTRUCTOR. */ - bool simple_target = (init && SIMPLE_TARGET_EXPR_P (init)); - if (simple_target) - init = TARGET_EXPR_INITIAL (init); - init = break_out_target_exprs (init); - if (simple_target && TREE_CODE (init) != CONSTRUCTOR) - /* Now put it back so C++17 copy elision works. */ - init = get_target_expr (init); + init = error_mark_node; } + + /* Strip redundant TARGET_EXPR so we don't need to remap it, and + so the aggregate init code below will see a CONSTRUCTOR. */ + bool simple_target = (init && SIMPLE_TARGET_EXPR_P (init)); + if (simple_target) + init = TARGET_EXPR_INITIAL (init); + init = break_out_target_exprs (init); + if (simple_target && TREE_CODE (init) != CONSTRUCTOR) + /* Now put it back so C++17 copy elision works. */ + init = get_target_expr (init); + current_class_ptr = save_ccp; current_class_ref = save_ccr; return init; @@ -644,7 +648,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) - init = get_nsdmi (member, /*ctor*/true); + init = get_nsdmi (member, /*ctor*/true, tf_warning_or_error); if (init == error_mark_node) return; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 8b07f526473..bff960513c0 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1357,7 +1357,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, default constructor is noexcept(false). */ if (spec_p) { - tree nsdmi = get_nsdmi (field, /*ctor*/false); + tree nsdmi = get_nsdmi (field, /*ctor*/false, complain); if (!expr_noexcept_p (nsdmi, complain)) *spec_p = noexcept_false_spec; } @@ -1660,6 +1660,10 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, flags |= LOOKUP_DEFAULTED; tsubst_flags_t complain = diag ? tf_warning_or_error : tf_none; + if (diag && spec_p) + /* We're in get_defaulted_eh_spec; we don't actually want any walking + diagnostics, we just want complain set. */ + diag = false; int quals = const_p ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED; for (binfo = TYPE_BINFO (ctype), i = 0; @@ -1749,7 +1753,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, needed. Return what it should be. */ tree -get_defaulted_eh_spec (tree decl) +get_defaulted_eh_spec (tree decl, tsubst_flags_t complain) { if (DECL_CLONED_FUNCTION_P (decl)) decl = DECL_CLONED_FUNCTION (decl); @@ -1759,8 +1763,9 @@ get_defaulted_eh_spec (tree decl) tree parm_type = TREE_VALUE (parms); bool const_p = CP_TYPE_CONST_P (non_reference (parm_type)); tree spec = empty_except_spec; + bool diag = !DECL_DELETED_FN (decl) && (complain & tf_error); synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL, - NULL, false, DECL_INHERITED_CTOR (decl), + NULL, diag, DECL_INHERITED_CTOR (decl), parms); return spec; } @@ -2173,6 +2178,12 @@ defaulted_late_check (tree fn) "does not match expected signature %qD", implicit_fn); } + if (DECL_DELETED_FN (implicit_fn)) + { + DECL_DELETED_FN (fn) = 1; + return; + } + /* 8.4.2/2: An explicitly-defaulted function (...) may have an explicit exception-specification only if it is compatible (15.4) with the exception-specification on the implicit declaration. If a function @@ -2231,9 +2242,6 @@ defaulted_late_check (tree fn) } DECL_DECLARED_CONSTEXPR_P (fn) = false; } - - if (DECL_DELETED_FN (implicit_fn)) - DECL_DELETED_FN (fn) = 1; } /* OK, we've parsed the NSDMI for class T, now we can check any explicit diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 28f32888312..9d989a7f84f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -27431,7 +27431,7 @@ cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl, else if (maybe_reject_flexarray_init (decl, parsed_arg)) parsed_arg = error_mark_node; else - parsed_arg = digest_nsdmi_init (decl, parsed_arg); + parsed_arg = digest_nsdmi_init (decl, parsed_arg, tf_warning_or_error); } /* If the token stream has not been completely used up, then @@ -28681,6 +28681,17 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) return default_argument; } +/* A location to use for diagnostics about an unparsed DEFAULT_ARG. */ + +location_t +defarg_location (tree default_argument) +{ + cp_token_cache *tokens = DEFARG_TOKENS (default_argument); + location_t start = tokens->first->location; + location_t end = tokens->last->location; + return make_location (start, start, end); +} + /* Begin parsing tentatively. We always save tokens while parsing tentatively so that if the tentative parsing fails we can restore the tokens. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bd61438fc39..3d6f4b512b5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -22493,16 +22493,17 @@ always_instantiate_p (tree decl) } /* If FN has a noexcept-specifier that hasn't been instantiated yet, - instantiate it now, modifying TREE_TYPE (fn). */ + instantiate it now, modifying TREE_TYPE (fn). Returns false on + error, true otherwise. */ -void -maybe_instantiate_noexcept (tree fn) +bool +maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) { tree fntype, spec, noex, clone; /* Don't instantiate a noexcept-specification from template context. */ if (processing_template_decl) - return; + return true; if (DECL_CLONED_FUNCTION_P (fn)) fn = DECL_CLONED_FUNCTION (fn); @@ -22510,7 +22511,7 @@ maybe_instantiate_noexcept (tree fn) spec = TYPE_RAISES_EXCEPTIONS (fntype); if (!spec || !TREE_PURPOSE (spec)) - return; + return true; noex = TREE_PURPOSE (spec); @@ -22519,7 +22520,7 @@ maybe_instantiate_noexcept (tree fn) static hash_set* fns = new hash_set; bool added = false; if (DEFERRED_NOEXCEPT_PATTERN (noex) == NULL_TREE) - spec = get_defaulted_eh_spec (fn); + spec = get_defaulted_eh_spec (fn, complain); else if (!(added = !fns->add (fn))) { /* If hash_set::add returns true, the element was already there. */ @@ -22553,6 +22554,9 @@ maybe_instantiate_noexcept (tree fn) if (added) fns->remove (fn); + if (spec == error_mark_node) + return false; + TREE_TYPE (fn) = build_exception_variant (fntype, spec); } @@ -22563,6 +22567,8 @@ maybe_instantiate_noexcept (tree fn) else TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec); } + + return true; } /* Produce the definition of D, a _DECL generated from a template. If diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 430ba30536a..06c079e41be 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1182,7 +1182,7 @@ digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain) /* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL). */ tree -digest_nsdmi_init (tree decl, tree init) +digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) { gcc_assert (TREE_CODE (decl) == FIELD_DECL); @@ -1192,8 +1192,8 @@ digest_nsdmi_init (tree decl, tree init) flags = LOOKUP_NORMAL; if (BRACE_ENCLOSED_INITIALIZER_P (init) && CP_AGGREGATE_TYPE_P (type)) - init = reshape_init (type, init, tf_warning_or_error); - init = digest_init_flags (type, init, flags, tf_warning_or_error); + init = reshape_init (type, init, complain); + init = digest_init_flags (type, init, flags, complain); if (TREE_CODE (init) == TARGET_EXPR) /* This represents the whole initialization. */ TARGET_EXPR_DIRECT_INIT_P (init) = true; @@ -1427,7 +1427,7 @@ process_init_constructor_record (tree type, tree init, goto restart; } /* C++14 aggregate NSDMI. */ - next = get_nsdmi (field, /*ctor*/false); + next = get_nsdmi (field, /*ctor*/false, complain); } else if (type_build_ctor_call (TREE_TYPE (field))) { @@ -1525,7 +1525,8 @@ process_init_constructor_union (tree type, tree init, { CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init), field, - get_nsdmi (field, /*in_ctor=*/false)); + get_nsdmi (field, /*in_ctor=*/false, + complain)); break; } } diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C index 0f06343958b..056d16dca4a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C @@ -2,7 +2,7 @@ struct A { - int i = (A(), 42); // { dg-error "constructor required" } + int i = (A(), 42); // { dg-error "" } }; A a; diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C index 1a00ec0d6a9..a885a241279 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C @@ -3,14 +3,14 @@ template struct A { - int i = (A<0>(), 0); // { dg-error "recursive instantiation of non-static data" } + int i = (A<0>(), 0); // { dg-error "recursive instantiation of default" } }; A<0> a; template struct B { - B* p = new B; // { dg-error "recursive instantiation of non-static data" } + B* p = new B; // { dg-error "recursive instantiation of default" } }; B<1> x; diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C index 56f9ff08bdf..d8588b7f29e 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C @@ -6,7 +6,7 @@ struct A1 { int y1 = 1; }; - A1(const B1& opts = B1()) {} // { dg-error "constructor" } + A1(const B1& opts = B1()) {} // { dg-error "default member initializer" } }; struct A2 { @@ -14,5 +14,5 @@ struct A2 { int x2, y2 = 1; }; - A2(const B2& opts = B2()) {} // { dg-error "constructor" } + A2(const B2& opts = B2()) {} // { dg-error "default member initializer" } }; diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae59.C b/gcc/testsuite/g++.dg/cpp0x/sfinae59.C new file mode 100644 index 00000000000..d1c730b6d23 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae59.C @@ -0,0 +1,19 @@ +// PR c++/81359 +// { dg-do compile { target c++11 } } + +template +static int test(int); + +template +static void test(...); + +template (0))> +struct A { }; + +struct B +{ + struct C { + int i = 0; + }; + A a; +};