Hi!

The following testcases ICE in various ways because of the interaction
between attributes and C/C++ c*_build_qualified_type behavior on array
types and how they affect TYPE_CANONICAL.
For array types, C/C++ moves qualifiers to the element type, but
when a cv qualified array build that way has an attribute applied to it,
we call build_type_attribute_qual_variant and that doesn't have that
handling and builds non-qualified version of the array type with qualified
element type and puts it as TYPE_CANONICAL of the type with attribute
which is a distinct type copy.

The following patch adds a langhook, so that even
build_type_attribute_qual_variant uses for C/C++ for array types
c*_build_qualified_type.
There has been already a related langhook
lang_hooks.types.copy_lang_qualifiers used solely for C++, so instead
of adding another langhook this adds a combined langhook for those two,
where C can handle array types specially and otherwise build_qualified_type,
while C++ ditto + do the function/method type modifiers propagation as
well.

Unfortunately there is a terrible array_as_string hack used by some
of the middle-end warnings which creates some array type with sometimes
an artificial attribute and then has hacks in the c-family type printing
to tweak the printed form, and this hack relies on the previous behavior
of build_type_attribute_qual_variant where it even for C/C++ kept
element type quals unmodified and added normally invalid quals on the
array type itself.  The patch right now temporarily overrides the
langhook to the generic version, so it keeps working (and renames the
attribute from "array" to "array " to make it clear it is internal
attribute users can't specify even in vendor attributes).
Though, I wonder if maybe it wouldn't be better to simply build
the array type type = build_array_type (eltype, index_type); as now,
and instead of the build_type_attribute_qual_variant call
copy_node, prepend TYPE_ATTRIBUTES, change quals on the copy,
print it and then ggc_free it, I think such types don't deserve to be
cached in variant type lists etc.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Or shall I go the copy_node way for array_as_string instead?

2025-12-18  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".  Temporarily override
        lang_hooks.types.build_lang_qualified_type to
        lhd_build_lang_qualified_type as the hack relies on that behavior.
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  2025-07-27 17:19:23.607127969 +0200
+++ gcc/langhooks.h     2025-12-18 12:57:10.780239979 +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 2025-10-11 22:30:51.527481745 +0200
+++ gcc/langhooks.cc    2025-12-18 12:19:41.234383962 +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      2025-07-27 17:19:23.607127969 +0200
+++ gcc/langhooks-def.h 2025-12-18 12:17:28.864684315 +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   2025-12-08 23:28:55.081950885 +0100
+++ gcc/attribs.cc      2025-12-18 13:16:24.200295574 +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;
 }
@@ -2660,12 +2663,24 @@ 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);
+      /* This terrible hack relies on
+        lang_hooks.types.build_lang_qualified_type not honoring the
+        C/C++ FE array handling, so that quals from the pointed type
+        stay unmodified on element type and quals from the pointer
+        type are installed without errors on the array type.  */
+      auto save_build_lang_qualified_type
+       = lang_hooks.types.build_lang_qualified_type;
+      extern tree lhd_build_lang_qualified_type (tree, tree, int);
+      lang_hooks.types.build_lang_qualified_type
+       = lhd_build_lang_qualified_type;
       type = build_type_attribute_qual_variant (type, arat, quals);
+      lang_hooks.types.build_lang_qualified_type
+       = save_build_lang_qualified_type;
     }
 
   /* Format the type using the current pretty printer.  The generic tree
--- gcc/c-family/c-pretty-print.cc.jj   2025-09-23 15:22:09.984552905 +0200
+++ gcc/c-family/c-pretty-print.cc      2025-12-18 13:05:30.823630822 +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   2025-11-27 21:34:24.276458859 +0100
+++ gcc/c/c-tree.h      2025-12-18 12:14:13.951071552 +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    2025-05-30 14:37:31.489079636 +0200
+++ gcc/c/c-objc-common.h       2025-12-16 22:26:49.120983402 +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   2025-09-23 15:22:09.986552878 +0200
+++ gcc/c/c-objc-common.cc      2025-12-18 12:14:00.347307960 +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 2025-12-16 22:26:28.436420328 +0100
+++ gcc/cp/cp-tree.h    2025-12-18 12:12:07.605267206 +0100
@@ -7370,6 +7370,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 2025-05-30 14:32:05.168473440 +0200
+++ gcc/cp/cp-objcp-common.h    2025-12-16 22:26:49.122248232 +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   2025-11-24 18:30:41.669332263 +0100
+++ gcc/cp/tree.cc      2025-12-18 12:57:31.851426620 +0100
@@ -1390,6 +1390,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  2025-12-16 22:26:49.123005327 
+0100
+++ gcc/testsuite/c-c++-common/pr101312-1.c     2025-12-16 22:26:49.123005327 
+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  2025-12-16 22:26:49.123089596 
+0100
+++ gcc/testsuite/c-c++-common/pr101312-2.c     2025-12-16 22:26:49.123089596 
+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