On 1/13/26 8:07 PM, Jakub Jelinek wrote:
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)
+       {

Please add a comment about why we aren't using build_ here.

+         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);

Why not use cp_build_qualified_type unconditionally? Needs a comment if there's a reason.

+  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


Reply via email to