c, c++: Use c*_build_qualified_type instead of build_qualified_type from within build_type_attribute_qual_variant [PR101312]

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 stops using build_type_attribute_qual_variant
for that and instead uses copy_node on the type and adjusts the quals and
adds the attribute to the copy and then ggc_frees it.  Also it renames the
attribute from "array" to "array " to make it clear it is internal
attribute users can't specify even in vendor attributes.

2026-01-28  Jakub Jelinek  <jakub@redhat.com>

	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.
This commit is contained in:
Jakub Jelinek
2026-01-28 09:50:26 +01:00
committed by Jakub Jelinek
parent 5c2a5bfcd4
commit 3d2a91a376
13 changed files with 107 additions and 21 deletions

View File

@@ -1322,14 +1322,15 @@ build_type_attribute_qual_variant (tree otype, tree attribute, int quals)
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 otype, tree attribute, int quals)
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;
}
@@ -2652,6 +2655,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 ();
@@ -2692,12 +2696,35 @@ attr_access::array_as_string (tree type) const
[*] 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)
{
/* We create a new array type which is only used during
printing. Can't use build_type_attribute_qual_variant
because it might with some lang hooks e.g. try to push
qualifiers to the element type, while for the printing
this wants the element type qualifiers to be unmodified
and ARRAY_TYPE qualifiers to be a copy of the pointer
type qualifiers. Furthermore, a type with somtimes
weird qualifiers or artificial attribute should be
freed right after the use. */
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
@@ -2705,6 +2732,8 @@ attr_access::array_as_string (tree type) const
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;
}

View File

@@ -634,7 +634,7 @@ c_pretty_printer::direct_abstract_declarator (tree t)
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))
{

View File

@@ -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)
{

View File

@@ -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

View File

@@ -780,6 +780,7 @@ extern tree c_finish_bc_name (location_t, tree, bool);
/* 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 *);

View File

@@ -112,8 +112,8 @@ extern tree cxx_simulate_record_decl (location_t, const char *,
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

View File

@@ -7540,6 +7540,7 @@ extern tmpl_spec_kind current_tmpl_spec_kind (int);
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);

View File

@@ -1470,6 +1470,27 @@ c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */,
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)
{
/* Only handle ARRAY_TYPEs using cp_build_qualified_type, so that
quals are pushed to the element type. That is needed for PR101312.
For other types just keep using build_qualified_type with
cxx_copy_lang_qualifiers if needed, otherwise we can run into
issues with FUNCTION_TYPEs with cv-qualifier-seq vs. type-specifier,
or REFERENCE_TYPE which will error on certain 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

View File

@@ -63,6 +63,7 @@ extern tree lhd_type_for_size (unsigned precision, int unsignedp);
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_reusable_padding (tree);
#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_reusable_padding (tree);
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, \

View File

@@ -202,6 +202,16 @@ lhd_register_builtin_type (tree ARG_UNUSED (type),
{
}
/* 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),

View File

@@ -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. */

View File

@@ -0,0 +1,4 @@
/* PR c/101312 */
/* { dg-do compile } */
volatile int a[1] __attribute__((may_alias));

View File

@@ -0,0 +1,5 @@
/* PR c/101312 */
/* { dg-do compile } */
/* { dg-options "-g" } */
volatile int a[1] __attribute__((may_alias));