Hi! On Thu, Aug 24, 2023 at 06:39:10PM +0200, Jakub Jelinek via Gcc-patches wrote: > > Maybe do this in mangle_decomp, based on the actual mangling in process > > instead of this pseudo-mangling? > > Not sure that is possible, for 2 reasons: > 1) determine_local_discriminator otherwise works on DECL_NAME, not mangled > names, so if one uses (albeit implementation reserved) > _ZZN1N3fooI1TB3bazEEivEDC1h1iEB6foobar and similar identifiers, they > could clash with the counting of the structured bindings > 2) seems the local discriminator counting shouldn't take into account > details like abi tags, e.g. if I have:
The following updated patch handles everything except it leaves for the above 2 reasons the determination of local discriminator where it was. I had to add a new (defaulted) argument to cp_finish_decl and do cp_maybe_mangle_decomp from there, so that it is after e.g. auto type deduction and maybe_commonize_var (which had to be changed as well) and spots in cp_finish_decl where we need or might need mangled names already. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? There is one difference between g++ with this patch and clang++, g++ uses _ZZ3barI1TB3quxEivEDC1o1pEB3qux while clang++ uses _ZZ3barI1TB3quxEivEDC1o1pE but from what I can see, such a difference is there also when just using normal local decls: struct [[gnu::abi_tag ("foobar")]] S { int i; }; struct [[gnu::abi_tag ("qux")]] T { int i; S j; int k; }; inline int foo () { static S c; static T d; return ++c.i + ++d.i; } template <typename T> inline int bar () { static S c; static T d; return ++c.i + ++d.i; } int (*p) () = &foo; int (*q) () = &bar<T>; where both compilers mangle c in foo as: _ZZ3foovE1cB6foobar and d in there as _ZZ3foovE1dB3qux and similarly both compilers mangle c in bar as _ZZ3barI1TB3quxEivE1cB6foobar but g++ mangles d in bar as _ZZ3barI1TB3quxEivE1dB3qux while clang++ mangles it as just _ZZ3barI1TB3quxEivE1d No idea what is right or wrong according to Itanium mangling. 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. (cp_finish_decl): Add DECOMP argument defaulted to nullptr. (cp_maybe_mangle_decomp): Remove declaration. * 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. * 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_convert_range_for, cp_parser_decomposition_declaration, cp_finish_omp_range_for): Don't call cp_maybe_mangle_decomp, adjust cp_finish_decl callers. * pt.cc (tsubst_expr): Likewise. 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 10:32:41.519579280 +0200 +++ gcc/common.opt 2023-08-28 10:35:30.337342832 +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-28 10:32:42.322568643 +0200 +++ gcc/doc/invoke.texi 2023-08-28 10:35:30.342342766 +0200 @@ -3016,6 +3016,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 10:32:41.462580035 +0200 +++ gcc/c-family/c-opts.cc 2023-08-28 10:35:30.338342819 +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-28 10:33:10.972189104 +0200 +++ gcc/cp/cp-tree.h 2023-08-28 10:41:19.782716871 +0200 @@ -6858,7 +6858,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); @@ -6891,9 +6891,9 @@ 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 int cp_complete_array_type (tree *, tree, bool); extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t); --- gcc/cp/decl.cc.jj 2023-08-28 10:32:42.170570656 +0200 +++ gcc/cp/decl.cc 2023-08-28 12:10:38.973074234 +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, tree, unsigned int); + /* 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->decl, decomp->count); + /* 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,7 +9080,7 @@ lookup_decomp_type (tree v) /* Mangle a decomposition declaration if needed. Arguments like in cp_finish_decomp. */ -void +static void cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) { if (!processing_template_decl @@ -9082,6 +9092,25 @@ cp_maybe_mangle_decomp (tree decl, tree tree d = first; for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) v[count - i - 1] = d; + if (DECL_FUNCTION_SCOPE_P (decl)) + { + size_t sz = 3; + for (unsigned int i = 0; i < 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 < 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); } --- gcc/cp/mangle.cc.jj 2023-08-28 10:32:42.172570630 +0200 +++ gcc/cp/mangle.cc 2023-08-28 10:35:30.333342885 +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,21 @@ 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 + && 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 +4372,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 +4572,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 +4645,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-28 10:33:10.985188932 +0200 +++ gcc/cp/parser.cc 2023-08-28 11:06:51.260457348 +0200 @@ -14182,15 +14182,20 @@ cp_convert_range_for (tree statement, tr tf_warning_or_error); finish_for_expr (expression, statement); + cp_decomp decomp_data, *decomp = nullptr; if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) - cp_maybe_mangle_decomp (range_decl, decomp_first_name, decomp_cnt); + { + decomp_data.decl = decomp_first_name; + decomp_data.count = decomp_cnt; + decomp = &decomp_data; + } /* 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); @@ -15890,9 +15895,10 @@ 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)); + (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT), + &decomp); cp_finish_decomp (decl, prev, v.length ()); } } @@ -43697,27 +43703,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_data, *decomp = nullptr; 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_data.decl = TREE_VEC_ELT (TREE_CHAIN (orig), 3); + decomp_data.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_data.decl; + for (unsigned i = 0; i < decomp_data.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); + decomp = &decomp_data; } /* The declaration is initialized with *__begin inside the loop body. */ @@ -43725,9 +43730,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->decl, decomp->count); } /* Return true if next tokens contain a standard attribute that contains --- gcc/cp/pt.cc.jj 2023-08-28 10:33:11.045188137 +0200 +++ gcc/cp/pt.cc 2023-08-28 10:49:36.880140901 +0200 @@ -19043,8 +19043,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_data, *decomp = nullptr; + tree ndecl = error_mark_node; tree asmspec_tree = NULL_TREE; maybe_push_decl (decl); @@ -19056,9 +19056,13 @@ 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); + { + ndecl = tsubst_decomp_names (decl, pattern_decl, args, + complain, in_decl, + &decomp_data.decl, + &decomp_data.count); + decomp = &decomp_data; + } init = tsubst_init (init, decl, args, complain, in_decl); @@ -19066,9 +19070,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 +19086,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->decl, decomp->count); } } } --- gcc/testsuite/g++.dg/cpp2a/decomp8.C.jj 2023-08-28 10:35:30.337342832 +0200 +++ gcc/testsuite/g++.dg/cpp2a/decomp8.C 2023-08-28 12:42:30.747030644 +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-28 12:21:50.292919000 +0200 +++ gcc/testsuite/g++.dg/cpp2a/decomp9.C 2023-08-28 12:33:25.478452184 +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 12:10:42.209890842 +0200 +++ gcc/testsuite/g++.dg/abi/macro0.C 2023-08-28 15:46:51.205462641 +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