c++, v3: Fix up mangling of function/block scope static structured bindings and emit abi tags [PR111069]
Checks
Commit Message
On Thu, Aug 31, 2023 at 01:11:57PM -0400, Jason Merrill wrote:
> > 2023-08-28 Jakub Jelinek <jakub@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 <jakub@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.
Jakub
Comments
On 8/31/23 15:14, Jakub Jelinek wrote:
> On Thu, Aug 31, 2023 at 01:11:57PM -0400, Jason Merrill wrote:
>>> 2023-08-28 Jakub Jelinek <jakub@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?
OK.
> 2023-08-31 Jakub Jelinek <jakub@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
>
@@ -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=
@@ -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
@@ -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;
@@ -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 &);
@@ -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:
@@ -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++);
@@ -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
@@ -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));
}
@@ -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_" } }
@@ -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" } }
@@ -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