On Thu, Aug 31, 2023 at 01:11:57PM -0400, Jason Merrill wrote: > > 2023-08-28 Jakub Jelinek <ja...@redhat.com> > > > > PR c++/111069 > > gcc/ > > * common.opt (fabi-version=): Document version 19. > > * doc/invoke.texi (-fabi-version=): Likewise. > > gcc/c-family/ > > * c-opts.cc (c_common_post_options): Change latest_abi_version to 19. > > gcc/cp/ > > * cp-tree.h (determine_local_discriminator): Add NAME argument with > > NULL_TREE default. > > (struct cp_decomp): New type. > > Maybe cp_finish_decomp should take this as well? And tsubst_decomp_names, > and various other functions with decomp_first_name/decomp_cnt parms?
Ok, done below. > > + if (tree tags = get_abi_tags (decl)) > > + { > > + /* We didn't emit ABI tags for structured bindings before ABI 19. */ > > + if (!G.need_abi_warning > > + && abi_warn_or_compat_version_crosses (19)) > > + G.need_abi_warning = 1; > > In general we should probably only warn about mangling changes if > TREE_PUBLIC (decl). I have done that but I think it ought to be unnecessary, because check_abi_tags starts with if (!TREE_PUBLIC (decl)) /* No need to worry about things local to this TU. */ return NULL_TREE; Here is an updated patch, so far just tested with make check-g++ GXX_TESTSUITE_STDS=98,11,14,17,20,2b,2c RUNTESTFLAGS="dg.exp='*decomp*'" ok for trunk if it passes full bootstrap/regtest? 2023-08-31 Jakub Jelinek <ja...@redhat.com> PR c++/111069 gcc/ * common.opt (fabi-version=): Document version 19. * doc/invoke.texi (-fabi-version=): Likewise. gcc/c-family/ * c-opts.cc (c_common_post_options): Change latest_abi_version to 19. gcc/cp/ * cp-tree.h (determine_local_discriminator): Add NAME argument with NULL_TREE default. (struct cp_decomp): New type. (cp_finish_decl): Add DECOMP argument defaulted to nullptr. (cp_maybe_mangle_decomp): Remove declaration. (cp_finish_decomp): Add cp_decomp * argument, remove tree and unsigned args. (cp_convert_range_for): Likewise. * decl.cc (determine_local_discriminator): Add NAME argument, use it if non-NULL, otherwise compute it the old way. (maybe_commonize_var): Don't return early for structured bindings. (cp_finish_decl): Add DECOMP argument, if non-NULL, call cp_maybe_mangle_decomp. (cp_maybe_mangle_decomp): Make it static with a forward declaration. Call determine_local_discriminator. Replace FIRST and COUNT arguments with DECOMP argument. (cp_finish_decomp): Replace FIRST and COUNT arguments with DECOMP argument. * mangle.cc (find_decomp_unqualified_name): Remove. (write_unqualified_name): Don't call find_decomp_unqualified_name. (mangle_decomp): Handle mangling of static function/block scope structured bindings. Don't call decl_mangling_context twice. Call check_abi_tags, call write_abi_tags for abi version >= 19 and emit -Wabi warnings if needed. (write_guarded_var_name): Handle structured bindings. (mangle_ref_init_variable): Use write_guarded_var_name. * parser.cc (cp_parser_range_for): Adjust do_range_for_auto_deduction and cp_convert_range_for callers. (do_range_for_auto_deduction): Replace DECOMP_FIRST_NAME and DECOMP_CNT arguments with DECOMP. Adjust cp_finish_decomp caller. (cp_convert_range_for): Replace DECOMP_FIRST_NAME and DECOMP_CNT arguments with DECOMP. Don't call cp_maybe_mangle_decomp, adjust cp_finish_decl and cp_finish_decomp callers. (cp_parser_decomposition_declaration): Don't call cp_maybe_mangle_decomp, adjust cp_finish_decl and cp_finish_decomp callers. (cp_convert_omp_range_for): Adjust do_range_for_auto_deduction and cp_finish_decomp callers. (cp_finish_omp_range_for): Don't call cp_maybe_mangle_decomp, adjust cp_finish_decl and cp_finish_decomp callers. * pt.cc (tsubst_omp_for_iterator): Adjust tsubst_decomp_names caller. (tsubst_decomp_names): Replace FIRST and CNT arguments with DECOMP. (tsubst_expr): Don't call cp_maybe_mangle_decomp, adjust tsubst_decomp_names, cp_finish_decl, cp_finish_decomp and cp_convert_range_for callers. gcc/testsuite/ * g++.dg/cpp2a/decomp8.C: New test. * g++.dg/cpp2a/decomp9.C: New test. * g++.dg/abi/macro0.C: Expect __GXX_ABI_VERSION 1019 rather than 1018. --- gcc/common.opt.jj 2023-08-28 13:55:55.670370386 +0200 +++ gcc/common.opt 2023-08-31 19:53:31.186280641 +0200 @@ -1010,6 +1010,9 @@ Driver Undocumented ; 18: Corrects errors in mangling of lambdas with additional context. ; Default in G++ 13. ; +; 19: Emits ABI tags if needed in structured binding mangled names. +; Default in G++ 14. +; ; Additional positive integers will be assigned as new versions of ; the ABI become the default version of the ABI. fabi-version= --- gcc/doc/invoke.texi.jj 2023-08-31 19:52:16.734307207 +0200 +++ gcc/doc/invoke.texi 2023-08-31 19:53:31.191280572 +0200 @@ -3017,6 +3017,9 @@ in C++14 and up. Version 18, which first appeard in G++ 13, fixes manglings of lambdas that have additional context. +Version 19, which first appeard in G++ 14, fixes manglings of structured +bindings to include ABI tags. + See also @option{-Wabi}. @opindex fabi-compat-version --- gcc/c-family/c-opts.cc.jj 2023-08-28 13:55:55.613371156 +0200 +++ gcc/c-family/c-opts.cc 2023-08-31 19:53:31.192280558 +0200 @@ -974,7 +974,7 @@ c_common_post_options (const char **pfil /* Change flag_abi_version to be the actual current ABI level, for the benefit of c_cpp_builtins, and to make comparison simpler. */ - const int latest_abi_version = 18; + const int latest_abi_version = 19; /* Generate compatibility aliases for ABI v13 (8.2) by default. */ const int abi_compat_default = 13; --- gcc/cp/cp-tree.h.jj 2023-08-31 14:31:05.991763184 +0200 +++ gcc/cp/cp-tree.h 2023-08-31 20:39:34.052154029 +0200 @@ -6859,7 +6859,7 @@ extern void pop_switch (void); extern void note_break_stmt (void); extern bool note_iteration_stmt_body_start (void); extern void note_iteration_stmt_body_end (bool); -extern void determine_local_discriminator (tree); +extern void determine_local_discriminator (tree, tree = NULL_TREE); extern bool member_like_constrained_friend_p (tree); extern bool fns_correspond (tree, tree); extern int decls_match (tree, tree, bool = true); @@ -6892,10 +6892,10 @@ extern tree start_decl (const cp_decl extern void start_decl_1 (tree, bool); extern bool check_array_initializer (tree, tree, tree); extern void omp_declare_variant_finalize (tree, tree); -extern void cp_finish_decl (tree, tree, bool, tree, int); +struct cp_decomp { tree decl; unsigned int count; }; +extern void cp_finish_decl (tree, tree, bool, tree, int, cp_decomp * = nullptr); extern tree lookup_decomp_type (tree); -extern void cp_maybe_mangle_decomp (tree, tree, unsigned int); -extern void cp_finish_decomp (tree, tree, unsigned int); +extern void cp_finish_decomp (tree, cp_decomp *); extern int cp_complete_array_type (tree *, tree, bool); extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t); extern tree build_ptrmemfunc_type (tree); @@ -7312,7 +7312,7 @@ extern tree clone_attrs (tree); extern bool maybe_clone_body (tree); /* In parser.cc */ -extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool, +extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, unsigned short, bool); extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &); --- gcc/cp/decl.cc.jj 2023-08-30 18:48:48.831597950 +0200 +++ gcc/cp/decl.cc 2023-08-31 20:48:21.127722180 +0200 @@ -911,15 +911,16 @@ static GTY((deletable)) vec<tree, va_gc> generally very few of these in any particular function. */ void -determine_local_discriminator (tree decl) +determine_local_discriminator (tree decl, tree name) { auto_cond_timevar tv (TV_NAME_LOOKUP); retrofit_lang_decl (decl); tree ctx = DECL_CONTEXT (decl); - tree name = (TREE_CODE (decl) == TYPE_DECL - && TYPE_UNNAMED_P (TREE_TYPE (decl)) - ? NULL_TREE : DECL_NAME (decl)); size_t nelts = vec_safe_length (local_entities); + if (name == NULL_TREE) + name = (TREE_CODE (decl) == TYPE_DECL + && TYPE_UNNAMED_P (TREE_TYPE (decl)) + ? NULL_TREE : DECL_NAME (decl)); for (size_t i = 0; i < nelts; i += 2) { tree *pair = &(*local_entities)[i]; @@ -6417,8 +6418,9 @@ layout_var_decl (tree decl) void maybe_commonize_var (tree decl) { - /* Don't mess with __FUNCTION__ and similar. */ - if (DECL_ARTIFICIAL (decl)) + /* Don't mess with __FUNCTION__ and similar. But do handle structured + bindings. */ + if (DECL_ARTIFICIAL (decl) && !DECL_DECOMPOSITION_P (decl)) return; /* Static data in a function with comdat linkage also has comdat @@ -8212,6 +8214,8 @@ omp_declare_variant_finalize (tree decl, } } +static void cp_maybe_mangle_decomp (tree, cp_decomp *); + /* Finish processing of a declaration; install its line number and initial value. If the length of an array type is not known before, @@ -8221,11 +8225,14 @@ omp_declare_variant_finalize (tree decl, true, then INIT is an integral constant expression. FLAGS is LOOKUP_ONLYCONVERTING if the = init syntax was used, else 0 - if the (init) syntax was used. */ + if the (init) syntax was used. + + DECOMP is first identifier's DECL and identifier count in a structured + bindings, nullptr if not a structured binding. */ void cp_finish_decl (tree decl, tree init, bool init_const_expr_p, - tree asmspec_tree, int flags) + tree asmspec_tree, int flags, cp_decomp *decomp) { vec<tree, va_gc> *cleanups = NULL; const char *asmspec = NULL; @@ -8600,6 +8607,9 @@ cp_finish_decl (tree decl, tree init, bo return; } + if (decomp) + cp_maybe_mangle_decomp (decl, decomp); + /* If this is a local variable that will need a mangled name, register it now. We must do this before processing the initializer for the variable, since the initialization might @@ -9070,18 +9080,37 @@ lookup_decomp_type (tree v) /* Mangle a decomposition declaration if needed. Arguments like in cp_finish_decomp. */ -void -cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) +static void +cp_maybe_mangle_decomp (tree decl, cp_decomp *decomp) { if (!processing_template_decl && !error_operand_p (decl) && TREE_STATIC (decl)) { auto_vec<tree, 16> v; - v.safe_grow (count, true); - tree d = first; - for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) - v[count - i - 1] = d; + v.safe_grow (decomp->count, true); + tree d = decomp->decl; + for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d)) + v[decomp->count - i - 1] = d; + if (DECL_FUNCTION_SCOPE_P (decl)) + { + size_t sz = 3; + for (unsigned int i = 0; i < decomp->count; ++i) + sz += IDENTIFIER_LENGTH (DECL_NAME (v[i])) + 1; + char *name = XALLOCAVEC (char, sz); + name[0] = 'D'; + name[1] = 'C'; + char *p = name + 2; + for (unsigned int i = 0; i < decomp->count; ++i) + { + size_t len = IDENTIFIER_LENGTH (DECL_NAME (v[i])); + *p++ = ' '; + memcpy (p, IDENTIFIER_POINTER (DECL_NAME (v[i])), len); + p += len; + } + *p = '\0'; + determine_local_discriminator (decl, get_identifier (name)); + } SET_DECL_ASSEMBLER_NAME (decl, mangle_decomp (decl, v)); maybe_apply_pragma_weak (decl); } @@ -9093,8 +9122,10 @@ cp_maybe_mangle_decomp (tree decl, tree those decls. */ void -cp_finish_decomp (tree decl, tree first, unsigned int count) +cp_finish_decomp (tree decl, cp_decomp *decomp) { + tree first = decomp->decl; + unsigned count = decomp->count; if (error_operand_p (decl)) { error_out: --- gcc/cp/mangle.cc.jj 2023-08-28 13:55:55.819368372 +0200 +++ gcc/cp/mangle.cc 2023-08-31 20:48:21.127722180 +0200 @@ -1347,51 +1347,6 @@ write_template_prefix (const tree node) add_substitution (substitution); } -/* As the list of identifiers for the structured binding declaration - DECL is likely gone, try to recover the DC <source-name>+ E portion - from its mangled name. Return pointer to the DC and set len to - the length up to and including the terminating E. On failure - return NULL. */ - -static const char * -find_decomp_unqualified_name (tree decl, size_t *len) -{ - const char *p = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - const char *end = p + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl)); - bool nested = false; - if (!startswith (p, "_Z")) - return NULL; - p += 2; - if (startswith (p, "St")) - p += 2; - else if (*p == 'N') - { - nested = true; - ++p; - while (ISDIGIT (p[0])) - { - char *e; - long num = strtol (p, &e, 10); - if (num >= 1 && num < end - e) - p = e + num; - else - break; - } - } - if (!startswith (p, "DC")) - return NULL; - if (nested) - { - if (end[-1] != 'E') - return NULL; - --end; - } - if (end[-1] != 'E') - return NULL; - *len = end - p; - return p; -} - /* "For the purposes of mangling, the name of an anonymous union is considered to be the name of the first named data member found by a pre-order, depth-first, declaration-order walk of the data members of the anonymous @@ -1465,17 +1420,7 @@ write_unqualified_name (tree decl) { found = true; gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); - const char *decomp_str = NULL; - size_t decomp_len = 0; - if (VAR_P (decl) - && DECL_DECOMPOSITION_P (decl) - && DECL_NAME (decl) == NULL_TREE - && DECL_NAMESPACE_SCOPE_P (decl)) - decomp_str = find_decomp_unqualified_name (decl, &decomp_len); - if (decomp_str) - write_chars (decomp_str, decomp_len); - else - write_source_name (DECL_ASSEMBLER_NAME (decl)); + write_source_name (DECL_ASSEMBLER_NAME (decl)); } else if (DECL_DECLARES_FUNCTION_P (decl)) { @@ -4373,6 +4318,7 @@ mangle_decomp (const tree decl, vec<tree location_t saved_loc = input_location; input_location = DECL_SOURCE_LOCATION (decl); + check_abi_tags (decl); start_mangling (decl); write_string ("_Z"); @@ -4380,13 +4326,21 @@ mangle_decomp (const tree decl, vec<tree gcc_assert (context != NULL_TREE); bool nested = false; + bool local = false; if (DECL_NAMESPACE_STD_P (context)) write_string ("St"); + else if (TREE_CODE (context) == FUNCTION_DECL) + { + local = true; + write_char ('Z'); + write_encoding (context); + write_char ('E'); + } else if (context != global_namespace) { nested = true; write_char ('N'); - write_prefix (decl_mangling_context (decl)); + write_prefix (context); } write_string ("DC"); @@ -4396,8 +4350,22 @@ mangle_decomp (const tree decl, vec<tree write_unqualified_name (d); write_char ('E'); + if (tree tags = get_abi_tags (decl)) + { + /* We didn't emit ABI tags for structured bindings before ABI 19. */ + if (!G.need_abi_warning + && TREE_PUBLIC (decl) + && abi_warn_or_compat_version_crosses (19)) + G.need_abi_warning = 1; + + if (abi_version_at_least (19)) + write_abi_tags (tags); + } + if (nested) write_char ('E'); + else if (local && DECL_DISCRIMINATOR_P (decl)) + write_discriminator (discriminator_for_local_entity (decl)); tree id = finish_mangling_get_identifier (); if (DEBUG_MANGLE) @@ -4405,6 +4373,37 @@ mangle_decomp (const tree decl, vec<tree IDENTIFIER_POINTER (id)); input_location = saved_loc; + + if (warn_abi && G.need_abi_warning) + { + const char fabi_version[] = "-fabi-version"; + tree id2 = id; + int save_ver = flag_abi_version; + + if (flag_abi_version != warn_abi_version) + { + flag_abi_version = warn_abi_version; + id2 = mangle_decomp (decl, decls); + flag_abi_version = save_ver; + } + + if (id2 == id) + /* OK. */; + else if (warn_abi_version != 0 + && abi_version_at_least (warn_abi_version)) + warning_at (DECL_SOURCE_LOCATION (G.entity), OPT_Wabi, + "the mangled name of %qD changed between " + "%<%s=%d%> (%qD) and %<%s=%d%> (%qD)", + G.entity, fabi_version, warn_abi_version, id2, + fabi_version, save_ver, id); + else + warning_at (DECL_SOURCE_LOCATION (G.entity), OPT_Wabi, + "the mangled name of %qD changes between " + "%<%s=%d%> (%qD) and %<%s=%d%> (%qD)", + G.entity, fabi_version, save_ver, id, + fabi_version, warn_abi_version, id2); + } + return id; } @@ -4574,6 +4573,13 @@ write_guarded_var_name (const tree varia /* The name of a guard variable for a reference temporary should refer to the reference, not the temporary. */ write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4); + else if (DECL_DECOMPOSITION_P (variable) + && DECL_NAME (variable) == NULL_TREE + && startswith (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (variable)), + "_Z")) + /* The name of a guard variable for a structured binding needs special + casing. */ + write_string (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (variable)) + 2); else write_name (variable, /*ignore_local_scope=*/0); } @@ -4640,7 +4646,7 @@ mangle_ref_init_variable (const tree var start_mangling (variable); write_string ("_ZGR"); check_abi_tags (variable); - write_name (variable, /*ignore_local_scope=*/0); + write_guarded_var_name (variable); /* Avoid name clashes with aggregate initialization of multiple references at once. */ write_compact_number (current_ref_temp_count++); --- gcc/cp/parser.cc.jj 2023-08-31 14:31:35.963352093 +0200 +++ gcc/cp/parser.cc 2023-08-31 20:48:21.127722180 +0200 @@ -2393,7 +2393,7 @@ static tree cp_parser_c_for static tree cp_parser_range_for (cp_parser *, tree, tree, tree, bool, unsigned short, bool, bool); static void do_range_for_auto_deduction - (tree, tree, tree, unsigned int); + (tree, tree, cp_decomp *); static tree cp_parser_perform_range_for_lookup (tree, tree *, tree *); static tree cp_parser_range_for_member_function @@ -13854,8 +13854,7 @@ cp_parser_range_for (cp_parser *parser, tree stmt, range_expr; auto_vec <cxx_binding *, 16> bindings; auto_vec <tree, 16> names; - tree decomp_first_name = NULL_TREE; - unsigned int decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; /* Get the range declaration momentarily out of the way so that the range expression doesn't clash with it. */ @@ -13872,9 +13871,11 @@ cp_parser_range_for (cp_parser *parser, { tree d = range_decl; range_decl = TREE_OPERAND (v, 0); - decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp_first_name = d; - for (unsigned int i = 0; i < decomp_cnt; i++, d = DECL_CHAIN (d)) + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp->decl = d; + for (unsigned int i = 0; i < decomp->count; + i++, d = DECL_CHAIN (d)) { tree name = DECL_NAME (d); names.safe_push (name); @@ -13928,15 +13929,13 @@ cp_parser_range_for (cp_parser *parser, if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ && !BRACE_ENCLOSED_INITIALIZER_P (range_expr)) - do_range_for_auto_deduction (range_decl, range_expr, decomp_first_name, - decomp_cnt); + do_range_for_auto_deduction (range_decl, range_expr, decomp); } else { stmt = begin_for_stmt (scope, init); - stmt = cp_convert_range_for (stmt, range_decl, range_expr, - decomp_first_name, decomp_cnt, ivdep, - unroll, novector); + stmt = cp_convert_range_for (stmt, range_decl, range_expr, decomp, + ivdep, unroll, novector); } return stmt; } @@ -13968,8 +13967,7 @@ build_range_temp (tree range_expr) a shortcut version of cp_convert_range_for. */ static void -do_range_for_auto_deduction (tree decl, tree range_expr, - tree decomp_first_name, unsigned int decomp_cnt) +do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp) { tree auto_node = type_uses_auto (TREE_TYPE (decl)); if (auto_node) @@ -13990,7 +13988,7 @@ do_range_for_auto_deduction (tree decl, tf_warning_or_error, adc_variable_type); if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) - cp_finish_decomp (decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (decl, decomp); } } } @@ -14113,8 +14111,8 @@ warn_for_range_copy (tree decl, tree exp tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, - tree decomp_first_name, unsigned int decomp_cnt, - bool ivdep, unsigned short unroll, bool novector) + cp_decomp *decomp, bool ivdep, unsigned short unroll, + bool novector) { tree begin, end; tree iter_type, begin_expr, end_expr; @@ -14182,17 +14180,14 @@ cp_convert_range_for (tree statement, tr tf_warning_or_error); finish_for_expr (expression, statement); - if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) - cp_maybe_mangle_decomp (range_decl, decomp_first_name, decomp_cnt); - /* The declaration is initialized with *__begin inside the loop body. */ tree deref_begin = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, NULL_TREE, tf_warning_or_error); cp_finish_decl (range_decl, deref_begin, /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + LOOKUP_ONLYCONVERTING, decomp); if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) - cp_finish_decomp (range_decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (range_decl, decomp); warn_for_range_copy (range_decl, deref_begin); @@ -15890,18 +15885,20 @@ cp_parser_decomposition_declaration (cp_ if (decl != error_mark_node) { - cp_maybe_mangle_decomp (decl, prev, v.length ()); + cp_decomp decomp = { prev, v.length () }; cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE, - (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)); - cp_finish_decomp (decl, prev, v.length ()); + (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT), + &decomp); + cp_finish_decomp (decl, &decomp); } } else if (decl != error_mark_node) { *maybe_range_for_decl = prev; + cp_decomp decomp = { prev, v.length () }; /* Ensure DECL_VALUE_EXPR is created for all the decls but the underlying DECL. */ - cp_finish_decomp (decl, prev, v.length ()); + cp_finish_decomp (decl, &decomp); } if (pushed_scope) @@ -43521,8 +43518,7 @@ cp_convert_omp_range_for (tree &this_pre && !BRACE_ENCLOSED_INITIALIZER_P (init)) { tree d = decl; - tree decomp_first_name = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl)) { tree v = DECL_VALUE_EXPR (decl); @@ -43531,11 +43527,12 @@ cp_convert_omp_range_for (tree &this_pre && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) { d = TREE_OPERAND (v, 0); - decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp_first_name = decl; + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp->decl = decl; } } - do_range_for_auto_deduction (d, init, decomp_first_name, decomp_cnt); + do_range_for_auto_deduction (d, init, decomp); } cond = global_namespace; incr = NULL_TREE; @@ -43626,8 +43623,7 @@ cp_convert_omp_range_for (tree &this_pre decl = begin; /* Defer popping sl here. */ - tree decomp_first_name = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (orig_decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (orig_decl)) { tree v = DECL_VALUE_EXPR (orig_decl); @@ -43637,8 +43633,9 @@ cp_convert_omp_range_for (tree &this_pre { tree d = orig_decl; orig_decl = TREE_OPERAND (v, 0); - decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp_first_name = d; + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp->decl = d; } } @@ -43651,10 +43648,10 @@ cp_convert_omp_range_for (tree &this_pre { TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl), t, auto_node); - if (decomp_first_name) + if (decomp) { ++processing_template_decl; - cp_finish_decomp (orig_decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (orig_decl, decomp); --processing_template_decl; if (!processing_template_decl) clear_has_value_expr = true; @@ -43670,8 +43667,9 @@ cp_convert_omp_range_for (tree &this_pre the whole loop nest. The remaining elements are decls of derived decomposition variables that are bound inside the loop body. This structure is further mangled by finish_omp_for into the form required - for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node. */ - tree v = make_tree_vec (decomp_cnt + 3); + for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node. */\ + unsigned decomp_cnt = decomp ? decomp->count : 0; + tree v = make_tree_vec (decomp_cnt); TREE_VEC_ELT (v, 0) = range_temp_decl; TREE_VEC_ELT (v, 1) = end; TREE_VEC_ELT (v, 2) = orig_decl; @@ -43686,13 +43684,13 @@ cp_convert_omp_range_for (tree &this_pre name but the DECL_VALUE_EXPR will be dependent. Hide those from folding of other loop initializers e.g. for warning purposes until cp_finish_omp_range_for. */ - gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (decomp_first_name) - || (TREE_TYPE (decomp_first_name) + gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (decomp->decl) + || (TREE_TYPE (decomp->decl) == error_mark_node)); - DECL_HAS_VALUE_EXPR_P (decomp_first_name) = 0; + DECL_HAS_VALUE_EXPR_P (decomp->decl) = 0; } - TREE_VEC_ELT (v, i + 3) = decomp_first_name; - decomp_first_name = DECL_CHAIN (decomp_first_name); + TREE_VEC_ELT (v, i + 3) = decomp->decl; + decomp->decl = DECL_CHAIN (decomp->decl); } orig_decl = tree_cons (NULL_TREE, NULL_TREE, v); } @@ -43706,27 +43704,26 @@ cp_finish_omp_range_for (tree orig, tree gcc_assert (TREE_CODE (orig) == TREE_LIST && TREE_CODE (TREE_CHAIN (orig)) == TREE_VEC); tree decl = TREE_VEC_ELT (TREE_CHAIN (orig), 2); - tree decomp_first_name = NULL_TREE; - unsigned int decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) { - decomp_first_name = TREE_VEC_ELT (TREE_CHAIN (orig), 3); - decomp_cnt = TREE_VEC_LENGTH (TREE_CHAIN (orig)) - 3; + decomp = &decomp_d; + decomp_d.decl = TREE_VEC_ELT (TREE_CHAIN (orig), 3); + decomp_d.count = TREE_VEC_LENGTH (TREE_CHAIN (orig)) - 3; if (TREE_PUBLIC (TREE_CHAIN (orig))) { /* Undo temporary clearing of DECL_HAS_VALUE_EXPR_P done by cp_convert_omp_range_for above. */ TREE_PUBLIC (TREE_CHAIN (orig)) = 0; - tree d = decomp_first_name; - for (unsigned i = 0; i < decomp_cnt; i++) + tree d = decomp_d.decl; + for (unsigned i = 0; i < decomp_d.count; i++) { if (TREE_TYPE (d) != error_mark_node) DECL_HAS_VALUE_EXPR_P (d) = 1; d = DECL_CHAIN (d); } } - cp_maybe_mangle_decomp (decl, decomp_first_name, decomp_cnt); } /* The declaration is initialized with *__begin inside the loop body. */ @@ -43734,9 +43731,9 @@ cp_finish_omp_range_for (tree orig, tree build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, NULL_TREE, tf_warning_or_error), /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + LOOKUP_ONLYCONVERTING, decomp); if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) - cp_finish_decomp (decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (decl, decomp); } /* Return true if next tokens contain a standard attribute that contains --- gcc/cp/pt.cc.jj 2023-08-28 13:55:55.868367710 +0200 +++ gcc/cp/pt.cc 2023-08-31 20:48:21.127722180 +0200 @@ -18352,7 +18352,7 @@ tsubst_copy_asm_operands (tree t, tree a static tree *omp_parallel_combined_clauses; static tree tsubst_decomp_names (tree, tree, tree, tsubst_flags_t, tree, - tree *, unsigned int *); + cp_decomp *); /* Substitute one OMP_FOR iterator. */ @@ -18383,28 +18383,27 @@ tsubst_omp_for_iterator (tree t, int i, && VAR_P (TREE_OPERAND (v, 0)) && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) { - tree decomp_first = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d = { NULL_TREE, 0 }; tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain); maybe_push_decl (d); d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain, - in_decl, &decomp_first, &decomp_cnt); + in_decl, &decomp_d); decomp = true; if (d == error_mark_node) decl = error_mark_node; else - for (unsigned int i = 0; i < decomp_cnt; i++) + for (unsigned int i = 0; i < decomp_d.count; i++) { - if (!DECL_HAS_VALUE_EXPR_P (decomp_first)) + if (!DECL_HAS_VALUE_EXPR_P (decomp_d.decl)) { tree v = build_nt (ARRAY_REF, d, - size_int (decomp_cnt - i - 1), + size_int (decomp_d.count - i - 1), NULL_TREE, NULL_TREE); - SET_DECL_VALUE_EXPR (decomp_first, v); - DECL_HAS_VALUE_EXPR_P (decomp_first) = 1; + SET_DECL_VALUE_EXPR (decomp_d.decl, v); + DECL_HAS_VALUE_EXPR_P (decomp_d.decl) = 1; } - fit_decomposition_lang_decl (decomp_first, d); - decomp_first = DECL_CHAIN (decomp_first); + fit_decomposition_lang_decl (decomp_d.decl, d); + decomp_d.decl = DECL_CHAIN (decomp_d.decl); } } } @@ -18723,11 +18722,10 @@ tsubst_find_omp_teams (tree *tp, int *wa static tree tsubst_decomp_names (tree decl, tree pattern_decl, tree args, - tsubst_flags_t complain, tree in_decl, tree *first, - unsigned int *cnt) + tsubst_flags_t complain, tree in_decl, cp_decomp *decomp) { tree decl2, decl3, prev = decl; - *cnt = 0; + decomp->count = 0; gcc_assert (DECL_NAME (decl) == NULL_TREE); for (decl2 = DECL_CHAIN (pattern_decl); decl2 @@ -18736,12 +18734,12 @@ tsubst_decomp_names (tree decl, tree pat && DECL_NAME (decl2); decl2 = DECL_CHAIN (decl2)) { - if (TREE_TYPE (decl2) == error_mark_node && *cnt == 0) + if (TREE_TYPE (decl2) == error_mark_node && decomp->count == 0) { gcc_assert (errorcount); return error_mark_node; } - (*cnt)++; + decomp->count++; gcc_assert (DECL_DECOMP_BASE (decl2) == pattern_decl); gcc_assert (DECL_HAS_VALUE_EXPR_P (decl2)); tree v = DECL_VALUE_EXPR (decl2); @@ -18771,7 +18769,7 @@ tsubst_decomp_names (tree decl, tree pat else prev = decl3; } - *first = prev; + decomp->decl = prev; return decl; } @@ -19043,8 +19041,8 @@ tsubst_expr (tree t, tree args, tsubst_f else { bool const_init = false; - unsigned int cnt = 0; - tree first = NULL_TREE, ndecl = error_mark_node; + cp_decomp decomp_d, *decomp = NULL; + tree ndecl = error_mark_node; tree asmspec_tree = NULL_TREE; maybe_push_decl (decl); @@ -19056,9 +19054,11 @@ tsubst_expr (tree t, tree args, tsubst_f if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl) && TREE_TYPE (pattern_decl) != error_mark_node) - ndecl = tsubst_decomp_names (decl, pattern_decl, args, - complain, in_decl, &first, - &cnt); + { + decomp = &decomp_d; + ndecl = tsubst_decomp_names (decl, pattern_decl, args, + complain, in_decl, decomp); + } init = tsubst_init (init, decl, args, complain, in_decl); @@ -19066,9 +19066,6 @@ tsubst_expr (tree t, tree args, tsubst_f const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (pattern_decl)); - if (ndecl != error_mark_node) - cp_maybe_mangle_decomp (ndecl, first, cnt); - /* In a non-template function, VLA type declarations are handled in grokdeclarator; for templates, handle them now. */ @@ -19085,10 +19082,11 @@ tsubst_expr (tree t, tree args, tsubst_f TREE_TYPE (asmspec_tree) = char_array_type_node; } - cp_finish_decl (decl, init, const_init, asmspec_tree, 0); + cp_finish_decl (decl, init, const_init, asmspec_tree, 0, + decomp); if (ndecl != error_mark_node) - cp_finish_decomp (ndecl, first, cnt); + cp_finish_decomp (ndecl, decomp); } } } @@ -19127,12 +19125,13 @@ tsubst_expr (tree t, tree args, tsubst_f maybe_push_decl (decl); expr = RECUR (RANGE_FOR_EXPR (t)); - tree decomp_first = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) - decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args, - complain, in_decl, - &decomp_first, &decomp_cnt); + { + decomp = &decomp_d; + decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args, + complain, in_decl, decomp); + } if (processing_template_decl) { @@ -19140,15 +19139,14 @@ tsubst_expr (tree t, tree args, tsubst_f RANGE_FOR_UNROLL (stmt) = RANGE_FOR_UNROLL (t); RANGE_FOR_NOVECTOR (stmt) = RANGE_FOR_NOVECTOR (t); finish_range_for_decl (stmt, decl, expr); - if (decomp_first && decl != error_mark_node) - cp_finish_decomp (decl, decomp_first, decomp_cnt); + if (decomp && decl != error_mark_node) + cp_finish_decomp (decl, decomp); } else { unsigned short unroll = (RANGE_FOR_UNROLL (t) ? tree_to_uhwi (RANGE_FOR_UNROLL (t)) : 0); - stmt = cp_convert_range_for (stmt, decl, expr, - decomp_first, decomp_cnt, + stmt = cp_convert_range_for (stmt, decl, expr, decomp, RANGE_FOR_IVDEP (t), unroll, RANGE_FOR_NOVECTOR (t)); } --- gcc/testsuite/g++.dg/cpp2a/decomp8.C.jj 2023-08-31 19:53:31.205280379 +0200 +++ gcc/testsuite/g++.dg/cpp2a/decomp8.C 2023-08-31 19:53:31.205280379 +0200 @@ -0,0 +1,74 @@ +// PR c++/111069 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +extern int a[2]; +struct Y { int b, c, d; }; + +inline int +freddy () +{ + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [k, l] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = ++i + ++k; + { + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [k, l] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++i + ++k; + } + { + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [k, l] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++i + ++k; + } + return ret; +} + +namespace N +{ + namespace M + { + template <int N> + inline int + corge () + { + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto && [u, v, w] = Y{}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = ++i + ++u; + { + static auto && [u, v, w] = Y{}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++v; + } + return ret; + } + } +} + +int (*p) () = &freddy; +int (*q) () = N::M::corge<3>; + +// { dg-final { scan-assembler "_ZZ6freddyvEDC1i1jE" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1i1jE_0" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1i1jE_1" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1k1lE" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1k1lE_0" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1k1lE_1" } } +// { dg-final { scan-assembler "_ZZN1N1M5corgeILi3EEEivEDC1i1jE" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1i1jE" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1i1jE_0" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1i1jE_1" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1k1lE" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1k1lE_0" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1k1lE_1" } } +// { dg-final { scan-assembler "_ZGVZN1N1M5corgeILi3EEEivEDC1i1jE" } } +// { dg-final { scan-assembler "_ZGRZN1N1M5corgeILi3EEEivEDC1u1v1wE_" } } +// { dg-final { scan-assembler "_ZGRZN1N1M5corgeILi3EEEivEDC1u1v1wE_0_" } } --- gcc/testsuite/g++.dg/cpp2a/decomp9.C.jj 2023-08-31 19:53:31.205280379 +0200 +++ gcc/testsuite/g++.dg/cpp2a/decomp9.C 2023-08-31 19:53:31.205280379 +0200 @@ -0,0 +1,82 @@ +// PR c++/111069 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct [[gnu::abi_tag ("foobar")]] S { int i; }; +extern S a[2]; +struct [[gnu::abi_tag ("qux")]] T { int i; S j; int k; }; +extern T b[2]; + +namespace N { + auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + auto [k, l] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } } +} + +inline int +foo () +{ + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [o, p] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = ++N::i.i + ++N::k.i; + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + + ret += ++n.i; + } + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + + ret += ++n.i; + } + ret += ++m.i + ++o.i; + return ret; +} + +template <typename T> +inline int +bar () +{ + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [o, p] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = 0; + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++n.i; + } + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++n.i; + } + ret += ++m.i + ++o.i; + return ret; +} + +int (*p) () = &foo; +int (*q) () = &bar<T>; + +// { dg-final { scan-assembler "_ZZ3foovEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZZ3foovEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZZ3foovEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZZ3foovEDC1o1pEB3qux" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1o1pEB3qux" } } +// { dg-final { scan-assembler "_ZN1NDC1i1jEB6foobarE" } } +// { dg-final { scan-assembler "_ZN1NDC1k1lEB3quxE" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1o1pEB3qux" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1o1pEB3qux" } } --- gcc/testsuite/g++.dg/abi/macro0.C.jj 2022-10-11 10:00:07.456124822 +0200 +++ gcc/testsuite/g++.dg/abi/macro0.C 2023-08-31 19:53:31.222280146 +0200 @@ -1,6 +1,6 @@ // This testcase will need to be kept in sync with c_common_post_options. // { dg-options "-fabi-version=0" } -#if __GXX_ABI_VERSION != 1018 +#if __GXX_ABI_VERSION != 1019 #error "Incorrect value of __GXX_ABI_VERSION" #endif Jakub