On Tue, Jan 13, 2026 at 06:45:11PM +0800, Jason Merrill wrote: > > Or shall I go the copy_node way for array_as_string instead? > > copy_node sounds better to me.
So like this if it passes full bootstrap/regtest? So far it passed GXX_TESTSUITE_STDS=98,20,26 make check-gcc check-g++ RUNTESTFLAGS="dg.exp='pr101312* W*parameter* attr-access* Warr*bound* Wbuiltin-decl*'" i.e. tests from this PR and tests which do use the array_as_string hack. 2026-01-13 Jakub Jelinek <[email protected]> PR c/101312 gcc/ * langhooks.h (struct lang_hooks_for_types): Remove copy_lang_qualifiers. Add build_lang_qualified_type. * langhooks.cc (lhd_build_lang_qualified_type): New function. * langhooks-def.h (lhd_build_lang_qualified_type): Declare. (LANG_HOOKS_COPY_LANG_QUALIFIERS): Remove. (LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE): Add. (LANG_HOOKS_FOR_TYPES_INITIALIZER): Use LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE instead of LANG_HOOKS_COPY_LANG_QUALIFIERS. * attribs.cc (build_type_attribute_qual_variant): Use lang_hooks.types.build_lang_qualified_type instead of build_qualified_type and/or build_qualified_type with optional lang_hooks.types.copy_lang_qualifiers call. (attr_access::array_as_string): Use "array " attribute instead of "array". If attribute has been created or intended quals differ from quals of build_array_type, use copy_node and adjust quals and attributes on the copy, print and then ggc_free. gcc/c-family/ * c-pretty-print.cc (c_pretty_printer::direct_abstract_declarator): Look up "array " attribute instead of "array". gcc/c/ * c-tree.h (c_build_lang_qualified_type): Declare. * c-objc-common.h (LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE): Define. * c-objc-common.cc (c_build_lang_qualified_type): New function. gcc/cp/ * cp-tree.h (cxx_build_lang_qualified_type): Declare. * cp-objcp-common.h (LANG_HOOKS_COPY_LANG_QUALIFIERS): Remove. (LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE): Define. * tree.cc (cxx_build_lang_qualified_type): New function. gcc/testsuite/ * c-c++-common/pr101312-1.c: New test. * c-c++-common/pr101312-2.c: New test. --- gcc/langhooks.h.jj 2026-01-02 09:56:10.209335806 +0100 +++ gcc/langhooks.h 2026-01-13 12:25:21.563194623 +0100 @@ -134,9 +134,10 @@ struct lang_hooks_for_types FUNCTION_TYPE or METHOD_TYPE. */ bool (*type_hash_eq) (const_tree, const_tree); - /* If non-NULL, return TYPE1 with any language-specific modifiers copied from - TYPE2. */ - tree (*copy_lang_qualifiers) (const_tree, const_tree); + /* Return a version of the TYPE, qualified as indicated by the + TYPE_QUALS in a language-specific way, if one exists, otherwise create it. + If OTYPE is non-NULL, copy extra language modifiers from it too. */ + tree (*build_lang_qualified_type) (tree, tree, int); /* Return TRUE if TYPE uses a hidden descriptor and fills in information for the debugger about the array bounds, strides, etc. */ --- gcc/langhooks.cc.jj 2026-01-02 09:56:10.209335806 +0100 +++ gcc/langhooks.cc 2026-01-13 12:25:21.564194606 +0100 @@ -202,6 +202,16 @@ lhd_register_builtin_type (tree ARG_UNUS { } +/* Return a version of the TYPE, qualified as indicated by the + TYPE_QUALS, if one exists. If no qualified version exists yet, + creates it and returns it. */ +tree +lhd_build_lang_qualified_type (tree type, tree ARG_UNUSED (otype), + int type_quals) +{ + return build_qualified_type (type, type_quals); +} + /* Invalid use of an incomplete type. */ void lhd_incomplete_type_error (location_t ARG_UNUSED (loc), --- gcc/langhooks-def.h.jj 2026-01-02 09:56:10.208335823 +0100 +++ gcc/langhooks-def.h 2026-01-13 12:25:21.565026190 +0100 @@ -63,6 +63,7 @@ extern tree lhd_type_for_size (unsigned extern void lhd_incomplete_type_error (location_t, const_tree, const_tree); extern tree lhd_type_promotes_to (tree); extern void lhd_register_builtin_type (tree, const char *); +extern tree lhd_build_lang_qualified_type (tree, tree, int); extern bool lhd_decl_ok_for_sibcall (const_tree); extern size_t lhd_tree_size (enum tree_code); extern HOST_WIDE_INT lhd_to_target_charset (HOST_WIDE_INT); @@ -212,7 +213,7 @@ extern tree lhd_unit_size_without_reusab #define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \ lhd_omp_firstprivatize_type_sizes #define LANG_HOOKS_TYPE_HASH_EQ NULL -#define LANG_HOOKS_COPY_LANG_QUALIFIERS NULL +#define LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE lhd_build_lang_qualified_type #define LANG_HOOKS_GET_ARRAY_DESCR_INFO NULL #define LANG_HOOKS_GET_SUBRANGE_BOUNDS NULL #define LANG_HOOKS_GET_TYPE_BIAS NULL @@ -240,7 +241,7 @@ extern tree lhd_unit_size_without_reusab LANG_HOOKS_TYPE_MAX_SIZE, \ LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES, \ LANG_HOOKS_TYPE_HASH_EQ, \ - LANG_HOOKS_COPY_LANG_QUALIFIERS, \ + LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE, \ LANG_HOOKS_GET_ARRAY_DESCR_INFO, \ LANG_HOOKS_GET_SUBRANGE_BOUNDS, \ LANG_HOOKS_GET_TYPE_BIAS, \ --- gcc/attribs.cc.jj 2026-01-02 09:56:09.905340942 +0100 +++ gcc/attribs.cc 2026-01-13 13:00:52.691612496 +0100 @@ -1322,14 +1322,15 @@ build_type_attribute_qual_variant (tree warning (OPT_Wattributes, "ignoring attributes applied to %qT after definition", TYPE_MAIN_VARIANT (ttype)); - return build_qualified_type (ttype, quals); + return lang_hooks.types.build_lang_qualified_type (ttype, NULL_TREE, + quals); } - ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED); - if (lang_hooks.types.copy_lang_qualifiers - && otype != TYPE_MAIN_VARIANT (otype)) - ttype = (lang_hooks.types.copy_lang_qualifiers - (ttype, TYPE_MAIN_VARIANT (otype))); + tree mtype = NULL_TREE; + if (otype != TYPE_MAIN_VARIANT (otype)) + mtype = TYPE_MAIN_VARIANT (otype); + ttype = lang_hooks.types.build_lang_qualified_type (ttype, mtype, + TYPE_UNQUALIFIED); tree dtype = ntype = build_distinct_type_copy (ttype); @@ -1354,13 +1355,15 @@ build_type_attribute_qual_variant (tree else if (TYPE_CANONICAL (ntype) == ntype) TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype); - ttype = build_qualified_type (ntype, quals); - if (lang_hooks.types.copy_lang_qualifiers - && otype != TYPE_MAIN_VARIANT (otype)) - ttype = lang_hooks.types.copy_lang_qualifiers (ttype, otype); + if (otype != TYPE_MAIN_VARIANT (otype)) + mtype = otype; + else + mtype = NULL_TREE; + ttype = lang_hooks.types.build_lang_qualified_type (ntype, mtype, quals); } else if (TYPE_QUALS (ttype) != quals) - ttype = build_qualified_type (ttype, quals); + ttype = lang_hooks.types.build_lang_qualified_type (ttype, NULL_TREE, + quals); return ttype; } @@ -2620,6 +2623,7 @@ std::string attr_access::array_as_string (tree type) const { std::string typstr; + bool free_type = false; if (type == error_mark_node) return std::string (); @@ -2660,12 +2664,26 @@ attr_access::array_as_string (tree type) [*] is represented the same as [0] this hack only works for the most significant bound like static and the others are rendered as [0]. */ - arat = build_tree_list (get_identifier ("array"), flag); + arat = build_tree_list (get_identifier ("array "), flag); } const int quals = TYPE_QUALS (type); type = build_array_type (eltype, index_type); - type = build_type_attribute_qual_variant (type, arat, quals); + if (arat || TYPE_QUALS (type) != quals) + { + type = copy_node (type); + if (arat) + { + TREE_CHAIN (arat) = TYPE_ATTRIBUTES (type); + TYPE_ATTRIBUTES (type) = arat; + } + TYPE_READONLY (type) = (quals & TYPE_QUAL_CONST) != 0; + TYPE_VOLATILE (type) = (quals & TYPE_QUAL_VOLATILE) != 0; + TYPE_ATOMIC (type) = (quals & TYPE_QUAL_ATOMIC) != 0; + TYPE_RESTRICT (type) = (quals & TYPE_QUAL_RESTRICT) != 0; + TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (quals); + free_type = true; + } } /* Format the type using the current pretty printer. The generic tree @@ -2673,6 +2691,8 @@ attr_access::array_as_string (tree type) std::unique_ptr<pretty_printer> pp (global_dc->clone_printer ()); pp_printf (pp.get (), "%qT", type); typstr = pp_formatted_text (pp.get ()); + if (free_type) + ggc_free (type); return typstr; } --- gcc/c-family/c-pretty-print.cc.jj 2026-01-02 09:56:09.911340841 +0100 +++ gcc/c-family/c-pretty-print.cc 2026-01-13 12:25:21.566194572 +0100 @@ -634,7 +634,7 @@ c_pretty_printer::direct_abstract_declar add_space = true; } - if (tree arr = lookup_attribute ("array", TYPE_ATTRIBUTES (t))) + if (tree arr = lookup_attribute ("array ", TYPE_ATTRIBUTES (t))) { if (TREE_VALUE (arr)) { --- gcc/c/c-tree.h.jj 2026-01-02 09:56:09.916340756 +0100 +++ gcc/c/c-tree.h 2026-01-13 12:25:21.567295446 +0100 @@ -776,6 +776,7 @@ extern tree c_finish_bc_name (location_t /* in c-objc-common.cc */ extern bool c_objc_common_init (void); +extern tree c_build_lang_qualified_type (tree, tree, int); extern bool c_missing_noreturn_ok_p (tree); extern bool c_warn_unused_global_decl (const_tree); extern void c_initialize_diagnostics (diagnostics::context *); --- gcc/c/c-objc-common.h.jj 2026-01-02 09:56:09.914340790 +0100 +++ gcc/c/c-objc-common.h 2026-01-13 12:25:21.567604522 +0100 @@ -59,6 +59,8 @@ extern void c_register_features (); #define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier #undef LANG_HOOKS_TYPES_COMPATIBLE_P #define LANG_HOOKS_TYPES_COMPATIBLE_P c_types_compatible_p +#undef LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE +#define LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE c_build_lang_qualified_type #undef LANG_HOOKS_MISSING_NORETURN_OK_P #define LANG_HOOKS_MISSING_NORETURN_OK_P c_missing_noreturn_ok_p #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU --- gcc/c/c-objc-common.cc.jj 2026-01-02 09:56:09.914340790 +0100 +++ gcc/c/c-objc-common.cc 2026-01-13 12:25:21.567879879 +0100 @@ -70,6 +70,17 @@ c_register_features () } } +/* Langhook for building qualified types. */ + +tree +c_build_lang_qualified_type (tree type, tree, int type_quals) +{ + if (TREE_CODE (type) == ARRAY_TYPE) + return c_build_qualified_type (type, type_quals); + else + return build_qualified_type (type, type_quals); +} + bool c_missing_noreturn_ok_p (tree decl) { --- gcc/cp/cp-tree.h.jj 2026-01-13 09:56:02.499182579 +0100 +++ gcc/cp/cp-tree.h 2026-01-13 12:25:21.568194537 +0100 @@ -7376,6 +7376,7 @@ extern tmpl_spec_kind current_tmpl_spec_ extern tree cxx_builtin_function (tree decl); extern tree cxx_builtin_function_ext_scope (tree decl); extern tree cxx_simulate_builtin_function_decl (tree); +extern tree cxx_build_lang_qualified_type (tree, tree, int); extern tree check_elaborated_type_specifier (enum tag_types, tree, bool); extern void warn_extern_redeclared_static (tree, tree); extern tree cxx_comdat_group (tree); --- gcc/cp/cp-objcp-common.h.jj 2026-01-02 09:56:10.101337631 +0100 +++ gcc/cp/cp-objcp-common.h 2026-01-13 12:25:21.569927321 +0100 @@ -112,8 +112,8 @@ extern tree cxx_simulate_record_decl (lo cxx_simulate_builtin_function_decl #undef LANG_HOOKS_TYPE_HASH_EQ #define LANG_HOOKS_TYPE_HASH_EQ cxx_type_hash_eq -#undef LANG_HOOKS_COPY_LANG_QUALIFIERS -#define LANG_HOOKS_COPY_LANG_QUALIFIERS cxx_copy_lang_qualifiers +#undef LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE +#define LANG_HOOKS_BUILD_LANG_QUALIFIED_TYPE cxx_build_lang_qualified_type #undef LANG_HOOKS_MISSING_NORETURN_OK_P #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU --- gcc/cp/tree.cc.jj 2026-01-02 09:56:10.115337394 +0100 +++ gcc/cp/tree.cc 2026-01-13 12:25:21.570194503 +0100 @@ -1469,6 +1469,21 @@ c_build_qualified_type (tree type, int t return cp_build_qualified_type (type, type_quals); } +/* Implementation of the build_lang_qualified_type langhook. */ +tree +cxx_build_lang_qualified_type (tree type, tree otype, int type_quals) +{ + if (TREE_CODE (type) == ARRAY_TYPE) + return cp_build_qualified_type (type, type_quals); + else + { + tree ret = build_qualified_type (type, type_quals); + if (otype) + ret = cxx_copy_lang_qualifiers (ret, otype); + return ret; + } +} + /* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles arrays correctly. In particular, if TYPE is an array of T's, and --- gcc/testsuite/c-c++-common/pr101312-1.c.jj 2026-01-13 12:25:21.571245540 +0100 +++ gcc/testsuite/c-c++-common/pr101312-1.c 2026-01-13 12:25:21.571245540 +0100 @@ -0,0 +1,4 @@ +/* PR c/101312 */ +/* { dg-do compile } */ + +volatile int a[1] __attribute__((may_alias)); --- gcc/testsuite/c-c++-common/pr101312-2.c.jj 2026-01-13 12:25:21.571543820 +0100 +++ gcc/testsuite/c-c++-common/pr101312-2.c 2026-01-13 12:25:21.571543820 +0100 @@ -0,0 +1,5 @@ +/* PR c/101312 */ +/* { dg-do compile } */ +/* { dg-options "-g" } */ + +volatile int a[1] __attribute__((may_alias)); Jakub
