diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 04ae0de3260..7b68b139599 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2017-03-02 Jason Merrill + + Allow deduction guides to look into primary template. + * cp-tree.h (struct saved_scope): Add deduction_guide_type. + (struct cp_decl_specifier_seq): Add constructor_p. + * parser.c (cp_parser_decl_specifier_seq): Set constructor_p. + (cp_parser_init_declarator): Check it. Set ctor_dtor_or_conv_p. + Clear deduction_guide_type. Don't handle deduction guide names. + (cp_parser_declarator): Don't clear ctor_dtor_or_conv_p. + (cp_parser_direct_declarator): Likewise. Handle deduction guides. + (cp_parser_member_declaration, cp_parser_cache_defarg) + (cp_parser_objc_class_ivars): Set ctor_dtor_or_conv_p. + * pt.c (tsubst_copy, tsubst_copy_and_build): Revert last change. + (build_deduction_guide): Set deduction_guide_type. + (dependent_scope_p): Check deduction_guide_type. + * search.c (lookup_member): Likewise. + 2017-03-02 Jakub Jelinek PR c++/79782 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f53f7442bc9..31edc5f175b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1272,6 +1272,7 @@ struct GTY(()) saved_scope { vec *lang_base; tree lang_name; tree template_parms; + tree deduction_guide_type; cp_binding_level *x_previous_class_level; tree x_saved_tree; @@ -5422,6 +5423,9 @@ struct cp_decl_specifier_seq { BOOL_BITFIELD gnu_thread_keyword_p : 1; /* True iff the type is a decltype. */ BOOL_BITFIELD decltype_p : 1; + /* True iff the declaration declares a constructor or C++17 deduction + guide. */ + BOOL_BITFIELD constructor_p : 1; }; /* The various kinds of declarators. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e6848701150..fbe864f685a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13313,6 +13313,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser, && constructor_possible_p && (cp_parser_constructor_declarator_p (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend)))); + if (constructor_p) + decl_specs->constructor_p = true; /* If we don't have a DECL_SPEC yet, then we must be looking at a type-specifier. */ @@ -19010,7 +19012,7 @@ cp_parser_init_declarator (cp_parser* parser, enum cpp_ttype initialization_kind; bool is_direct_init = false; bool is_non_constant_init; - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = decl_specifiers->constructor_p ? -1 : 0; bool friend_p = cp_parser_friend_p (decl_specifiers); tree pushed_scope = NULL_TREE; bool range_for_decl_p = false; @@ -19048,6 +19050,9 @@ cp_parser_init_declarator (cp_parser* parser, parser->default_arg_ok_p = saved_default_arg_ok_p; + if (cxx_dialect >= cxx1z) + scope_chain->deduction_guide_type = NULL_TREE; + /* If the DECLARATOR was erroneous, there's no need to go further. */ if (declarator == cp_error_declarator) @@ -19095,25 +19100,6 @@ cp_parser_init_declarator (cp_parser* parser, if (function_declarator_p (declarator)) { - /* Handle C++17 deduction guides. */ - if (!decl_specifiers->type - && ctor_dtor_or_conv_p <= 0 - && cxx_dialect >= cxx1z) - { - cp_declarator *id = get_id_declarator (declarator); - tree name = id->u.id.unqualified_name; - parser->scope = id->u.id.qualifying_scope; - tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); - if (tmpl - && (DECL_CLASS_TEMPLATE_P (tmpl) - || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) - { - id->u.id.unqualified_name = dguide_name (tmpl); - id->u.id.sfk = sfk_deduction_guide; - ctor_dtor_or_conv_p = 1; - } - } - /* Check to see if the token indicates the start of a function-definition. */ if (cp_parser_token_starts_function_definition_p (token)) @@ -19432,8 +19418,10 @@ cp_parser_init_declarator (cp_parser* parser, If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to detect constructors, destructors, deduction guides, or conversion operators. - It is set to -1 if the declarator is a name, and +1 if it is a - function. Otherwise it is set to zero. Usually you just want to + The caller should set it before the call, to -1 if parsing the + decl-specifier-seq determined that we're declaring a constructor or + deduction guide, or 0 otherwise. This function sets it to -1 if the + declarator is a name, and +1 if it is a function. Usually you just want to test for >0, but internally the negative value is used. (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have @@ -19464,11 +19452,6 @@ cp_parser_declarator (cp_parser* parser, tree class_type; tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE; - /* Assume this is not a constructor, destructor, or type-conversion - operator. */ - if (ctor_dtor_or_conv_p) - *ctor_dtor_or_conv_p = 0; - if (cp_parser_allow_gnu_extensions_p (parser)) gnu_attributes = cp_parser_gnu_attributes_opt (parser); @@ -19766,9 +19749,6 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse an array-declarator. */ tree bounds, attrs; - if (ctor_dtor_or_conv_p) - *ctor_dtor_or_conv_p = 0; - first = false; parser->default_arg_ok_p = false; parser->in_declarator_p = true; @@ -20023,6 +20003,34 @@ cp_parser_direct_declarator (cp_parser* parser, *ctor_dtor_or_conv_p = -1; } } + + if (cxx_dialect >= cxx1z + && sfk == sfk_none + && ctor_dtor_or_conv_p + && *ctor_dtor_or_conv_p == -1) + { + /* If *ctor_dtor_or_conv_p is set and we aren't declaring a + constructor, we must be declaring a deduction guide. */ + tree tmpl; + if (qualifying_scope) + tmpl = (lookup_qualified_name + (qualifying_scope, unqualified_name, + /*prefer_type*/false, /*complain*/true)); + else + tmpl = lookup_name (unqualified_name); + if (tmpl + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) + { + unqualified_name = dguide_name (tmpl); + scope_chain->deduction_guide_type + = TREE_TYPE (unqualified_name); + sfk = sfk_deduction_guide; + } + else + gcc_checking_assert (false); + } + declarator = make_id_declarator (qualifying_scope, unqualified_name, sfk); @@ -23251,7 +23259,7 @@ cp_parser_member_declaration (cp_parser* parser) cp_declarator *declarator; tree initializer; tree asm_specification; - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = decl_specifiers.constructor_p ? -1 : 0; /* Parse the declarator. */ declarator @@ -28334,7 +28342,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) declarator. */ do { - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = 0; cp_lexer_consume_token (parser->lexer); cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, &ctor_dtor_or_conv_p, @@ -29655,7 +29663,7 @@ cp_parser_objc_class_ivars (cp_parser* parser) { tree width = NULL_TREE, attributes, first_attribute, decl; cp_declarator *declarator = NULL; - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = 0; /* Check for a (possibly unnamed) bitfield declaration. */ token = cp_lexer_peek_token (parser->lexer); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8144ca66a01..3b320fc2b48 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14641,15 +14641,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) have to substitute this with one having context `D'. */ tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl); - if (dependent_scope_p (context)) - { - /* When rewriting a constructor into a deduction guide, a - non-dependent name can become dependent, so memtmpl - becomes context::template memtmpl. */ - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - return build_qualified_name (type, context, DECL_NAME (t), - /*template*/true); - } return lookup_field (context, DECL_NAME(t), 0, false); } else @@ -16633,14 +16624,6 @@ tsubst_copy_and_build (tree t, if (targs == error_mark_node) return error_mark_node; - if (TREE_CODE (templ) == SCOPE_REF) - { - tree name = TREE_OPERAND (templ, 1); - tree tid = lookup_template_function (name, targs); - TREE_OPERAND (templ, 1) = tid; - return templ; - } - if (variable_template_p (templ)) RETURN (lookup_and_finish_template_variable (templ, targs, complain)); @@ -23476,6 +23459,9 @@ bool dependent_scope_p (tree scope) { return (scope && TYPE_P (scope) && dependent_type_p (scope) + && !(cxx_dialect >= cxx1z + && scope_chain->deduction_guide_type + && same_type_p (scope, scope_chain->deduction_guide_type)) && !currently_open_class (scope)); } @@ -24997,6 +24983,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) if (outer_args) ctor = tsubst (ctor, outer_args, complain, ctor); type = DECL_CONTEXT (ctor); + scope_chain->deduction_guide_type = type; tree fn_tmpl; if (TREE_CODE (ctor) == TEMPLATE_DECL) { @@ -25089,6 +25076,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) current_template_parms = save_parms; --processing_template_decl; } + scope_chain->deduction_guide_type = NULL_TREE; } if (!memtmpl) diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 09c1b4e6456..6eb41243814 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1279,6 +1279,13 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type, if (tree t = currently_open_class (type)) type = t; + /* Declaration of a deduction guide can look inside the primary class + template; replace a compatible type with the real one. */ + if (cxx_dialect >= cxx1z + && scope_chain->deduction_guide_type + && same_type_p (type, scope_chain->deduction_guide_type)) + type = scope_chain->deduction_guide_type; + if (!basetype_path) basetype_path = TYPE_BINFO (type); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C new file mode 100644 index 00000000000..ee21d147fd6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C @@ -0,0 +1,16 @@ +// { dg-options -std=c++1z } + +template struct A +{ + using value_t = T; + A(value_t); +}; + +template +A(typename A::value_t) -> A; + +template struct same; +template struct same {}; + +A a(42); +same> s1;