https://gcc.gnu.org/g:9eae9268e41463927c9383004e58708048ec379f
commit r15-4812-g9eae9268e41463927c9383004e58708048ec379f Author: Martin Uecker <uec...@tugraz.at> Date: Tue Oct 22 23:25:00 2024 +0200 c: detect variably-modified types [PR117145,PR117245,PR100420] This fixes two cases where variably-modified types were not recognized as such. The first is when building composite types and the other when a type is reconstructed for the 'vector' attribute. Construction of types in the C FE is reorganized to use c_build_* functions which are responsible for setting C_TYPE_VARIABLE_SIZE, C_TYPE_VARIABLY_MODIFIED and TYPE_TYPELESS_STORAGE based on the properties of the type itself and these replace all other logic elsewhere (e.g. in grokdeclarator). A new 'c_reconstruct_complex_type' based on these functions is introduced which is called via a language hook when the 'vector' attribute is processed (as for C++). One problem is are arrays of unspecified size 'T[*]' which were represented identically to zero-sized arrays but with C_TYPE_VARIABLE_SIZE set. To avoid having to create distinct type copies for this, the representation was changed to make it a natural VLA by giving it an upper bound of '(0, 0)'. This also then allows fixing of PR100420 where such arrays were printed as 'T[0]'. Finally, a new function 'c_verify_type' checks consistency of properties specific to C FE and is called when checking is on. PR c/117145 PR c/117245 PR c/100420 gcc/c/ChangeLog: * c-decl.cc (c_build_pointer_type): Move to c-typeck.cc (grokdeclarator): Simplify logic. (match_builtin_function_types): Adapt. (push_decl): Adapt. (implicitly_declare): Adapt. (c_update_type_canonical): Adapt. (c_make_fname_decl): Adapt. (start_function): Adapt. * c-objc-common.h: Add LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE. * c-tree.h: Add prototypes. * c-typeck.cc (c_verify_type): New function. (c_set_type_bits). New function. (c_build_pointer_type): Moved from c-decl.cc. (c_build_pointer_type_for_mode): New function. (c_build_function_type): New function. (c_build_array_type): New function. (c_build_type_attribute_variant): New function. (c_reconstruct_complex_type): New function. (c_build_functype_attribute_variant): Renamed. (array_to_pointer_conversion): Simplify logic. (composite_type_internal): Simplify logic.. (build_unary_op): Simplify logic.. (comptypes_verify): Add checking assertions. (c_build_qualified_type): Add checking assertions. (c_build_function_call_vec): Adapt. (qualify_type): Adapt. (build_functype_attribute_variant): Adapt. (common_pointer_type): Adapt. (c_common_type): Adapt. (convert_for_assignment): Adapt. (type_or_builtin_type): Adapt. (build_access_with_size_for_counted_by): Adapt. (build_conditional_expr): Adapt. (build_modify_expr): Adapt. (build_binary_op): Adapt. (build_omp_array_section): Adapt. (handle_omp_array_sections): Adapt. (c_finish_omp_clauses): Adapt. * c-parser.cc (c_parser_typeof_specifier): Adapt. (c_parser_generic_selection): Adapt. gcc/c-family/ChangeLog: * c-pretty-print.cc (c_pretty_printer::direct_abstract_declarator): Detect arrays of unspecified size. gcc/testsuite/ChangeLog: * gcc.dg/c23-tag-composite-11.c: New test. * gcc.dg/Warray-parameter-4.c: Resolve xfails. * gcc.dg/Wvla-parameter-2.c: Resolve xfails. * gcc.dg/Wvla-parameter-3.c: Resolve xfails. * gcc.dg/pr117145-1.c: New test. * gcc.dg/pr117145-2.c: New test. * gcc.dg/pr117245.c: New test. Diff: --- gcc/c-family/c-pretty-print.cc | 6 +- gcc/c/c-decl.cc | 130 ++++------- gcc/c/c-objc-common.h | 2 + gcc/c/c-parser.cc | 4 +- gcc/c/c-tree.h | 7 + gcc/c/c-typeck.cc | 331 ++++++++++++++++++++++------ gcc/testsuite/gcc.dg/Warray-parameter-4.c | 6 +- gcc/testsuite/gcc.dg/Wvla-parameter-2.c | 15 +- gcc/testsuite/gcc.dg/Wvla-parameter-3.c | 11 +- gcc/testsuite/gcc.dg/c23-tag-composite-11.c | 27 +++ gcc/testsuite/gcc.dg/pr117145-1.c | 14 ++ gcc/testsuite/gcc.dg/pr117145-2.c | 10 + gcc/testsuite/gcc.dg/pr117245.c | 17 ++ 13 files changed, 393 insertions(+), 187 deletions(-) diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc index fadb9e3ecfef..810e48780492 100644 --- a/gcc/c-family/c-pretty-print.cc +++ b/gcc/c-family/c-pretty-print.cc @@ -690,7 +690,11 @@ c_pretty_printer::direct_abstract_declarator (tree t) maxval = TREE_OPERAND (maxval, 0); } - expression (maxval); + /* This covers unspecified bounds. */ + if (TREE_CODE (maxval) == COMPOUND_EXPR) + pp_string (this, "*"); + else + expression (maxval); } } else if (TYPE_SIZE (t)) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 9cb33e0e9d36..42d329e4fd52 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -716,22 +716,9 @@ add_stmt (tree t) return t; } - -/* Build a pointer type using the default pointer mode. */ -static tree -c_build_pointer_type (tree to_type) -{ - addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC - : TYPE_ADDR_SPACE (to_type); - machine_mode pointer_mode; - if (as != ADDR_SPACE_GENERIC || c_default_pointer_mode == VOIDmode) - pointer_mode = targetm.addr_space.pointer_mode (as); - else - pointer_mode = c_default_pointer_mode; - return build_pointer_type_for_mode (to_type, pointer_mode, false); -} + /* Return true if we will want to say something if a goto statement @@ -1923,7 +1910,7 @@ match_builtin_function_types (tree newtype, tree oldtype, newargs = TREE_CHAIN (newargs); } - tree trytype = build_function_type (newrettype, tryargs); + tree trytype = c_build_function_type (newrettype, tryargs); /* Allow declaration to change transaction_safe attribute. */ tree oldattrs = TYPE_ATTRIBUTES (oldtype); @@ -1936,7 +1923,7 @@ match_builtin_function_types (tree newtype, tree oldtype, oldattrs = tree_cons (get_identifier ("transaction_safe"), NULL_TREE, oldattrs); - return build_type_attribute_variant (trytype, oldattrs); + return c_build_type_attribute_variant (trytype, oldattrs); } /* Subroutine of diagnose_mismatched_decls. Check for function type @@ -3397,9 +3384,9 @@ pushdecl (tree x) if (TREE_CODE (b_use->decl) == FUNCTION_DECL && fndecl_built_in_p (b_use->decl)) thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES - (b_use->u.type)); + = c_build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES + (b_use->u.type)); TREE_TYPE (b_use->decl) = thistype; } return b_use->decl; @@ -3497,8 +3484,8 @@ pushdecl (tree x) b->u.type = TREE_TYPE (b->decl); /* Propagate the type attributes to the decl. */ thistype - = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES (b->u.type)); + = c_build_type_attribute_variant (thistype, + TYPE_ATTRIBUTES (b->u.type)); TREE_TYPE (b->decl) = thistype; bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true, locus); @@ -3896,9 +3883,9 @@ implicitly_declare (location_t loc, tree functionid) } if (fndecl_built_in_p (decl)) { - newtype = build_type_attribute_variant (newtype, - TYPE_ATTRIBUTES - (TREE_TYPE (decl))); + newtype = c_build_type_attribute_variant (newtype, + TYPE_ATTRIBUTES + (TREE_TYPE (decl))); if (!comptypes (newtype, TREE_TYPE (decl))) { auto_diagnostic_group d; @@ -4838,8 +4825,8 @@ c_make_fname_decl (location_t loc, tree id, int type_dep) tree decl, type, init; size_t length = strlen (name); - type = build_array_type (char_type_node, - build_index_type (size_int (length))); + type = c_build_array_type (char_type_node, + build_index_type (size_int (length))); type = c_build_qualified_type (type, TYPE_QUAL_CONST); decl = build_decl (loc, VAR_DECL, id, type); @@ -7224,8 +7211,6 @@ grokdeclarator (const struct c_declarator *declarator, array_parm_static = false; } - bool varmod = C_TYPE_VARIABLY_MODIFIED (type); - switch (declarator->kind) { case cdk_attrs: @@ -7507,31 +7492,20 @@ grokdeclarator (const struct c_declarator *declarator, /* ISO C99 Flexible array members are effectively identical to GCC's zero-length array extension. */ - if (flexible_array_member || array_parm_vla_unspec_p) - itype = build_range_type (sizetype, size_zero_node, - NULL_TREE); + if (flexible_array_member) + itype = build_index_type (NULL_TREE); } - else if (decl_context == PARM) + + if (array_parm_vla_unspec_p) { - if (array_parm_vla_unspec_p) - { - itype = build_range_type (sizetype, size_zero_node, NULL_TREE); - size_varies = true; - } - } - else if (decl_context == TYPENAME) - { - if (array_parm_vla_unspec_p) - { - /* C99 6.7.5.2p4 */ - warning (0, "%<[*]%> not in a declaration"); - /* We use this to avoid messing up with incomplete - array types of the same type, that would - otherwise be modified below. */ - itype = build_range_type (sizetype, size_zero_node, - NULL_TREE); - size_varies = true; - } + /* C99 6.7.5.2p4 */ + if (decl_context == TYPENAME) + warning (0, "%<[*]%> not in a declaration"); + /* Array of unspecified size. */ + tree upper = build2 (COMPOUND_EXPR, TREE_TYPE (size_zero_node), + integer_zero_node, size_zero_node); + itype = build_index_type (upper); + size_varies = true; } /* Complain about arrays of incomplete types. */ @@ -7562,34 +7536,15 @@ grokdeclarator (const struct c_declarator *declarator, modify the shared type, so we gcc_assert (itype) below. */ { - /* Identify typeless storage as introduced in C2Y - and supported also in earlier language modes. */ - bool typeless = (char_type_p (type) - && !(type_quals & TYPE_QUAL_ATOMIC)) - || (AGGREGATE_TYPE_P (type) - && TYPE_TYPELESS_STORAGE (type)); - addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) - type = build_qualified_type (type, - ENCODE_QUAL_ADDR_SPACE (as)); - type = build_array_type (type, itype, typeless); + type = c_build_qualified_type (type, + ENCODE_QUAL_ADDR_SPACE (as)); + type = c_build_array_type (type, itype); } if (type != error_mark_node) { - if (size_varies) - { - /* It is ok to modify type here even if itype is - NULL: if size_varies, we're in a - multi-dimensional array and the inner type has - variable size, so the enclosing shared array type - must too. */ - if (size && TREE_CODE (size) == INTEGER_CST) - type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - C_TYPE_VARIABLE_SIZE (type) = 1; - } - /* The GCC extension for zero-length arrays differs from ISO flexible array members in that sizeof yields zero. */ @@ -7601,15 +7556,6 @@ grokdeclarator (const struct c_declarator *declarator, TYPE_SIZE_UNIT (type) = size_zero_node; SET_TYPE_STRUCTURAL_EQUALITY (type); } - if (array_parm_vla_unspec_p) - { - gcc_assert (itype); - /* The type is complete. C99 6.7.5.2p4 */ - type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); - TYPE_SIZE (type) = bitsize_zero_node; - TYPE_SIZE_UNIT (type) = size_zero_node; - SET_TYPE_STRUCTURAL_EQUALITY (type); - } if (!valid_array_size_p (loc, type, name)) type = error_mark_node; @@ -7732,8 +7678,8 @@ grokdeclarator (const struct c_declarator *declarator, } type_quals = TYPE_UNQUALIFIED; - type = build_function_type (type, arg_types, - arg_info->no_named_args_stdarg_p); + type = c_build_function_type (type, arg_types, + arg_info->no_named_args_stdarg_p); declarator = declarator->declarator; /* Set the TYPE_CONTEXTs for each tagged type which is local to @@ -7798,8 +7744,6 @@ grokdeclarator (const struct c_declarator *declarator, default: gcc_unreachable (); } - if (type != error_mark_node) - C_TYPE_VARIABLY_MODIFIED (type) = varmod || size_varies; } *decl_attrs = chainon (returned_attrs, *decl_attrs); *decl_attrs = chainon (decl_id_attrs, *decl_attrs); @@ -8122,7 +8066,7 @@ grokdeclarator (const struct c_declarator *declarator, if (TREE_CODE (type) == FUNCTION_TYPE) { error_at (loc, "field %qE declared as a function", name); - type = build_pointer_type (type); + type = c_build_pointer_type (type); } else if (TREE_CODE (type) != ERROR_MARK && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) @@ -9451,7 +9395,7 @@ c_update_type_canonical (tree t) else { tree - c = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x)); + c = c_build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x)); if (TYPE_STRUCTURAL_EQUALITY_P (c)) { gcc_checking_assert (TYPE_CANONICAL (t) == t); @@ -9486,8 +9430,8 @@ c_update_type_canonical (tree t) continue; if (TYPE_CANONICAL (x) != x || TYPE_REF_CAN_ALIAS_ALL (p)) TYPE_CANONICAL (p) - = build_pointer_type_for_mode (TYPE_CANONICAL (x), TYPE_MODE (p), - false); + = c_build_pointer_type_for_mode (TYPE_CANONICAL (x), TYPE_MODE (p), + false); else TYPE_CANONICAL (p) = p; c_update_type_canonical (p); @@ -10724,9 +10668,9 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, error_at (loc, "return type is an incomplete type"); /* Make it return void instead. */ TREE_TYPE (decl1) - = build_function_type (void_type_node, - TYPE_ARG_TYPES (TREE_TYPE (decl1)), - TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (decl1))); + = c_build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1)), + TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (decl1))); } if (warn_about_return_type) diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index 365b59388038..80b8ec9e8fcb 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -74,6 +74,8 @@ extern void c_register_features (); #define LANG_HOOKS_EMITS_BEGIN_STMT true #undef LANG_HOOKS_FINALIZE_EARLY_DEBUG #define LANG_HOOKS_FINALIZE_EARLY_DEBUG c_common_finalize_early_debug +#undef LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE +#define LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE c_reconstruct_complex_type static const scoped_attribute_specs *const c_objc_attribute_table[] = { diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 90c33970fda3..179c772fb76f 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -4417,7 +4417,7 @@ c_parser_typeof_specifier (c_parser *parser) else if (FUNCTION_POINTER_TYPE_P (ret.spec) && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED) ret.spec - = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec))); + = c_build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec))); } } return ret; @@ -10700,7 +10700,7 @@ c_parser_generic_selection (c_parser *parser) if (FUNCTION_POINTER_TYPE_P (selector_type) && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED) selector_type - = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type))); + = c_build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type))); } if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index a1435e7cb0ca..c8e9731bfc42 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -879,6 +879,13 @@ extern tree c_build_function_call_vec (location_t, const vec<location_t>&, tree, vec<tree, va_gc> *, vec<tree, va_gc> *); extern tree c_omp_clause_copy_ctor (tree, tree, tree); +extern tree c_reconstruct_complex_type (tree, tree); +extern tree c_build_type_attribute_variant (tree ntype, tree attrs); +extern tree c_build_pointer_type (tree type); +extern tree c_build_array_type (tree type, tree domain); +extern tree c_build_function_type (tree type, tree args, bool no = false); +extern tree c_build_pointer_type_for_mode (tree type, machine_mode mode, bool m); + /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index dbc9f885f4a4..6673cbf72947 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -357,6 +357,191 @@ qualify_type (tree type, tree like) | ENCODE_QUAL_ADDR_SPACE (as_common)); } + +/* Check consistency of type TYP.E For derived types, we test that + C_TYPE_VARIABLE_SIZE and C_TYPE_VARIABLY_MODIFIED are consistent with + the requirements of the base type. We also check that arrays with a + non-constant length are marked with C_TYPE_VARIABLE_SIZE. If any + inconsistency is detected false is returned and true otherwise. */ + +static bool +c_verify_type (tree type) +{ + switch (TREE_CODE (type)) + { + case POINTER_TYPE: + case FUNCTION_TYPE: + /* Pointer and funcions can not have variable size. */ + if (C_TYPE_VARIABLE_SIZE (type)) + return false; + /* Pointer and funcions are variably modified if and only if the + return / target type is variably modified. */ + if (C_TYPE_VARIABLY_MODIFIED (type) + != C_TYPE_VARIABLY_MODIFIED (TREE_TYPE (type))) + return false; + break; + case ARRAY_TYPE: + /* An array has variable size if and only if it has a non-constant + dimensions or its element type has variable size. */ + if ((C_TYPE_VARIABLE_SIZE (TREE_TYPE (type)) + || (TYPE_DOMAIN (type) && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + != INTEGER_CST)) + != C_TYPE_VARIABLE_SIZE (type)) + return false; + /* If the element type or the array has variable size, then the + array has variable size and is variably modified. */ + if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (type)) + || C_TYPE_VARIABLE_SIZE (type)) + { + if (!C_TYPE_VARIABLE_SIZE (type)) + return false; + if (!C_TYPE_VARIABLY_MODIFIED (type)) + return false; + } + /* If the element type is variably modified, then also the array. */ + if (C_TYPE_VARIABLY_MODIFIED (TREE_TYPE (type)) + && !C_TYPE_VARIABLY_MODIFIED (type)) + return false; + break; + default: + break; + } + return true; +} + +/* Propagate C_TYPE_VARIABLY_MODIFIED and C_TYPE_VARIABLE_SIZE + from a base type to a newly built derived or qualified type. */ + +static tree +c_set_type_bits (tree new_type, tree old_type) +{ + gcc_checking_assert (c_verify_type (old_type)); + + if (C_TYPE_VARIABLY_MODIFIED (old_type)) + C_TYPE_VARIABLY_MODIFIED (new_type) = true; + + if (TREE_CODE (new_type) == ARRAY_TYPE && C_TYPE_VARIABLE_SIZE (old_type)) + { + C_TYPE_VARIABLY_MODIFIED (new_type) = true; + C_TYPE_VARIABLE_SIZE (new_type) = true; + } + return new_type; +} + +/* Build a pointer type using the default pointer mode. */ + +tree +c_build_pointer_type (tree to_type) +{ + addr_space_t as = to_type == error_mark_node ? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + machine_mode pointer_mode; + + if (as != ADDR_SPACE_GENERIC || c_default_pointer_mode == VOIDmode) + pointer_mode = targetm.addr_space.pointer_mode (as); + else + pointer_mode = c_default_pointer_mode; + + return c_build_pointer_type_for_mode (to_type, pointer_mode, false); +} + +/* Build a pointer type using the given mode. */ + +tree +c_build_pointer_type_for_mode (tree type, machine_mode mode, bool m) +{ + tree ret = build_pointer_type_for_mode (type, mode, m); + return c_set_type_bits (ret, type); +} + +/* Build a function type. */ + +tree +c_build_function_type (tree type, tree args, bool no) +{ + tree ret = build_function_type (type, args, no); + return c_set_type_bits (ret, type); +} + +/* Build an array type. This sets typeless storage as required + by C2Y and C_TYPE_VARIABLY_MODIFIED and C_TYPE_VARIABLE_SIZE + based on the element type and domain. */ + +tree +c_build_array_type (tree type, tree domain) +{ + int type_quals = TYPE_QUALS (type); + + /* Identify typeless storage as introduced in C2Y + and supported also in earlier language modes. */ + bool typeless = (char_type_p (type) && !(type_quals & TYPE_QUAL_ATOMIC)) + || (AGGREGATE_TYPE_P (type) && TYPE_TYPELESS_STORAGE (type)); + + tree ret = build_array_type (type, domain, typeless); + + if (domain && TYPE_MAX_VALUE (domain) + && TREE_CODE (TYPE_MAX_VALUE (domain)) != INTEGER_CST) + { + C_TYPE_VARIABLE_SIZE (ret) = 1; + C_TYPE_VARIABLY_MODIFIED (ret) = 1; + } + + return c_set_type_bits (ret, type); +} + +tree +c_build_type_attribute_qual_variant (tree type, tree attrs, int quals) +{ + tree ret = build_type_attribute_qual_variant (type, attrs, quals); + return c_set_type_bits (ret, type); +} + +tree +c_build_type_attribute_variant (tree type, tree attrs) +{ + return c_build_type_attribute_qual_variant (type, attrs, TYPE_QUALS (type)); +} + +/* Reconstruct a complex derived type. This is used to re-construct types + with the vector attribute. It is called via a langhook. */ + +tree +c_reconstruct_complex_type (tree type, tree bottom) +{ + tree inner, outer; + + if (TREE_CODE (type) == POINTER_TYPE) + { + inner = c_reconstruct_complex_type (TREE_TYPE (type), bottom); + outer = c_build_pointer_type_for_mode (inner, TYPE_MODE (type), + TYPE_REF_CAN_ALIAS_ALL (type)); + } + else if (TREE_CODE (type) == ARRAY_TYPE) + { + inner = c_reconstruct_complex_type (TREE_TYPE (type), bottom); + outer = c_build_array_type (inner, TYPE_DOMAIN (type)); + + gcc_checking_assert (C_TYPE_VARIABLE_SIZE (type) + == C_TYPE_VARIABLE_SIZE (outer)); + gcc_checking_assert (C_TYPE_VARIABLY_MODIFIED (outer) + == C_TYPE_VARIABLY_MODIFIED (type)); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + inner = c_reconstruct_complex_type (TREE_TYPE (type), bottom); + outer = c_build_function_type (inner, TYPE_ARG_TYPES (type), + TYPE_NO_NAMED_ARGS_STDARG_P (type)); + } + else if (TREE_CODE (type) == REFERENCE_TYPE + || TREE_CODE (type) == OFFSET_TYPE) + gcc_unreachable (); + else + return bottom; + + return c_build_type_attribute_qual_variant (outer, TYPE_ATTRIBUTES (type), + TYPE_QUALS (type)); +} /* If NTYPE is a type of a non-variadic function with a prototype and OTYPE is a type of a function without a prototype and ATTRS @@ -365,7 +550,7 @@ qualify_type (tree type, tree like) the (possibly) modified ATTRS. */ static tree -build_functype_attribute_variant (tree ntype, tree otype, tree attrs) +c_build_functype_attribute_variant (tree ntype, tree otype, tree attrs) { if (!prototype_p (otype) && prototype_p (ntype) @@ -376,9 +561,11 @@ build_functype_attribute_variant (tree ntype, tree otype, tree attrs) "does not take variable arguments", "format"); attrs = remove_attribute ("format", attrs); } - return build_type_attribute_variant (ntype, attrs); + return c_build_type_attribute_variant (ntype, attrs); } + + /* Return the composite type of two compatible types. We assume that comptypes has already been done and returned @@ -440,8 +627,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) tree pointed_to_2 = TREE_TYPE (t2); tree target = composite_type_internal (pointed_to_1, pointed_to_2, cache); - t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false); - t1 = build_type_attribute_variant (t1, attributes); + t1 = c_build_pointer_type_for_mode (target, TYPE_MODE (t1), false); + t1 = c_build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); } @@ -479,15 +666,15 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) /* Save space: see if the result is identical to one of the args. */ if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1) && (d2_variable || d2_zero || !d1_variable)) - return build_type_attribute_variant (t1, attributes); + return c_build_type_attribute_variant (t1, attributes); if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2) && (d1_variable || d1_zero || !d2_variable)) - return build_type_attribute_variant (t2, attributes); + return c_build_type_attribute_variant (t2, attributes); if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return build_type_attribute_variant (t1, attributes); + return c_build_type_attribute_variant (t1, attributes); if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return build_type_attribute_variant (t2, attributes); + return c_build_type_attribute_variant (t2, attributes); /* Merge the element types, and have a size if either arg has one. We may have qualifiers on the element types. To set @@ -496,13 +683,21 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) back at the end. */ quals = TYPE_QUALS (strip_array_types (elt)); unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); - t1 = build_array_type (unqual_elt, - TYPE_DOMAIN ((TYPE_DOMAIN (t1) - && (d2_variable - || d2_zero - || !d1_variable)) - ? t1 - : t2)); + t1 = c_build_array_type (unqual_elt, + TYPE_DOMAIN ((TYPE_DOMAIN (t1) + && (d2_variable + || d2_zero + || !d1_variable)) + ? t1 + : t2)); + + /* Check that a type which has a varying outermost dimension + got marked has having a variable size. */ + bool varsize = (d1_variable && d2_variable) + || (d1_variable && !t2_complete) + || (d2_variable && !t1_complete); + gcc_checking_assert (!varsize || C_TYPE_VARIABLE_SIZE (t1)); + /* Ensure a composite type involving a zero-length array type is a zero-length type not an incomplete type. */ if (d1_zero && d2_zero @@ -513,7 +708,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) TYPE_SIZE_UNIT (t1) = size_zero_node; } t1 = c_build_qualified_type (t1, quals); - return build_type_attribute_variant (t1, attributes); + return c_build_type_attribute_variant (t1, attributes); } case RECORD_TYPE: @@ -612,7 +807,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes)) return t2; } - return build_type_attribute_variant (t1, attributes); + return c_build_type_attribute_variant (t1, attributes); case FUNCTION_TYPE: /* Function types: prefer the one that specified arg types. @@ -628,23 +823,23 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) /* Save space: see if the result is identical to one of the args. */ if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2)) - return build_functype_attribute_variant (t1, t2, attributes); + return c_build_functype_attribute_variant (t1, t2, attributes); if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1)) - return build_functype_attribute_variant (t2, t1, attributes); + return c_build_functype_attribute_variant (t2, t1, attributes); /* Simple way if one arg fails to specify argument types. */ if (TYPE_ARG_TYPES (t1) == NULL_TREE) { - t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2), - TYPE_NO_NAMED_ARGS_STDARG_P (t2)); - t1 = build_type_attribute_variant (t1, attributes); + t1 = c_build_function_type (valtype, TYPE_ARG_TYPES (t2), + TYPE_NO_NAMED_ARGS_STDARG_P (t2)); + t1 = c_build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); } if (TYPE_ARG_TYPES (t2) == NULL_TREE) { - t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1), - TYPE_NO_NAMED_ARGS_STDARG_P (t1)); - t1 = build_type_attribute_variant (t1, attributes); + t1 = c_build_function_type (valtype, TYPE_ARG_TYPES (t1), + TYPE_NO_NAMED_ARGS_STDARG_P (t1)); + t1 = c_build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); } @@ -739,13 +934,13 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) parm_done: ; } - t1 = build_function_type (valtype, newargs); + t1 = c_build_function_type (valtype, newargs); t1 = qualify_type (t1, t2); } /* FALLTHRU */ default: - return build_type_attribute_variant (t1, attributes); + return c_build_type_attribute_variant (t1, attributes); } } @@ -822,8 +1017,8 @@ common_pointer_type (tree t1, tree t2) target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); - t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); - return build_type_attribute_variant (t1, attributes); + t1 = c_build_pointer_type (c_build_qualified_type (target, target_quals)); + return c_build_type_attribute_variant (t1, attributes); } /* Return the common type for two arithmetic types under the usual @@ -855,13 +1050,13 @@ c_common_type (tree t1, tree t2) if (TYPE_ATTRIBUTES (t1) != NULL_TREE) { tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t1)); - t1 = build_type_attribute_variant (t1, attrs); + t1 = c_build_type_attribute_variant (t1, attrs); } if (TYPE_ATTRIBUTES (t2) != NULL_TREE) { tree attrs = affects_type_identity_attributes (TYPE_ATTRIBUTES (t2)); - t2 = build_type_attribute_variant (t2, attrs); + t2 = c_build_type_attribute_variant (t2, attrs); } /* Save time if the two types are the same. */ @@ -1181,6 +1376,9 @@ comptypes_verify (tree type1, tree type2) || TREE_CODE (type1) == ERROR_MARK || TREE_CODE (type2) == ERROR_MARK) return true; + gcc_checking_assert (c_verify_type (type1)); + gcc_checking_assert (c_verify_type (type2)); + if (TYPE_CANONICAL (type1) != TYPE_CANONICAL (type2) && !TYPE_STRUCTURAL_EQUALITY_P (type1) && !TYPE_STRUCTURAL_EQUALITY_P (type2)) @@ -2002,11 +2200,7 @@ array_to_pointer_conversion (location_t loc, tree exp) copy_warning (exp, orig_exp); - bool varmod = C_TYPE_VARIABLY_MODIFIED (restype); - - ptrtype = build_pointer_type (restype); - - C_TYPE_VARIABLY_MODIFIED (ptrtype) = varmod; + ptrtype = c_build_pointer_type (restype); if (INDIRECT_REF_P (exp)) return convert (ptrtype, TREE_OPERAND (exp, 0)); @@ -2750,7 +2944,7 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, { gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))); /* The result type of the call is a pointer to the flexible array type. */ - tree result_type = build_pointer_type (TREE_TYPE (ref)); + tree result_type = c_build_pointer_type (TREE_TYPE (ref)); tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, @@ -3209,7 +3403,7 @@ build_omp_array_section (location_t loc, tree array, tree index, tree length) gcc_assert (!error_operand_p (idxtype)); - sectype = build_array_type (eltype, idxtype); + sectype = c_build_array_type (eltype, idxtype); } return build3_loc (loc, OMP_ARRAY_SECTION, sectype, array, index, length); @@ -4887,7 +5081,6 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, tree eptype = NULL_TREE; const char *invalid_op_diag; bool int_operands; - bool varmod; int_operands = EXPR_INT_CONST_OPERANDS (xarg); if (int_operands) @@ -5376,11 +5569,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, gcc_assert (TREE_CODE (arg) != COMPONENT_REF || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))); - varmod = C_TYPE_VARIABLY_MODIFIED (argtype); - - argtype = build_pointer_type (argtype); - - C_TYPE_VARIABLY_MODIFIED (argtype) = varmod; + argtype = c_build_pointer_type (argtype); /* ??? Cope with user tricks that amount to offsetof. Delete this when we have proper support for integer constant expressions. */ @@ -5659,7 +5848,7 @@ type_or_builtin_type (tree expr, tree *bltin = NULL) return type; if ((*bltin = builtin_decl_implicit (code))) - type = build_pointer_type (TREE_TYPE (*bltin)); + type = c_build_pointer_type (TREE_TYPE (*bltin)); return type; } @@ -5944,7 +6133,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, /* for array, use qualifiers of element type */ if (flag_isoc23) t2 = t2_stripped; - result_type = build_pointer_type (qualify_type (t1, t2)); + result_type = c_build_pointer_type (qualify_type (t1, t2)); } /* Objective-C pointer comparisons are a bit more lenient. */ else if (objc_have_common_type (type1, type2, -3, NULL_TREE)) @@ -5967,8 +6156,8 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, inform (op1_loc, "first expression has type %qT", type1); inform (op2_loc, "second expression has type %qT", type2); } - result_type = build_pointer_type - (build_qualified_type (void_type_node, qual)); + result_type = c_build_pointer_type + (c_build_qualified_type (void_type_node, qual)); } } else if (code1 == POINTER_TYPE @@ -6922,8 +7111,8 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, } /* Remove qualifiers. */ - lhstype = build_qualified_type (lhstype, TYPE_UNQUALIFIED); - olhstype = build_qualified_type (olhstype, TYPE_UNQUALIFIED); + lhstype = c_build_qualified_type (lhstype, TYPE_UNQUALIFIED); + olhstype = c_build_qualified_type (olhstype, TYPE_UNQUALIFIED); /* Convert new value to destination type. Fold it first, then restore any excess precision information, for the sake of @@ -7573,11 +7762,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, } if (!c_mark_addressable (rhs)) return error_mark_node; - rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); + rhs = build1 (ADDR_EXPR, c_build_pointer_type (TREE_TYPE (rhs)), rhs); SET_EXPR_LOCATION (rhs, location); rhs = convert_for_assignment (location, expr_loc, - build_pointer_type (TREE_TYPE (type)), + c_build_pointer_type (TREE_TYPE (type)), rhs, origtype, errtype, null_pointer_constant, fundecl, function, parmnum, warnopt); @@ -13647,8 +13836,8 @@ build_binary_op (location_t location, enum tree_code code, if (result_type == NULL_TREE) { int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - result_type = build_pointer_type - (build_qualified_type (void_type_node, qual)); + result_type = c_build_pointer_type + (c_build_qualified_type (void_type_node, qual)); } } else if (code0 == POINTER_TYPE @@ -13680,10 +13869,10 @@ build_binary_op (location_t location, enum tree_code code, create a pointer type from its type. */ else if (code0 == NULLPTR_TYPE && null_pointer_constant_p (orig_op1)) result_type = (INTEGRAL_TYPE_P (type1) - ? build_pointer_type (type1) : type1); + ? c_build_pointer_type (type1) : type1); else if (code1 == NULLPTR_TYPE && null_pointer_constant_p (orig_op0)) result_type = (INTEGRAL_TYPE_P (type0) - ? build_pointer_type (type0) : type0); + ? c_build_pointer_type (type0) : type0); if ((C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op0)) || truth_value_p (TREE_CODE (orig_op0))) ^ (C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op1)) @@ -13781,8 +13970,8 @@ build_binary_op (location_t location, enum tree_code code, else { int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - result_type = build_pointer_type - (build_qualified_type (void_type_node, qual)); + result_type = c_build_pointer_type + (c_build_qualified_type (void_type_node, qual)); pedwarn (location, OPT_Wcompare_distinct_pointer_types, "comparison of distinct pointer types lacks a cast"); } @@ -15047,8 +15236,8 @@ handle_omp_array_sections (tree &c, enum c_omp_region_type ort) tree eltype = TREE_TYPE (first); while (TREE_CODE (eltype) == ARRAY_TYPE) eltype = TREE_TYPE (eltype); - tree type = build_array_type (eltype, index_type); - tree ptype = build_pointer_type (eltype); + tree type = c_build_array_type (eltype, index_type); + tree ptype = c_build_pointer_type (eltype); if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) t = build_fold_addr_expr (t); tree t2 = build_fold_addr_expr (first); @@ -15518,10 +15707,10 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) size = size_binop (MINUS_EXPR, size, size_one_node); size = save_expr (size); tree index_type = build_index_type (size); - tree atype = build_array_type (TYPE_MAIN_VARIANT (type), - index_type); + tree atype = c_build_array_type (TYPE_MAIN_VARIANT (type), + index_type); atype = c_build_qualified_type (atype, TYPE_QUALS (type)); - tree ptype = build_pointer_type (type); + tree ptype = c_build_pointer_type (type); if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) t = build_fold_addr_expr (t); t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); @@ -17177,17 +17366,17 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type, || (domain && TYPE_CANONICAL (domain) != domain)) { tree unqualified_canon - = build_array_type (TYPE_CANONICAL (element_type), - domain? TYPE_CANONICAL (domain) - : NULL_TREE); + = c_build_array_type (TYPE_CANONICAL (element_type), + domain ? TYPE_CANONICAL (domain) + : NULL_TREE); if (TYPE_REVERSE_STORAGE_ORDER (type)) { unqualified_canon - = build_distinct_type_copy (unqualified_canon); + = build_distinct_type_copy (unqualified_canon); TYPE_REVERSE_STORAGE_ORDER (unqualified_canon) = 1; } TYPE_CANONICAL (t) - = c_build_qualified_type (unqualified_canon, type_quals); + = c_build_qualified_type (unqualified_canon, type_quals); } else TYPE_CANONICAL (t) = t; @@ -17209,6 +17398,12 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type, tree var_type = (orig_qual_type && orig_qual_indirect == 0 ? orig_qual_type : build_qualified_type (type, type_quals)); + + gcc_checking_assert (C_TYPE_VARIABLE_SIZE (var_type) + == C_TYPE_VARIABLE_SIZE (type)); + gcc_checking_assert (C_TYPE_VARIABLY_MODIFIED (var_type) + == C_TYPE_VARIABLY_MODIFIED (type)); + /* A variant type does not inherit the list of incomplete vars from the type main variant. */ if ((RECORD_OR_UNION_TYPE_P (var_type) diff --git a/gcc/testsuite/gcc.dg/Warray-parameter-4.c b/gcc/testsuite/gcc.dg/Warray-parameter-4.c index b702d730a13e..2c91ccdec06c 100644 --- a/gcc/testsuite/gcc.dg/Warray-parameter-4.c +++ b/gcc/testsuite/gcc.dg/Warray-parameter-4.c @@ -104,11 +104,9 @@ void ffpa7_n1 (void (* (* (* [8])[n1])(void))(void)); // { dg-warning "argument 1 of type 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[8]\\\)\\\[n1]\\\)\\\(void\\\)\\\)\\\(void\\\)' with mismatched bound" "" { target *-*-* } .-1 } void ffpa9_x (void (* (* (* [9])[*])(void))(void)); -// { dg-message "previously declared as 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[9]\\\)\\\[\\\*]\\\)\\\(void\\\)\\\)\\\(void\\\)'" "pr?????" { xfail *-*-* } .-1 } -// { dg-message "previously declared as 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[9]\\\)\\\[0]\\\)\\\(void\\\)\\\)\\\(void\\\)'" "" { target *-*-* } .-2 } +// { dg-message "previously declared as 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[9]\\\)\\\[\\\*]\\\)\\\(void\\\)\\\)\\\(void\\\)'" "pr?????" { target *-*-* } .-1 } void ffpa9_x (void (* (* (* [8])[*])(void))(void)); -// { dg-warning "argument 1 of type 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[8]\\\)\\\[\\\*]\\\)\\\(void\\\)\\\)\\\(void\\\)' with mismatched bound" "pr?????" { xfail *-*-* } .-1 } -// { dg-warning "argument 1 of type 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[8]\\\)\\\[0]\\\)\\\(void\\\)\\\)\\\(void\\\)' with mismatched bound" "" { target *-*-* } .-2 } +// { dg-warning "argument 1 of type 'void \\\(\\\* ?\\\(\\\* ?\\\(\\\*\\\[8]\\\)\\\[\\\*]\\\)\\\(void\\\)\\\)\\\(void\\\)' with mismatched bound" "pr?????" { target *-*-* } .-1 } /* Verify a three-dimensional array of pointers to two-dimensional arrays of pointers to function pointers. */ diff --git a/gcc/testsuite/gcc.dg/Wvla-parameter-2.c b/gcc/testsuite/gcc.dg/Wvla-parameter-2.c index daa71d897c97..08d4a1069b68 100644 --- a/gcc/testsuite/gcc.dg/Wvla-parameter-2.c +++ b/gcc/testsuite/gcc.dg/Wvla-parameter-2.c @@ -34,17 +34,10 @@ void f (int[n1][2][n3][4][n5][6][n7][8][n9]); // { dg-message "previously decl // { dg-message "with 5 variable bounds" "note" { target *-*-* } .-1 } void f (int[n1][2][n3][4][n5][6][n7][8][n9]); -/* Due to a limitation and because [*] is represented the same as [0] - only the most significant array bound is rendered as [*]; the others - are rendered as [0]. */ -void f (int[n1][2][n3][4][n5][6][n7][8][*]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[\\\*]' declared with 1 unspecified variable bound" "pr100420 (expected)" { xfail *-*-* } } -// { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[0]' declared with 1 unspecified variable bound" "pr100420" { target *-*-* } .-1 } -void f (int[n1][2][n3][4][n5][6][*][8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[\\\*]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420 (expected)" { xfail *-*-* } } -// { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[0]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420" { target *-*-* } .-1 } -void f (int[n1][2][n3][4][*][6][n7][8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[\\\*]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420 (expected)" { xfail *-*-*} } -// { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[0]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420" { target *-*-* } .-1 } -void f (int[n1][2][*][4][n5][6][n7][8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[\\\*]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420 (expected)" { xfail *-*-* } } -// { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[0]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420" { target *-*-* } .-1 } +void f (int[n1][2][n3][4][n5][6][n7][8][*]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[\\\*]' declared with 1 unspecified variable bound" "pr100420 (expected)" { target *-*-* } } +void f (int[n1][2][n3][4][n5][6][*][8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[\\\*]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420 (expected)" { target *-*-* } } +void f (int[n1][2][n3][4][*][6][n7][8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[n3]\\\[4]\\\[\\\*]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420 (expected)" { target *-*-*} } +void f (int[n1][2][*][4][n5][6][n7][8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[2]\\\[\\\*]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" "pr100420 (expected)" { target *-*-* } } void f (int[*][2][n3][4][n5][6][n7][8][n9]); // { dg-warning "argument 1 of type 'int\\\[\\\*]\\\[2]\\\[n3]\\\[4]\\\[n5]\\\[6]\\\[n7]\\\[8]\\\[n9]' declared with 1 unspecified variable bound" } void f (int[n1][n2][n3][n4][n5][n6][n7][n8][n9]); // { dg-warning "argument 1 of type 'int\\\[n1]\\\[n2]\\\[n3]\\\[n4]\\\[n5]\\\[n6]\\\[n7]\\\[n8]\\\[n9]' declared with 9 variable bounds" } diff --git a/gcc/testsuite/gcc.dg/Wvla-parameter-3.c b/gcc/testsuite/gcc.dg/Wvla-parameter-3.c index f1cf139192d3..33abe3e3aebc 100644 --- a/gcc/testsuite/gcc.dg/Wvla-parameter-3.c +++ b/gcc/testsuite/gcc.dg/Wvla-parameter-3.c @@ -23,21 +23,16 @@ void pa1 (int (*)[n + 1]); // { dg-warning "mismatch in bound 1 of void ppax (int (**)[*]); // { dg-message "previously declared as 'int \\\(\\\*\\\*\\\)\\\[.]'" "note" } void ppax (int (**)[n]); // { dg-warning "\\\[-Wvla-parameter" } -/* A VLA with an unspecified bound is represented the same as [0] so - so the pretty printer can't differentiate between the two forms. */ -void ppax (int (**)[1]); // { dg-bogus "\\\[-Warray-parameter" "pr100420 (expected)" { xfail *-*-* } } - // { dg-warning "\\\[-Wvla-parameter" "pr100420 (expected)" { xfail *-*-* } .-1 } +void ppax (int (**)[1]); // { dg-warning "\\\[-Wvla-parameter" "pr100420 (expected)" } void ppax (int (**)[n + 1]); // { dg-warning "mismatch in bound 1 of argument 1 declared as 'int *\\\(\\\*\\\*\\\)\\\[n \\\+ 1\\\]'" } void pa1_n (int (*)[1][n]); void pa1_n (int (*)[1][n]); -void pa1_n (int (*)[*][n]); // { dg-warning "mismatch in bound 1 of argument 1 declared as 'int \\\(\\\*\\\)\\\[\\\*]\\\[n]'" "pr100420 (expected)" { xfail *-*-*} } - // { dg-warning "mismatch in bound 1 of argument 1 declared as 'int \\\(\\\*\\\)\\\[0]\\\[n]'" "pr100420" { target *-*-* } .-1 } +void pa1_n (int (*)[*][n]); // { dg-warning "mismatch in bound 1 of argument 1 declared as 'int \\\(\\\*\\\)\\\[\\\*]\\\[n]'" "pr100420 (expected)" { target *-*-*} } void pa1_n_2 (int (*)[1][n][2]); -void pa1_n_2 (int (*)[1][n][*]); // { dg-warning "mismatch in bound 3 of argument 1 declared as 'int \\\(\\\*\\\)\\\[1]\\\[n]\\\[\\\*]'" "pr100420 (expected)" { xfail *-*-* } } - // { dg-warning "mismatch in bound 3 of argument 1 declared as 'int \\\(\\\*\\\)\\\[1]\\\[n]\\\[0]'" "pr100420" { target *-*-* } .-1 } +void pa1_n_2 (int (*)[1][n][*]); // { dg-warning "mismatch in bound 3 of argument 1 declared as 'int \\\(\\\*\\\)\\\[1]\\\[n]\\\[\\\*]'" "pr100420 (expected)" { target *-*-* } } void pa1_n_2_a1_n_2 (int (*)[1][n][2], int (*)[1][n][2]); diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-11.c b/gcc/testsuite/gcc.dg/c23-tag-composite-11.c new file mode 100644 index 000000000000..960c7a0ba81d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-11.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +void f(int n, int m) +{ + typedef struct fo { int a; } aaa[n]; + { + typedef struct fo { int a; } bbb[m]; + + goto foo; /* { dg-error "jump" } */ + typeof((1 ? (aaa*)0 : (bbb*)0)) x; + foo: + } +} + +void g(int n, int m) +{ + typedef struct fo { int a; } aaa[n]; + { + typedef struct fo { int a; } bbb[]; + + goto foo; /* { dg-error "jump" } */ + typeof((1 ? (aaa*)0 : (bbb*)0)) x; + foo: + } +} + diff --git a/gcc/testsuite/gcc.dg/pr117145-1.c b/gcc/testsuite/gcc.dg/pr117145-1.c new file mode 100644 index 000000000000..20482d3b3b79 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr117145-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +void b(); +int e(int c, struct d { [[gnu::vector_size(4)]] char an[c]; } *) +{ + (void)sizeof(struct d); + return 0; +} +void f() { + if (e(0, 0)) + b(); +} + diff --git a/gcc/testsuite/gcc.dg/pr117145-2.c b/gcc/testsuite/gcc.dg/pr117145-2.c new file mode 100644 index 000000000000..088a0cf571d0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr117145-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void e(int c) +{ + goto foo; /* { dg-error "jump into scope" } */ + [[maybe_unused]] struct d { [[gnu::vector_size(4)]] char an[c]; } q; +foo: +} + diff --git a/gcc/testsuite/gcc.dg/pr117245.c b/gcc/testsuite/gcc.dg/pr117245.c new file mode 100644 index 000000000000..ebcc60b898fc --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr117245.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void a() { + int b; + struct { + char c[b]; + } bar() { + } + struct bar { + __attribute__((vector_size(4))) char c[b]; + } (*d)(); + struct bar e() { struct bar f; } + d = e; + sizeof(d()); +} +