From patchwork Tue Oct 4 20:42:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 678204 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3spW8P11N1z9s9Y for ; Wed, 5 Oct 2016 07:43:07 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=wzsVKqpB; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=osM/iMknbJnjCPD120x9OxRxNzhm5yq5glxJCnlWUVfW/o V7Y+g7pGYt8GrQ+arQskEbFNQUUyQsEgKlLVMZB4FzOcqdyjiD40fEtPVtfT9Iej a+Pb1Dm/RCMoEoSn0waSsvQc8b4Xn2s2/C9Bn3kXpf5JgwZTtmCiLq3M0Eh7w= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=+/LD+wMk2bOZkf3SsmrGsr0ELo8=; b=wzsVKqpBZzTGVEleXmJz /khvizzLtsz0H8IVmZfmSsudG/pWbh3GSIEtuOY7zb3HcT9TwQy69p+sem3Dl1oy TE+30dkIJerNgxQBE+re6pmNrLaXC3C87xe10gBtB1PbQDHrzcLLWKOUL7KHvQA8 He61MJw0pYeH/VsTtU7qVO8= Received: (qmail 39626 invoked by alias); 4 Oct 2016 20:42:58 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 39611 invoked by uid 89); 4 Oct 2016 20:42:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.0 required=5.0 tests=AWL, BAYES_50, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM autolearn=no version=3.3.2 spammy=tuv, TUV, concepts, TUP X-HELO: mail-oi0-f54.google.com Received: from mail-oi0-f54.google.com (HELO mail-oi0-f54.google.com) (209.85.218.54) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 04 Oct 2016 20:42:53 +0000 Received: by mail-oi0-f54.google.com with SMTP id n132so184428258oih.1 for ; Tue, 04 Oct 2016 13:42:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=8+wCaqjj2TChNSrnS2iHvzTTI3p2aMIMJPA4MHDjMPg=; b=ASVJpw2lus+EsdYWDFMexDoYZBYmbrHQZPBJasRylb6mmf4ySAIQIjtx0Yvn8YYDy0 uClGS8ikl1gF1Ij4s/44ULeWztAT0o4jXER1PrcUINZhoNXDGb2v3ULZ5/fRAH9bkxYd d/l8IvlF83lh4X2OKVHTyTu7/mOl9slGipXK0B1k9sbImx9MrV9dWPZSGqeKM4SBTQWU ZWjp6ZVrU9kbFT9OtSZGV6Oc0PrBNV7SpNs9TU64LRqKhnAPKbwCqKUn/JFg7pSCgmhx bN82TPMSZXwbPdksmGeGBqrmyZa0cIhbbEOx+TbjWL1ijShuojywrIb8zP2hwn8hp6Eh a3ng== X-Gm-Message-State: AA6/9RlZl1j/sWuRQXg2mB2zgnhRCANPW2imVXITn3GpL1MLOUEJNEb6HYHi+KarVWI1HupxFllYSEjVrywvd8mu X-Received: by 10.202.192.69 with SMTP id q66mr5036620oif.52.1475613770109; Tue, 04 Oct 2016 13:42:50 -0700 (PDT) MIME-Version: 1.0 Received: by 10.182.105.167 with HTTP; Tue, 4 Oct 2016 13:42:29 -0700 (PDT) From: Jason Merrill Date: Tue, 4 Oct 2016 16:42:29 -0400 Message-ID: Subject: C++ PATCH for C++17 class template placeholders To: gcc-patches List X-IsSubscribed: yes C++17 adds the ability to omit the template arguments for a class template when declaring a variable with an initializer, much like auto but supporting a wider variety of initialization. This is intended to replace functions like make_tuple. Tested x86_64-pc-linux-gnu, applying to trunk. commit beb368fa92a6eb8b55809ab442f59e2fca071cb7 Author: Jason Merrill Date: Tue Oct 4 16:03:17 2016 -0400 Implement P0091R2, Template argument deduction for class templates. * parser.c (cp_parser_simple_type_specifier): Parse class placeholder. Use the location of the beginning of the type-specifier. (cp_parser_init_declarator): Parse deduction guide. (cp_parser_diagnose_invalid_type_name): Mention class deduction. (cp_parser_type_id_1): Don't accept class placeholder as template arg. * cp-tree.h (CLASS_PLACEHOLDER_TEMPLATE): New. * decl.c (grokdeclarator): Check for uninitialized auto here. (start_decl_1): Not here. (cp_finish_decl): Or here. Don't collapse a list when doing class deduction. (grokfndecl): Check deduction guide scope and body. * error.c (dump_decl, dump_function_decl, dump_function_name): Handle deduction guides. * pt.c (make_template_placeholder, do_class_deduction): New. (build_deduction_guide, rewrite_template_parm): New. (dguide_name, dguide_name_p, deduction_guide_p): New. (do_auto_deduction): Call do_class_deduction. (splice_late_return_type, is_auto): Handle class placeholders. (template_parms_level_to_args): Split from template_parms_to_args. (tsubst_template_parms_level): Split from tsubst_template_parms. * typeck2.c (build_functional_cast): Handle class placeholder. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 85702c5..3fbe1d9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1199,6 +1199,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER] /* The name of the std namespace. */ #define std_identifier cp_global_trees[CPTI_STD_IDENTIFIER] +/* The name of a C++17 deduction guide. */ #define lang_name_c cp_global_trees[CPTI_LANG_NAME_C] #define lang_name_cplusplus cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS] @@ -5104,6 +5105,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; #define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \ (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE))) +/* For a C++17 class deduction placeholder, the template it represents. */ +#define CLASS_PLACEHOLDER_TEMPLATE(NODE) \ + (DECL_INITIAL (TYPE_NAME (TEMPLATE_TYPE_PARM_CHECK (NODE)))) + /* Contexts in which auto deduction occurs. These flags are used to control diagnostics in do_auto_deduction. */ @@ -6027,6 +6032,7 @@ extern int num_template_headers_for_class (tree); extern void check_template_variable (tree); extern tree make_auto (void); extern tree make_decltype_auto (void); +extern tree make_template_placeholder (tree); extern tree do_auto_deduction (tree, tree, tree); extern tree do_auto_deduction (tree, tree, tree, tsubst_flags_t, @@ -6158,6 +6164,9 @@ extern void register_local_specialization (tree, tree); extern tree retrieve_local_specialization (tree); extern tree extract_fnparm_pack (tree, tree *); extern tree template_parm_to_arg (tree); +extern tree dguide_name (tree); +extern bool dguide_name_p (tree); +extern bool deduction_guide_p (tree); /* in repo.c */ extern void init_repo (void); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c8f7666..6646062 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5140,7 +5140,7 @@ start_decl_1 (tree decl, bool initialized) else if (aggregate_definition_p && !complete_p) { if (type_uses_auto (type)) - error ("declaration of %q#D has no initializer", decl); + gcc_unreachable (); else error ("aggregate %q#D has incomplete type and cannot be defined", decl); @@ -6695,12 +6695,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, return; } - error ("declaration of %q#D has no initializer", decl); - TREE_TYPE (decl) = error_mark_node; - return; + gcc_unreachable (); } d_init = init; - if (TREE_CODE (d_init) == TREE_LIST) + if (TREE_CODE (d_init) == TREE_LIST + && !CLASS_PLACEHOLDER_TEMPLATE (auto_node)) d_init = build_x_compound_expr_from_list (d_init, ELK_INIT, tf_warning_or_error); d_init = resolve_nondeduced_context (d_init, tf_warning_or_error); @@ -8182,7 +8181,27 @@ grokfndecl (tree ctype, } } - if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)) + if (deduction_guide_p (decl)) + { + if (!DECL_NAMESPACE_SCOPE_P (decl)) + { + error_at (location, "deduction guide %qD must be declared at " + "namespace scope", decl); + return NULL_TREE; + } + tree type = TREE_TYPE (DECL_NAME (decl)); + if (CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type)) + { + error_at (location, "deduction guide %qD must be declared in the " + "same scope as %qT", decl, type); + inform (location_of (type), " declared here"); + return NULL_TREE; + } + if (funcdef_flag) + error_at (location, + "deduction guide %qD must not have a function body", decl); + } + else if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)) && !grok_op_properties (decl, /*complain=*/true)) return NULL_TREE; else if (UDLIT_OPER_P (DECL_NAME (decl))) @@ -11063,12 +11082,19 @@ grokdeclarator (const cp_declarator *declarator, } else if (decl_context == FIELD) { - if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE - && type_uses_auto (type)) - { - error ("non-static data member declared %"); - type = error_mark_node; - } + if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE) + if (tree auto_node = type_uses_auto (type)) + { + location_t loc = declspecs->locations[ds_type_spec]; + if (CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + error_at (loc, "invalid use of template-name %qE without an " + "argument list", + CLASS_PLACEHOLDER_TEMPLATE (auto_node)); + else + error_at (loc, "non-static data member declared with " + "placeholder %qT", auto_node); + type = error_mark_node; + } /* The C99 flexible array extension. */ if (!staticp && TREE_CODE (type) == ARRAY_TYPE @@ -11543,6 +11569,22 @@ grokdeclarator (const cp_declarator *declarator, } } + if (VAR_P (decl) && !initialized) + if (tree auto_node = type_uses_auto (type)) + { + location_t loc = declspecs->locations[ds_type_spec]; + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + { + error_at (loc, "invalid use of template-name %qE without an " + "argument list", tmpl); + inform (loc, "class template argument deduction " + "requires an initializer"); + } + else + error_at (loc, "declaration of %q#D has no initializer", decl); + TREE_TYPE (decl) = error_mark_node; + } + if (storage_class == sc_extern && initialized && !funcdef_flag) { if (toplevel_bindings_p ()) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 745d7ba..20b20b4 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1159,6 +1159,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) dump_type (pp, TREE_TYPE (t), flags); break; } + else if (dguide_name_p (t)) + dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)), + TFF_PLAIN_IDENTIFIER); else pp_cxx_tree_identifier (pp, t); break; @@ -1552,8 +1555,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) /* Print the return type? */ if (show_return) - show_return = !DECL_CONV_FN_P (t) && !DECL_CONSTRUCTOR_P (t) - && !DECL_DESTRUCTOR_P (t); + show_return = (!DECL_CONV_FN_P (t) && !DECL_CONSTRUCTOR_P (t) + && !DECL_DESTRUCTOR_P (t) && !deduction_guide_p (t)); if (show_return) { tree ret = fndecl_declared_return_type (t); @@ -1598,6 +1601,11 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (show_return) dump_type_suffix (pp, TREE_TYPE (fntype), flags); + else if (deduction_guide_p (t)) + { + pp_cxx_ws_string (pp, "->"); + dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags); + } if (flag_concepts) if (tree ci = get_constraints (t)) @@ -1767,10 +1775,6 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags) pp_cxx_ws_string (pp, "operator"); dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags); } - else if (name && IDENTIFIER_OPNAME_P (name)) - pp_cxx_tree_identifier (pp, name); - else if (name && UDLIT_OPER_P (name)) - pp_cxx_tree_identifier (pp, name); else dump_decl (pp, name, flags); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8581375..683a6dd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3155,6 +3155,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, error_at (location, "invalid use of template-name %qE without an argument list", decl); + if (DECL_CLASS_TEMPLATE_P (decl) && cxx_dialect < cxx1z) + inform (location, "class template argument deduction is only available " + "with -std=c++1z or -std=gnu++1z"); inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); } else if (TREE_CODE (id) == BIT_NOT_EXPR) @@ -12224,6 +12227,9 @@ cp_parser_declaration_seq_opt (cp_parser* parser) linkage-specification namespace-definition + C++17: + deduction-guide + GNU extension: declaration: @@ -16150,7 +16156,7 @@ cp_parser_type_specifier (cp_parser* parser, double void - C++0x Extension: + C++11 Extension: simple-type-specifier: auto @@ -16159,6 +16165,10 @@ cp_parser_type_specifier (cp_parser* parser, char32_t __underlying_type ( type-id ) + C++17 extension: + + nested-name-specifier(opt) template-name + GNU Extension: simple-type-specifier: @@ -16429,9 +16439,11 @@ cp_parser_simple_type_specifier (cp_parser* parser, /* Don't gobble tokens or issue error messages if this is an optional type-specifier. */ - if (flags & CP_PARSER_FLAGS_OPTIONAL) + if ((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx1z) cp_parser_parse_tentatively (parser); + token = cp_lexer_peek_token (parser->lexer); + /* Look for the optional `::' operator. */ global_p = (cp_parser_global_scope_opt (parser, @@ -16445,7 +16457,6 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*type_p=*/false, /*is_declaration=*/false) != NULL_TREE); - token = cp_lexer_peek_token (parser->lexer); /* If we have seen a nested-name-specifier, and the next token is `template', then we are using the template-id production. */ if (parser->scope @@ -16476,9 +16487,50 @@ cp_parser_simple_type_specifier (cp_parser* parser, && identifier_p (DECL_NAME (type))) maybe_note_name_used_in_class (DECL_NAME (type), type); /* If it didn't work out, we don't have a TYPE. */ - if ((flags & CP_PARSER_FLAGS_OPTIONAL) + if (((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx1z) && !cp_parser_parse_definitely (parser)) type = NULL_TREE; + if (!type && cxx_dialect >= cxx1z) + { + if (flags & CP_PARSER_FLAGS_OPTIONAL) + cp_parser_parse_tentatively (parser); + + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false); + cp_parser_nested_name_specifier_opt (parser, + /*typename_keyword_p=*/false, + /*check_dependency_p=*/true, + /*type_p=*/false, + /*is_declaration=*/false); + tree name = cp_parser_identifier (parser); + if (name && TREE_CODE (name) == IDENTIFIER_NODE + && parser->scope != error_mark_node) + { + tree tmpl = cp_parser_lookup_name (parser, name, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true, + /*ambiguous_decls=*/NULL, + token->location); + if (tmpl && tmpl != error_mark_node + && DECL_CLASS_TEMPLATE_P (tmpl)) + type = make_template_placeholder (tmpl); + else + { + type = error_mark_node; + if (!cp_parser_simulate_error (parser)) + cp_parser_name_lookup_error (parser, name, tmpl, + NLE_TYPE, token->location); + } + } + else + type = error_mark_node; + + if ((flags & CP_PARSER_FLAGS_OPTIONAL) + && !cp_parser_parse_definitely (parser)) + type = NULL_TREE; + } if (type && decl_specs) cp_parser_set_decl_spec_type (decl_specs, type, token, @@ -18577,10 +18629,28 @@ cp_parser_init_declarator (cp_parser* parser, declared. */ resume_deferring_access_checks (); + token = cp_lexer_peek_token (parser->lexer); + + cp_parser_declarator_kind cdk = CP_PARSER_DECLARATOR_NAMED; + if (token->type == CPP_OPEN_PAREN + && decl_specifiers->type + && is_auto (decl_specifiers->type) + && CLASS_PLACEHOLDER_TEMPLATE (decl_specifiers->type)) + { + // C++17 deduction guide. + cdk = CP_PARSER_DECLARATOR_ABSTRACT; + + for (int i = 0; i < ds_last; ++i) + if (i != ds_type_spec + && decl_specifiers->locations[i] + && !cp_parser_simulate_error (parser)) + error_at (decl_specifiers->locations[i], + "decl-specifier in declaration of deduction guide"); + } + /* Parse the declarator. */ - token = cp_lexer_peek_token (parser->lexer); declarator - = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + = cp_parser_declarator (parser, cdk, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, member_p, friend_p); @@ -18594,6 +18664,17 @@ cp_parser_init_declarator (cp_parser* parser, if (declarator == cp_error_declarator) return error_mark_node; + if (cdk == CP_PARSER_DECLARATOR_ABSTRACT) + { + gcc_assert (declarator->kind == cdk_function + && !declarator->declarator); + tree t = CLASS_PLACEHOLDER_TEMPLATE (decl_specifiers->type); + declarator->declarator = make_id_declarator (NULL_TREE, dguide_name (t), + sfk_none); + declarator->declarator->id_loc + = decl_specifiers->locations[ds_type_spec]; + } + /* Check that the number of template-parameter-lists is OK. */ if (!cp_parser_check_declarator_template_parameters (parser, declarator, token->location)) @@ -20118,6 +20199,16 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, is_trailing_return, &type_specifier_seq); + if (is_template_arg && type_specifier_seq.type + && TREE_CODE (type_specifier_seq.type) == TEMPLATE_TYPE_PARM + && CLASS_PLACEHOLDER_TEMPLATE (type_specifier_seq.type)) + /* A bare template name as a template argument is a template template + argument, not a placeholder, so fail parsing it as a type argument. */ + { + gcc_assert (cp_parser_uncommitted_to_tentative_parse_p (parser)); + cp_parser_simulate_error (parser); + return error_mark_node; + } if (type_specifier_seq.type == error_mark_node) return error_mark_node; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2fd1aac..f923666 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4272,6 +4272,23 @@ template_parm_to_arg (tree t) return t; } +/* Given a single level of template parameters (a TREE_VEC), return it + as a set of template arguments. */ + +static tree +template_parms_level_to_args (tree parms) +{ + tree a = copy_node (parms); + TREE_TYPE (a) = NULL_TREE; + for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) + TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i)); + + if (CHECKING_P) + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a)); + + return a; +} + /* Given a set of template parameters, return them as a set of template arguments. The template parameters are represented as a TREE_VEC, in the form documented in cp-tree.h for template arguments. */ @@ -4292,15 +4309,7 @@ template_parms_to_args (tree parms) for (header = parms; header; header = TREE_CHAIN (header)) { - tree a = copy_node (TREE_VALUE (header)); - int i; - - TREE_TYPE (a) = NULL_TREE; - for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) - TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i)); - - if (CHECKING_P) - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a)); + tree a = template_parms_level_to_args (TREE_VALUE (header)); if (length > 1) TREE_VEC_ELT (args, --l) = a; @@ -11357,6 +11366,30 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) return t; } +/* Substitute ARGS into one level PARMS of template parameters. */ + +static tree +tsubst_template_parms_level (tree parms, tree args, tsubst_flags_t complain) +{ + if (parms == error_mark_node) + return error_mark_node; + + tree new_vec = make_tree_vec (TREE_VEC_LENGTH (parms)); + + for (int i = 0; i < TREE_VEC_LENGTH (new_vec); ++i) + { + tree tuple = TREE_VEC_ELT (parms, i); + + if (tuple == error_mark_node) + continue; + + TREE_VEC_ELT (new_vec, i) = + tsubst_template_parm (tuple, args, complain); + } + + return new_vec; +} + /* Return the result of substituting ARGS into the template parameters given by PARMS. If there are m levels of ARGS and m + n levels of PARMS, then the result will contain n levels of PARMS. For @@ -11381,26 +11414,8 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) new_parms = &(TREE_CHAIN (*new_parms)), parms = TREE_CHAIN (parms)) { - tree new_vec = - make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms))); - int i; - - for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i) - { - tree tuple; - - if (parms == error_mark_node) - continue; - - tuple = TREE_VEC_ELT (TREE_VALUE (parms), i); - - if (tuple == error_mark_node) - continue; - - TREE_VEC_ELT (new_vec, i) = - tsubst_template_parm (tuple, args, complain); - } - + tree new_vec = tsubst_template_parms_level (TREE_VALUE (parms), + args, complain); *new_parms = tree_cons (size_int (TMPL_PARMS_DEPTH (parms) - TMPL_ARGS_DEPTH (args)), @@ -23940,6 +23955,16 @@ make_auto (void) return make_auto_1 (get_identifier ("auto"), true); } +/* Return a C++17 deduction placeholder for class template TMPL. */ + +tree +make_template_placeholder (tree tmpl) +{ + tree t = make_auto_1 (DECL_NAME (tmpl), true); + CLASS_PLACEHOLDER_TEMPLATE (t) = tmpl; + return t; +} + /* Make a "constrained auto" type-specifier. This is an auto type with constraints that must be associated after deduction. The constraint is formed from the given @@ -24097,6 +24122,316 @@ extract_autos (tree type) return tree_vec; } +/* The stem for deduction guide names. */ +const char *const dguide_base = "__dguide_"; + +/* Return the name for a deduction guide for class template TMPL. */ + +tree +dguide_name (tree tmpl) +{ + tree type = (TYPE_P (tmpl) ? tmpl : TREE_TYPE (tmpl)); + tree tname = TYPE_IDENTIFIER (type); + char *buf = (char *) alloca (1 + strlen (dguide_base) + + IDENTIFIER_LENGTH (tname)); + memcpy (buf, dguide_base, strlen (dguide_base)); + memcpy (buf + strlen (dguide_base), IDENTIFIER_POINTER (tname), + IDENTIFIER_LENGTH (tname) + 1); + tree dname = get_identifier (buf); + TREE_TYPE (dname) = type; + return dname; +} + +/* True if NAME is the name of a deduction guide. */ + +bool +dguide_name_p (tree name) +{ + return (TREE_TYPE (name) + && !strncmp (IDENTIFIER_POINTER (name), dguide_base, + strlen (dguide_base))); +} + +/* True if FN is a deduction guide. */ + +bool +deduction_guide_p (tree fn) +{ + if (tree name = DECL_NAME (fn)) + return dguide_name_p (name); + return false; +} + +/* OLDDECL is a _DECL for a template parameter. Return a similar parameter at + LEVEL:INDEX, using tsubst_args and complain for substitution into non-type + template parameter types. Note that the handling of template template + parameters relies on current_template_parms being set appropriately for the + new template. */ + +static tree +rewrite_template_parm (tree olddecl, unsigned index, unsigned level, + tree tsubst_args, tsubst_flags_t complain) +{ + tree oldidx = get_template_parm_index (olddecl); + + tree newtype; + if (TREE_CODE (olddecl) == TYPE_DECL + || TREE_CODE (olddecl) == TEMPLATE_DECL) + { + newtype = copy_type (TREE_TYPE (olddecl)); + TYPE_MAIN_VARIANT (newtype) = newtype; + } + else + newtype = tsubst (TREE_TYPE (olddecl), tsubst_args, + complain, NULL_TREE); + + tree newdecl + = build_decl (DECL_SOURCE_LOCATION (olddecl), TREE_CODE (olddecl), + DECL_NAME (olddecl), newtype); + SET_DECL_TEMPLATE_PARM_P (newdecl); + + tree newidx; + if (TREE_CODE (olddecl) == TYPE_DECL + || TREE_CODE (olddecl) == TEMPLATE_DECL) + { + newidx = TEMPLATE_TYPE_PARM_INDEX (newtype) + = build_template_parm_index (index, level, level, + newdecl, newtype); + TYPE_STUB_DECL (newtype) = TYPE_NAME (newtype) = newdecl; + TYPE_CANONICAL (newtype) = canonical_type_parameter (newtype); + + if (TREE_CODE (olddecl) == TEMPLATE_DECL) + { + DECL_TEMPLATE_RESULT (newdecl) + = build_decl (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL, + DECL_NAME (olddecl), newtype); + DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (newdecl)) = true; + // First create a copy (ttargs) of tsubst_args with an + // additional level for the template template parameter's own + // template parameters (ttparms). + tree ttparms = (INNERMOST_TEMPLATE_PARMS + (DECL_TEMPLATE_PARMS (olddecl))); + const int depth = TMPL_ARGS_DEPTH (tsubst_args); + tree ttargs = make_tree_vec (depth + 1); + for (int i = 0; i < depth; ++i) + TREE_VEC_ELT (ttargs, i) = TREE_VEC_ELT (tsubst_args, i); + TREE_VEC_ELT (ttargs, depth) + = template_parms_level_to_args (ttparms); + // Substitute ttargs into ttparms to fix references to + // other template parameters. + ttparms = tsubst_template_parms_level (ttparms, ttargs, + complain); + // Now substitute again with args based on tparms, to reduce + // the level of the ttparms. + ttargs = current_template_args (); + ttparms = tsubst_template_parms_level (ttparms, ttargs, + complain); + // Finally, tack the adjusted parms onto tparms. + ttparms = tree_cons (size_int (depth), ttparms, + current_template_parms); + DECL_TEMPLATE_PARMS (newdecl) = ttparms; + } + } + else + { + tree oldconst = TEMPLATE_PARM_DECL (oldidx); + tree newconst + = build_decl (DECL_SOURCE_LOCATION (oldconst), + TREE_CODE (oldconst), + DECL_NAME (oldconst), newtype); + TREE_CONSTANT (newconst) = TREE_CONSTANT (newdecl) + = TREE_READONLY (newconst) = TREE_READONLY (newdecl) = true; + SET_DECL_TEMPLATE_PARM_P (newconst); + newidx = build_template_parm_index (index, level, level, + newconst, newtype); + DECL_INITIAL (newdecl) = DECL_INITIAL (newconst) = newidx; + } + + TEMPLATE_PARM_PARAMETER_PACK (newidx) + = TEMPLATE_PARM_PARAMETER_PACK (oldidx); + return newdecl; +} + +/* Returns a C++17 class deduction guide template based on the constructor + CTOR. */ + +static tree +build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) +{ + if (outer_args) + ctor = tsubst (ctor, outer_args, complain, ctor); + tree type = DECL_CONTEXT (ctor); + tree fn_tmpl; + if (TREE_CODE (ctor) == TEMPLATE_DECL) + { + fn_tmpl = ctor; + ctor = DECL_TEMPLATE_RESULT (fn_tmpl); + } + else + fn_tmpl = DECL_TI_TEMPLATE (ctor); + + tree tparms = DECL_TEMPLATE_PARMS (fn_tmpl); + /* If type is a member class template, DECL_TI_ARGS (ctor) will have fully + specialized args for the enclosing class. Strip those off, as the + deduction guide won't have those template parameters. */ + tree targs = get_innermost_template_args (DECL_TI_ARGS (ctor), + TMPL_PARMS_DEPTH (tparms)); + /* Discard the 'this' parameter. */ + tree fparms = FUNCTION_ARG_CHAIN (ctor); + tree fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor)); + tree ci = get_constraints (ctor); + + if (PRIMARY_TEMPLATE_P (fn_tmpl)) + { + /* For a member template constructor, we need to flatten the two template + parameter lists into one, and then adjust the function signature + accordingly. This gets...complicated. */ + ++processing_template_decl; + tree save_parms = current_template_parms; + + /* For a member template we should have two levels of parms/args, one for + the class and one for the constructor. We stripped specialized args + for further enclosing classes above. */ + const int depth = 2; + gcc_assert (TMPL_ARGS_DEPTH (targs) == depth); + + /* Template args for translating references to the two-level template + parameters into references to the one-level template parameters we are + creating. */ + tree tsubst_args = copy_node (targs); + TMPL_ARGS_LEVEL (tsubst_args, depth) + = copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth)); + + /* Template parms for the constructor template. */ + tree ftparms = TREE_VALUE (tparms); + unsigned flen = TREE_VEC_LENGTH (ftparms); + /* Template parms for the class template. */ + tparms = TREE_CHAIN (tparms); + tree ctparms = TREE_VALUE (tparms); + unsigned clen = TREE_VEC_LENGTH (ctparms); + /* Template parms for the deduction guide start as a copy of the template + parms for the class. We set current_template_parms for + lookup_template_class_1. */ + current_template_parms = tparms = copy_node (tparms); + tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen); + for (unsigned i = 0; i < clen; ++i) + TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i); + + /* Now we need to rewrite the constructor parms to append them to the + class parms. */ + for (unsigned i = 0; i < flen; ++i) + { + unsigned index = i + clen; + unsigned level = 1; + tree oldelt = TREE_VEC_ELT (ftparms, i); + tree olddecl = TREE_VALUE (oldelt); + tree newdecl = rewrite_template_parm (olddecl, index, level, + tsubst_args, complain); + tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt), + tsubst_args, complain, ctor); + tree list = build_tree_list (newdef, newdecl); + TEMPLATE_PARM_CONSTRAINTS (list) + = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt), + tsubst_args, complain, ctor); + TREE_VEC_ELT (new_vec, index) = list; + TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list); + } + + /* Now we have a final set of template parms to substitute into the + function signature. */ + targs = template_parms_to_args (tparms); + fparms = tsubst (fparms, tsubst_args, complain, ctor); + fargs = tsubst (fargs, tsubst_args, complain, ctor); + if (ci) + ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor); + + current_template_parms = save_parms; + --processing_template_decl; + } + + tree fntype = build_function_type (type, fparms); + tree ded_fn = build_lang_decl_loc (DECL_SOURCE_LOCATION (ctor), + FUNCTION_DECL, + dguide_name (type), fntype); + DECL_ARGUMENTS (ded_fn) = fargs; + tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false); + DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn; + TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn); + DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs); + if (ci) + set_constraints (ded_tmpl, ci); + + return ded_tmpl; +} + +/* Deduce template arguments for the class template TMPL based on the + initializer INIT, and return the resulting type. */ + +tree +do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain) +{ + gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl)); + tree type = TREE_TYPE (tmpl); + + vec *args; + if (TREE_CODE (init) == TREE_LIST) + args = make_tree_vector_from_list (init); + else + args = make_tree_vector_single (init); + + if (args->length() == 1) + { + /* First try to deduce directly, since we don't have implicitly-declared + constructors yet. */ + tree parms = build_tree_list (NULL_TREE, type); + tree tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl)); + tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms)); + int err = type_unification_real (tparms, targs, parms, &(*args)[0], + 1, /*subr*/false, DEDUCE_CALL, + LOOKUP_NORMAL, NULL, /*explain*/false); + if (err == 0) + return tsubst (type, targs, complain, tmpl); + } + + tree dname = dguide_name (tmpl); + tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname, + /*type*/false, /*complain*/false, + /*hidden*/false); + if (cands == error_mark_node) + cands = NULL_TREE; + + tree outer_args = NULL_TREE; + if (DECL_CLASS_SCOPE_P (tmpl) + && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (tmpl))) + { + outer_args = CLASSTYPE_TI_ARGS (DECL_CONTEXT (tmpl)); + type = TREE_TYPE (most_general_template (tmpl)); + } + + if (CLASSTYPE_METHOD_VEC (type)) + // FIXME cache artificial deduction guides + for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns)) + { + tree fn = OVL_CURRENT (fns); + tree guide = build_deduction_guide (fn, outer_args, complain); + cands = ovl_cons (guide, cands); + } + + if (cands == NULL_TREE) + { + error ("cannot deduce template arguments for %qT, as it has " + "no deduction guides or user-declared constructors", type); + return error_mark_node; + } + + tree t = build_new_function_call (cands, &args, /*koenig*/false, + complain|tf_decltype); + + release_tree_vector (args); + + return TREE_TYPE (t); +} + /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. */ @@ -24175,6 +24510,9 @@ do_auto_deduction (tree type, tree init, tree auto_node, return error_mark_node; } } + else if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + /* C++17 class template argument deduction. */ + return do_class_deduction (tmpl, init, complain); else { tree parms = build_tree_list (NULL_TREE, type); @@ -24274,6 +24612,20 @@ splice_late_return_type (tree type, tree late_return_type) { if (is_auto (type)) { + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type)) + { + if (!late_return_type) + error ("deduction guide must have trailing return type"); + else if (CLASS_TYPE_P (late_return_type) + && CLASSTYPE_TEMPLATE_INFO (late_return_type) + && CLASSTYPE_TI_TEMPLATE (late_return_type) == tmpl) + /* OK */; + else + error ("trailing return type %qT of deduction guide is not " + "a specialization of %qT", + late_return_type, TREE_TYPE (tmpl)); + } + if (late_return_type) return late_return_type; @@ -24288,14 +24640,15 @@ splice_late_return_type (tree type, tree late_return_type) } /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or - 'decltype(auto)'. */ + 'decltype(auto)' or a deduced class template. */ bool is_auto (const_tree type) { if (TREE_CODE (type) == TEMPLATE_TYPE_PARM && (TYPE_IDENTIFIER (type) == get_identifier ("auto") - || TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)"))) + || TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)") + || CLASS_PLACEHOLDER_TEMPLATE (type))) return true; else return false; diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 6e22685..a063ea3 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1952,11 +1952,23 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) return error_mark_node; } - if (type_uses_auto (type)) + if (tree anode = type_uses_auto (type)) { - if (complain & tf_error) - error ("invalid use of %"); - return error_mark_node; + if (!CLASS_PLACEHOLDER_TEMPLATE (anode)) + { + if (complain & tf_error) + error ("invalid use of %qT", anode); + return error_mark_node; + } + else if (!parms) + { + if (complain & tf_error) + error ("cannot deduce template arguments for %qT from ()", anode); + return error_mark_node; + } + else + type = do_auto_deduction (type, parms, anode, complain, + adc_variable_type); } if (processing_template_decl) diff --git a/gcc/testsuite/g++.dg/concepts/class-deduction1.C b/gcc/testsuite/g++.dg/concepts/class-deduction1.C new file mode 100644 index 0000000..ad48cf8 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/class-deduction1.C @@ -0,0 +1,17 @@ +// { dg-options "-std=c++1z -fconcepts" } + +template +concept bool Isint = __is_same_as(T,int); + +template +struct A +{ + int i; + A(...); +}; + +template +A(I) -> A; + +A a(1); +A a2(1.0); // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/concepts/var-concept5.C b/gcc/testsuite/g++.dg/concepts/var-concept5.C index ca16332..b91eb94 100644 --- a/gcc/testsuite/g++.dg/concepts/var-concept5.C +++ b/gcc/testsuite/g++.dg/concepts/var-concept5.C @@ -10,5 +10,5 @@ concept bool C2 = true; template // { dg-error "not a type" } constexpr bool f1( ) { return true; } -template T> // { dg-error "expected" } +template T> // { dg-error "expected|not a type" } constexpr bool f2( ) { return true; } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction1.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction1.C new file mode 100644 index 0000000..87fced9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction1.C @@ -0,0 +1,9 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + A(T); +}; + +A a (42); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction10.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction10.C new file mode 100644 index 0000000..8bc4288 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction10.C @@ -0,0 +1,11 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + int i; + A(...); +}; + +template +A(T) -> A { } // { dg-error "1:function body" } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction11.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction11.C new file mode 100644 index 0000000..4e90292 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction11.C @@ -0,0 +1,11 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + int i; + A(...); +}; + +template +static A(T) -> A; // { dg-error "1:decl-specifier" } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction12.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction12.C new file mode 100644 index 0000000..9eb541d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction12.C @@ -0,0 +1,17 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + template class P> + A(T,U,P<42>); +}; + +template struct B { }; + +int i; +A a(&i,2,B<42>()); + +template class same; +template class same {}; +same> s; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction13.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction13.C new file mode 100644 index 0000000..0e2d235 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction13.C @@ -0,0 +1,18 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + template + struct B + { + template + B(T,U,V); + }; +}; + +A::B b(1,2.0,'\3'); + +template class same; +template class same {}; +same::B> s; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction2.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction2.C new file mode 100644 index 0000000..736b263 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction2.C @@ -0,0 +1,10 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + template + A(T, U); +}; + +A a (42, 1.0); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction3.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction3.C new file mode 100644 index 0000000..ed86965 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction3.C @@ -0,0 +1,14 @@ +// { dg-options -std=c++1z } + +template +struct A { }; + +template +struct B +{ + templateclass T> + B(T); +}; + +A<42> a; +B b (a); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction4.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction4.C new file mode 100644 index 0000000..16c41f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction4.C @@ -0,0 +1,19 @@ +// { dg-options -std=c++1z } + +template +struct A { }; + +template +struct B +{ + template + B(A); +}; + +A<42,24> a; +B b (a); + +int main() +{ + (B(a)); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction5.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction5.C new file mode 100644 index 0000000..b94a300 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction5.C @@ -0,0 +1,10 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + int i; +}; + +A a1; +A a(a1); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction6.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction6.C new file mode 100644 index 0000000..569217d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction6.C @@ -0,0 +1,11 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + int i; +}; + +struct B : A {} b; + +A a(b); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction7.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction7.C new file mode 100644 index 0000000..8e982b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction7.C @@ -0,0 +1,10 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + int i; +}; + +template +A(T); // { dg-error "must have trailing return type" } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction8.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction8.C new file mode 100644 index 0000000..3658315 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction8.C @@ -0,0 +1,15 @@ +// { dg-options -std=c++1z } + +template +struct A +{ + int i; + A(...); // { dg-message "candidate" } +}; + +A a(42); // { dg-error "" } + +template +A(T) -> A; + +A a2(42); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C new file mode 100644 index 0000000..5a2b4f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C @@ -0,0 +1,18 @@ +// { dg-options -std=c++1z } + +namespace N { + template + struct A + { + int i; + A(...); + }; +} + +template +N::A(T) -> N::A; // { dg-error "scope" } + +namespace N { + template + A(T) -> A; +} diff --git a/gcc/testsuite/g++.dg/parse/access10.C b/gcc/testsuite/g++.dg/parse/access10.C index 62adc1b..d53d317 100644 --- a/gcc/testsuite/g++.dg/parse/access10.C +++ b/gcc/testsuite/g++.dg/parse/access10.C @@ -8,4 +8,4 @@ template struct A }; // Instead of the bogus error we get a different error. -// { dg-error "template-name" "" { target *-*-* } 7 } +// { dg-error "template-name|expected" "" { target *-*-* } 7 } diff --git a/gcc/testsuite/g++.dg/parse/decl-specifier-1.C b/gcc/testsuite/g++.dg/parse/decl-specifier-1.C index baf0fe7..5c39b60 100644 --- a/gcc/testsuite/g++.dg/parse/decl-specifier-1.C +++ b/gcc/testsuite/g++.dg/parse/decl-specifier-1.C @@ -5,13 +5,12 @@ namespace N { template - struct X { }; // { dg-message "N::X" } + struct X { }; } N::X X; // { dg-error "" "" } int main() { - return sizeof(X); // { dg-error "" "" } - // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } 15 } + return sizeof(X); // { dg-prune-output "not declared in this scope" } } diff --git a/gcc/testsuite/g++.dg/parse/template2.C b/gcc/testsuite/g++.dg/parse/template2.C index 6689c8b..93c7def 100644 --- a/gcc/testsuite/g++.dg/parse/template2.C +++ b/gcc/testsuite/g++.dg/parse/template2.C @@ -3,5 +3,5 @@ namespace N { } int main() { - N::C(); // { dg-error "template" } + N::C(); // { dg-error "template|deduction" } } diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb129.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb129.C index 83fb86b..a8dae01 100644 --- a/gcc/testsuite/g++.old-deja/g++.robertl/eb129.C +++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb129.C @@ -17,7 +17,7 @@ int main() find_if( l.begin(), l.end(), // This is a typo, it should be bind2nd, but an // ICE is not a very helpful diagnostic! - binder2nd( equal_to(), 2 ) ); // { dg-error "" } + binder2nd( equal_to(), 2 ) ); // { dg-error "" "" { target c++14_down } } assert( *(it) == 2 ); } diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb129a.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb129a.C index bba5ff0..3150422 100644 --- a/gcc/testsuite/g++.old-deja/g++.robertl/eb129a.C +++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb129a.C @@ -16,7 +16,7 @@ int main() std::find_if( l.begin(), l.end(), // This is a typo, it should be bind2nd, but an // ICE is not a very helpful diagnostic! - std::binder2nd( std::equal_to(), 2 ) ); // { dg-error "" } + std::binder2nd( std::equal_to(), 2 ) ); // { dg-error "" "" { target c++14_down } } assert( *(it) == 2 ); }