[gcc r15-2026] c, objc: Add -Wunterminated-string-initialization
https://gcc.gnu.org/g:44c9403ed1833ae71a59e84f9e37af3182be0df5 commit r15-2026-g44c9403ed1833ae71a59e84f9e37af3182be0df5 Author: Alejandro Colomar Date: Sat Jun 29 15:10:43 2024 +0200 c, objc: Add -Wunterminated-string-initialization Warn about the following: char s[3] = "foo"; Initializing a char array with a string literal of the same length as the size of the array is usually a mistake. Rarely is the case where one wants to create a non-terminated character sequence from a string literal. In some cases, for writing faster code, one may want to use arrays instead of pointers, since that removes the need for storing an array of pointers apart from the strings themselves. char *log_levels[] = { "info", "warning", "err" }; vs. char log_levels[][7] = { "info", "warning", "err" }; This forces the programmer to specify a size, which might change if a new entry is later added. Having no way to enforce null termination is very dangerous, however, so it is useful to have a warning for this, so that the compiler can make sure that the programmer didn't make any mistakes. This warning catches the bug above, so that the programmer will be able to fix it and write: char log_levels[][8] = { "info", "warning", "err" }; This warning already existed as part of -Wc++-compat, but this patch allows enabling it separately. It is also included in -Wextra, since it may not always be desired (when unterminated character sequences are wanted), but it's likely to be desired in most cases. Since Wc++-compat now includes this warning, the test has to be modified to expect the text of the new warning too, in . Link: https://lists.gnu.org/archive/html/groff/2022-11/msg00059.html Link: https://lists.gnu.org/archive/html/groff/2022-11/msg00063.html Link: https://inbox.sourceware.org/gcc/36da94eb-1cac-5ae8-7fea-ec66160cf...@gmail.com/T/ PR c/115185 gcc/c-family/ChangeLog: * c.opt: Add -Wunterminated-string-initialization. gcc/c/ChangeLog: * c-typeck.cc (digest_init): Separate warnings about character arrays being initialized as unterminated character sequences with string literals, from -Wc++-compat, into a new warning, -Wunterminated-string-initialization. gcc/ChangeLog: * doc/invoke.texi: Document the new -Wunterminated-string-initialization. gcc/testsuite/ChangeLog: * gcc.dg/Wcxx-compat-14.c: Adapt the test to match the new text of the warning, which doesn't say anything about C++ anymore. * gcc.dg/Wunterminated-string-initialization.c: New test. Acked-by: Doug McIlroy Acked-by: Mike Stump Reviewed-by: Sandra Loosemore Reviewed-by: Martin Uecker Signed-off-by: Alejandro Colomar Reviewed-by: Marek Polacek Diff: --- gcc/c-family/c.opt | 4 gcc/c/c-typeck.cc| 6 +++--- gcc/doc/invoke.texi | 20 +++- gcc/testsuite/gcc.dg/Wcxx-compat-14.c| 2 +- .../gcc.dg/Wunterminated-string-initialization.c | 6 ++ 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 5c1006ff321f..a52682d835ce 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1464,6 +1464,10 @@ Wunsuffixed-float-constants C ObjC Var(warn_unsuffixed_float_constants) Warning Warn about unsuffixed float constants. +Wunterminated-string-initialization +C ObjC Var(warn_unterminated_string_initialization) Warning LangEnabledBy(C ObjC,Wextra || Wc++-compat) +Warn about character arrays initialized as unterminated character sequences with a string literal. + Wunused C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wall) ; documented in common.opt diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 574114d541fd..7e0f01ed22b9 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -8878,11 +8878,11 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, pedwarn_init (init_loc, 0, ("initializer-string for array of %qT " "is too long"), typ1); - else if (warn_cxx_compat + else if (warn_unterminated_string_initialization && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0) - warning_at (init_loc, OPT_Wc___compat, + warning_at (init_loc, OPT_Wunterminated_string_initialization, ("initializer-string for array of %qT " -"is too long for C++"), typ1); +"is too long"), typ1); if
[gcc r15-1930] Fix test errors after r15-1394 for sizeof(int)==sizeof(long) [PR115545]
https://gcc.gnu.org/g:5b46f196cdb62af0e611315ea411938d756a0ad1 commit r15-1930-g5b46f196cdb62af0e611315ea411938d756a0ad1 Author: Martin Uecker Date: Sun Jun 23 09:10:20 2024 +0200 Fix test errors after r15-1394 for sizeof(int)==sizeof(long) [PR115545] Some tests added to test the type of redeclarations of enumerators in r15-1394 fail on architectures where sizeof(long) == sizeof(int). Adapt tests to use long long and/or accept that long long is selected as type for the enumerator. PR testsuite/115545 gcc/testsuite/ * gcc.dg/pr115109.c: Adapt test. * gcc.dg/c23-tag-enum-6.c: Adapt test. * gcc.dg/c23-tag-enum-7.c: Adapt test. Diff: --- gcc/testsuite/gcc.dg/c23-tag-enum-6.c | 4 ++-- gcc/testsuite/gcc.dg/c23-tag-enum-7.c | 12 ++-- gcc/testsuite/gcc.dg/pr115109.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c index 29aef7ee3fdf..d8d304d9b3df 100644 --- a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c @@ -7,10 +7,10 @@ enum E : int { a = 1, b = 2 }; enum E : int { b = _Generic(a, enum E: 2), a = 1 }; enum H { x = 1 }; -enum H { x = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */ +enum H { x = 2ULL + UINT_MAX };/* { dg-error "outside the range" } */ enum K : int { z = 1 }; -enum K : int { z = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */ +enum K : int { z = 2ULL + UINT_MAX }; /* { dg-error "outside the range" } */ enum F { A = 0, B = UINT_MAX }; enum F { B = UINT_MAX, A };/* { dg-error "outside the range" } */ diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c index d4c787c8f716..974735bf2ef4 100644 --- a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c @@ -4,23 +4,23 @@ #include // enumerators are all representable in int -enum E { a = 1UL, b = _Generic(a, int: 2) }; +enum E { a = 1ULL, b = _Generic(a, int: 2) }; static_assert(_Generic(a, int: 1)); static_assert(_Generic(b, int: 1)); -enum E { a = 1UL, b = _Generic(a, int: 2) }; +enum E { a = 1ULL, b = _Generic(a, int: 2) }; static_assert(_Generic(a, int: 1)); static_assert(_Generic(b, int: 1)); // enumerators are not representable in int -enum H { c = 1UL << (UINT_WIDTH + 1), d = 2 }; +enum H { c = 1ULL << (UINT_WIDTH + 1), d = 2 }; static_assert(_Generic(c, enum H: 1)); static_assert(_Generic(d, enum H: 1)); -enum H { c = 1UL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) }; +enum H { c = 1ULL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) }; static_assert(_Generic(c, enum H: 1)); static_assert(_Generic(d, enum H: 1)); // there is an overflow in the first declaration -enum K { e = UINT_MAX, f, g = _Generic(e, unsigned int: 0) + _Generic(f, unsigned long: 1) }; +enum K { e = UINT_MAX, f, g = _Generic(e, unsigned int: 0) + _Generic(f, unsigned long: 1, unsigned long long: 1) }; static_assert(_Generic(e, enum K: 1)); static_assert(_Generic(f, enum K: 1)); static_assert(_Generic(g, enum K: 1)); @@ -30,7 +30,7 @@ static_assert(_Generic(f, enum K: 1)); static_assert(_Generic(g, enum K: 1)); // there is an overflow in the first declaration -enum U { k = INT_MAX, l, m = _Generic(k, int: 0) + _Generic(l, long: 1) }; +enum U { k = INT_MAX, l, m = _Generic(k, int: 0) + _Generic(l, long: 1, long long: 1) }; static_assert(_Generic(k, enum U: 1)); static_assert(_Generic(l, enum U: 1)); static_assert(_Generic(m, enum U: 1)); diff --git a/gcc/testsuite/gcc.dg/pr115109.c b/gcc/testsuite/gcc.dg/pr115109.c index 4baee0f34453..8245ff7fadb7 100644 --- a/gcc/testsuite/gcc.dg/pr115109.c +++ b/gcc/testsuite/gcc.dg/pr115109.c @@ -3,6 +3,6 @@ #include -enum E { a = 1UL << (ULONG_WIDTH - 5), b = 2 }; -enum E { a = 1ULL << (ULONG_WIDTH - 5), b = _Generic(a, enum E: 2) }; +enum E { a = 1ULL << (ULLONG_WIDTH - 5), b = 2 }; +enum E { a = 1ULL << (ULLONG_WIDTH - 5), b = _Generic(a, enum E: 2) };
[gcc r15-1929] c: Fix ICE for redeclaration of structs with different alignment [PR114727]
https://gcc.gnu.org/g:7825c07bbaf503c47ecedd87e3d64be003b24f2c commit r15-1929-g7825c07bbaf503c47ecedd87e3d64be003b24f2c Author: Martin Uecker Date: Sat Jun 29 15:53:43 2024 +0200 c: Fix ICE for redeclaration of structs with different alignment [PR114727] For redeclarations of struct in C23, if one has an alignment attribute that makes the alignment different, we later get an ICE in verify_types. This patches disallows such redeclarations by declaring such types to be different. PR c/114727 gcc/c/ * c-typeck.cc (tagged_types_tu_compatible): Add test. gcc/testsuite/ * gcc.dg/pr114727.c: New test. Diff: --- gcc/c/c-typeck.cc | 3 +++ gcc/testsuite/gcc.dg/pr114727.c | 6 ++ 2 files changed, 9 insertions(+) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index e486ac04f9cf..455dc374b481 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1603,6 +1603,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, != TYPE_REVERSE_STORAGE_ORDER (t2))) return false; + if (TYPE_USER_ALIGN (t1) != TYPE_USER_ALIGN (t2)) +data->different_types_p = true; + /* For types already being looked at in some active invocation of this function, assume compatibility. The cache is built as a linked list on the stack diff --git a/gcc/testsuite/gcc.dg/pr114727.c b/gcc/testsuite/gcc.dg/pr114727.c new file mode 100644 index ..12949590ce09 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114727.c @@ -0,0 +1,6 @@ +/* { dg-do compile } + * { dg-options "-std=c23 -g" } */ + +#define Y [[gnu::aligned(128)]] +extern struct Y foo { int x; } x; +struct foo { int x; }; /* { dg-error "redefinition" } */
[gcc r15-1928] c: Fix ICE for incorrect code in comptypes_verify [PR115696]
https://gcc.gnu.org/g:592a746533a278a5fd3e7b5dff004e1846ef26a4 commit r15-1928-g592a746533a278a5fd3e7b5dff004e1846ef26a4 Author: Martin Uecker Date: Sat Jun 29 15:36:18 2024 +0200 c: Fix ICE for incorrect code in comptypes_verify [PR115696] The new verification code produces an ICE for incorrect code. Add the same logic as already used in comptypes to to bail out under certain conditions. PR c/115696 gcc/c/ * c-typeck.cc (comptypes_verify): Bail out for identical, empty, and erroneous input types. gcc/testsuite/ * gcc.dg/pr115696.c: New test. Diff: --- gcc/c/c-typeck.cc | 4 gcc/testsuite/gcc.dg/pr115696.c | 7 +++ 2 files changed, 11 insertions(+) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ffcab7df4d3b..e486ac04f9cf 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1175,6 +1175,10 @@ common_type (tree t1, tree t2) static bool comptypes_verify (tree type1, tree type2) { + if (type1 == type2 || !type1 || !type2 + || TREE_CODE (type1) == ERROR_MARK || TREE_CODE (type2) == ERROR_MARK) +return true; + if (TYPE_CANONICAL (type1) != TYPE_CANONICAL (type2) && !TYPE_STRUCTURAL_EQUALITY_P (type1) && !TYPE_STRUCTURAL_EQUALITY_P (type2)) diff --git a/gcc/testsuite/gcc.dg/pr115696.c b/gcc/testsuite/gcc.dg/pr115696.c new file mode 100644 index ..50b8ebc24f08 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr115696.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-implicit-int" } */ + +a(); /* { dg-warning "no type or storage" } */ +a; /* { dg-error "redeclared" } */ + /* { dg-warning "no type or storage" "" { target *-*-* } .-1 } */ +a(); /* { dg-warning "no type or storage" } */
[gcc r15-1698] c: Error message for incorrect use of static in array declarations.
https://gcc.gnu.org/g:da7976a015a4388b8ed843412c3c1c840451cf0f commit r15-1698-gda7976a015a4388b8ed843412c3c1c840451cf0f Author: Martin Uecker Date: Thu Jun 27 21:47:56 2024 +0200 c: Error message for incorrect use of static in array declarations. Add an explicit error messages when c99's static is used without a size expression in an array declarator. gcc/c: * c-parser.cc (c_parser_direct_declarator_inner): Add error message. gcc/testsuite: * gcc.dg/c99-arraydecl-4.c: New test. Diff: --- gcc/c/c-parser.cc | 63 -- gcc/testsuite/gcc.dg/c99-arraydecl-4.c | 14 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 6a3f96d5b61..8c4e697a4e1 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -4715,8 +4715,6 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, location_t brace_loc = c_parser_peek_token (parser)->location; struct c_declarator *declarator; struct c_declspecs *quals_attrs = build_null_declspecs (); - bool static_seen; - bool star_seen; struct c_expr dimen; dimen.value = NULL_TREE; dimen.original_code = ERROR_MARK; @@ -4724,49 +4722,48 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, c_parser_consume_token (parser); c_parser_declspecs (parser, quals_attrs, false, false, true, false, false, false, false, cla_prefer_id); - static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC); - if (static_seen) - c_parser_consume_token (parser); - if (static_seen && !quals_attrs->declspecs_seen_p) - c_parser_declspecs (parser, quals_attrs, false, false, true, - false, false, false, false, cla_prefer_id); + + location_t static_loc = UNKNOWN_LOCATION; + if (c_parser_next_token_is_keyword (parser, RID_STATIC)) + { + static_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (!quals_attrs->declspecs_seen_p) + c_parser_declspecs (parser, quals_attrs, false, false, true, + false, false, false, false, cla_prefer_id); + } if (!quals_attrs->declspecs_seen_p) quals_attrs = NULL; /* If "static" is present, there must be an array dimension. Otherwise, there may be a dimension, "*", or no dimension. */ - if (static_seen) + const bool static_seen = (static_loc != UNKNOWN_LOCATION); + bool star_seen = false; + if (c_parser_next_token_is (parser, CPP_MULT) + && c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) { - star_seen = false; - dimen = c_parser_expr_no_commas (parser, NULL); + star_seen = true; + c_parser_consume_token (parser); } - else + else if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + dimen = c_parser_expr_no_commas (parser, NULL); + + if (static_seen) { - if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) - { - dimen.value = NULL_TREE; - star_seen = false; - } - else if (c_parser_next_token_is (parser, CPP_MULT)) - { - if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) - { - dimen.value = NULL_TREE; - star_seen = true; - c_parser_consume_token (parser); - } - else - { - star_seen = false; - dimen = c_parser_expr_no_commas (parser, NULL); - } - } - else + if (star_seen) { + error_at (static_loc, + "% may not be used with an unspecified " + "variable length array size"); + /* Prevent further errors. */ star_seen = false; - dimen = c_parser_expr_no_commas (parser, NULL); + dimen.value = error_mark_node; } + else if (!dimen.value) + error_at (static_loc, + "% may not be used without an array size"); } + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) c_parser_consume_token (parser); else diff --git a/gcc/testsuite/gcc.dg/c99-arraydecl-4.c b/gcc/testsuite/gcc.dg/c99-arraydecl-4.c new file mode 100644 index 000..f8cad3b9429 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-arraydecl-4.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -pedantic-errors" } */ + +void fo(char buf[static]); /* { dg-error "'static' may not be used without an array size" } */ +void fo(char buf[static]) { } /* { dg-error "'static' may not be used without an array size" }
[gcc r15-1394] c23: Fix for redeclared enumerator initialized with different type [PR115109]
https://gcc.gnu.org/g:c9b96a68860bfdee49d40b4a844af7c5ef69cd12 commit r15-1394-gc9b96a68860bfdee49d40b4a844af7c5ef69cd12 Author: Martin Uecker Date: Sat May 18 22:00:04 2024 +0200 c23: Fix for redeclared enumerator initialized with different type [PR115109] c23 specifies that the type of a redeclared enumerator is the one of the previous declaration. Convert initializers with different type accordingly and emit an error when the value does not fit. 2024-06-01 Martin Uecker PR c/115109 gcc/c/ * c-decl.cc (build_enumerator): When redeclaring an enumerator convert value to previous type. For redeclared enumerators use underlying type for computing the next value. gcc/testsuite/ * gcc.dg/pr115109.c: New test. * gcc.dg/c23-tag-enum-6.c: New test. * gcc.dg/c23-tag-enum-7.c: New test. Diff: --- gcc/c/c-decl.cc | 29 ++--- gcc/testsuite/gcc.dg/c23-tag-enum-6.c | 20 + gcc/testsuite/gcc.dg/c23-tag-enum-7.c | 41 +++ gcc/testsuite/gcc.dg/pr115109.c | 8 +++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 6c09eb731284..01326570e2b2 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -10277,6 +10277,7 @@ build_enumerator (location_t decl_loc, location_t loc, struct c_enum_contents *the_enum, tree name, tree value) { tree decl; + tree old_decl; /* Validate and default VALUE. */ @@ -10336,6 +10337,23 @@ build_enumerator (location_t decl_loc, location_t loc, definition. */ value = convert (the_enum->enum_type, value); } + else if (flag_isoc23 + && (old_decl = lookup_name_in_scope (name, current_scope)) + && old_decl != error_mark_node + && TREE_TYPE (old_decl) + && TREE_TYPE (TREE_TYPE (old_decl)) + && TREE_CODE (old_decl) == CONST_DECL) +{ + /* Enumeration constants in a redeclaration have the previous type. */ + tree previous_type = TREE_TYPE (DECL_INITIAL (old_decl)); + if (!int_fits_type_p (value, previous_type)) + { + error_at (loc, "value of redeclared enumerator outside the range " +"of %qT", previous_type); + locate_old_decl (old_decl); + } + value = convert (previous_type, value); +} else { /* Even though the underlying type of an enum is unspecified, the @@ -10402,9 +10420,14 @@ build_enumerator (location_t decl_loc, location_t loc, false); } else -the_enum->enum_next_value - = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), -PLUS_EXPR, value, integer_one_node, false); +{ + /* In a redeclaration the type can already be the enumeral type. */ + if (TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE) + value = convert (ENUM_UNDERLYING_TYPE (TREE_TYPE (value)), value); + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, value, integer_one_node, false); +} the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); if (the_enum->enum_overflow && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c new file mode 100644 index ..29aef7ee3fdf --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -fno-short-enums" } */ + +#include + +enum E : int { a = 1, b = 2 }; +enum E : int { b = _Generic(a, enum E: 2), a = 1 }; + +enum H { x = 1 }; +enum H { x = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */ + +enum K : int { z = 1 }; +enum K : int { z = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */ + +enum F { A = 0, B = UINT_MAX }; +enum F { B = UINT_MAX, A };/* { dg-error "outside the range" } */ + +enum G : unsigned int { C = 0, D = UINT_MAX }; +enum G : unsigned int { D = UINT_MAX, C }; /* { dg-error "overflow" } */ + diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c new file mode 100644 index ..d4c787c8f716 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c @@ -0,0 +1,41 @@ +/* { dg-do compile } + * { dg-options "-std=c23 -fno-short-enums" } */ + +#include + +// enumerators are all representable in int +enum E { a = 1UL, b = _Generic(a, int: 2) }; +static_assert(_Generic(a, int: 1)); +static_assert(_Generic(b, int: 1)); +enum E { a = 1UL, b = _Generic(a, int: 2) }; +static_assert(_Generic(a, int: 1)); +static_assert(_Generic(b, int: 1)); + +// enumerators are not representable in int +enum H { c = 1UL << (UINT_WIDTH +
[gcc r15-934] C23: allow aliasing for types derived from structs with variable size
https://gcc.gnu.org/g:d2cfe8a73b3c4195a25cde28e1641ef36ebb08c1 commit r15-934-gd2cfe8a73b3c4195a25cde28e1641ef36ebb08c1 Author: Martin Uecker Date: Fri May 24 12:35:27 2024 +0200 C23: allow aliasing for types derived from structs with variable size Previously, we set the aliasing set of structures with variable size struct foo { int x[n]; char b; }; to zero. The reason is that such types can be compatible to diffrent structure types which are incompatible. struct foo { int x[2]; char b; }; struct foo { int x[3]; char b; }; But it is not enough to set the aliasing set to zero, because derived types would then still end up in different equivalence classes even though they might be compatible. Instead those types should be set to structural equivalency. We also add checking assertions that ensure that TYPE_CANONICAL is set correctly for all tagged types. gcc/c/ * c-decl.cc (finish_struct): Do not set TYPE_CANONICAL for structure or unions with variable size. * c-objc-common.cc (c_get_alias_set): Do not set alias set to zero. * c-typeck.cc (comptypes_verify): New function. (comptypes,comptypes_same_p,comptypes_check_enum_int): Add assertion. (comptypes_equiv_p): Add assertion that ensures that compatible types have the same equivalence class. (tagged_types_tu_compatible_p): Remove now unneeded special case. gcc/testsuite/ * gcc.dg/gnu23-tag-alias-8.c: New test. Diff: --- gcc/c/c-decl.cc | 2 +- gcc/c/c-objc-common.cc | 5 - gcc/c/c-typeck.cc| 37 +--- gcc/testsuite/gcc.dg/gnu23-tag-alias-8.c | 24 + 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 6e6606c9570..9f7d55c0b10 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9749,7 +9749,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_BEING_DEFINED (t) = 0; /* Set type canonical based on equivalence class. */ - if (flag_isoc23) + if (flag_isoc23 && !C_TYPE_VARIABLE_SIZE (t)) { if (c_struct_htab == NULL) c_struct_htab = hash_table::create_ggc (61); diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index 283f6a8ae26..738e899a2a9 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -420,11 +420,6 @@ c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED) alias_set_type c_get_alias_set (tree t) { - /* Structs with variable size can alias different incompatible - structs. Let them alias anything. */ - if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t)) -return 0; - return c_common_get_alias_set (t); } diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 09b2c265a46..48934802148 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1167,6 +1167,28 @@ common_type (tree t1, tree t2) return c_common_type (t1, t2); } + + +/* Helper function for comptypes. For two compatible types, return 1 + if they pass consistency checks. In particular we test that + TYPE_CANONICAL is set correctly, i.e. the two types can alias. */ + +static bool +comptypes_verify (tree type1, tree type2) +{ + if (TYPE_CANONICAL (type1) != TYPE_CANONICAL (type2) + && !TYPE_STRUCTURAL_EQUALITY_P (type1) + && !TYPE_STRUCTURAL_EQUALITY_P (type2)) +{ + /* FIXME: check other types. */ + if (RECORD_OR_UNION_TYPE_P (type1) + || TREE_CODE (type1) == ENUMERAL_TYPE + || TREE_CODE (type2) == ENUMERAL_TYPE) + return false; +} + return true; +} + struct comptypes_data { bool enum_and_int_p; bool different_types_p; @@ -1188,6 +1210,8 @@ comptypes (tree type1, tree type2) struct comptypes_data data = { }; bool ret = comptypes_internal (type1, type2, ); + gcc_checking_assert (!ret || comptypes_verify (type1, type2)); + return ret ? (data.warning_needed ? 2 : 1) : 0; } @@ -1201,6 +1225,8 @@ comptypes_same_p (tree type1, tree type2) struct comptypes_data data = { }; bool ret = comptypes_internal (type1, type2, ); + gcc_checking_assert (!ret || comptypes_verify (type1, type2)); + if (data.different_types_p) return false; @@ -1218,6 +1244,8 @@ comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) bool ret = comptypes_internal (type1, type2, ); *enum_and_int_p = data.enum_and_int_p; + gcc_checking_assert (!ret || comptypes_verify (type1, type2)); + return ret ? (data.warning_needed ? 2 : 1) : 0; } @@ -1232,6 +1260,8 @@ comptypes_check_different_types (tree type1, tree type2, bool ret = comptypes_internal (type1, type2, ); *different_types_p = data.different_types_p; + gcc_checking_assert (!ret || comptypes_verify (type1, type2)); + return ret ? (data.warning_needed ? 2 :
[gcc r15-933] C: allow aliasing of compatible types derived from enumeral types [PR115157]
https://gcc.gnu.org/g:867d1264fe71d4291194373d1a1c409cac97a597 commit r15-933-g867d1264fe71d4291194373d1a1c409cac97a597 Author: Martin Uecker Date: Sun May 19 23:13:22 2024 +0200 C: allow aliasing of compatible types derived from enumeral types [PR115157] Aliasing of enumeral types with the underlying integer is now allowed by setting the aliasing set to zero. But this does not allow aliasing of derived types which are compatible as required by ISO C. Instead, initially set structural equality. Then set TYPE_CANONICAL and update pointers and main variants when the type is completed (as done for structures and unions in C23). PR tree-optimization/115157 PR tree-optimization/115177 gcc/c/ * c-decl.cc (shadow_tag-warned,parse_xref_tag,start_enum, finish_enum): Set SET_TYPE_STRUCTURAL_EQUALITY / TYPE_CANONICAL. * c-objc-common.cc (get_alias_set): Remove special case. (get_aka_type): Add special case. gcc/c-family/ * c-attribs.cc (handle_hardbool_attribute): Set TYPE_CANONICAL for hardbools. gcc/ * godump.cc (go_output_typedef): Use TYPE_MAIN_VARIANT instead of TYPE_CANONICAL. gcc/testsuite/ * gcc.dg/enum-alias-1.c: New test. * gcc.dg/enum-alias-2.c: New test. * gcc.dg/enum-alias-3.c: New test. * gcc.dg/enum-alias-4.c: New test. Diff: --- gcc/c-family/c-attribs.cc | 1 + gcc/c/c-decl.cc | 11 +-- gcc/c/c-objc-common.cc | 7 ++- gcc/godump.cc | 10 +++--- gcc/testsuite/gcc.dg/enum-alias-1.c | 24 gcc/testsuite/gcc.dg/enum-alias-2.c | 25 + gcc/testsuite/gcc.dg/enum-alias-3.c | 26 ++ gcc/testsuite/gcc.dg/enum-alias-4.c | 22 ++ 8 files changed, 112 insertions(+), 14 deletions(-) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 605469dd7dd..e3833ed5f20 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -1074,6 +1074,7 @@ handle_hardbool_attribute (tree *node, tree name, tree args, TREE_SET_CODE (*node, ENUMERAL_TYPE); ENUM_UNDERLYING_TYPE (*node) = orig; + TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig); tree false_value; if (args) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index b691b91b3db..6e6606c9570 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -5051,7 +5051,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) if (t == NULL_TREE) { t = make_node (code); - if (flag_isoc23 && code != ENUMERAL_TYPE) + if (flag_isoc23 || code == ENUMERAL_TYPE) SET_TYPE_STRUCTURAL_EQUALITY (t); pushtag (input_location, name, t); } @@ -8828,7 +8828,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, the forward-reference will be altered into a real type. */ ref = make_node (code); - if (flag_isoc23 && code != ENUMERAL_TYPE) + if (flag_isoc23 || code == ENUMERAL_TYPE) SET_TYPE_STRUCTURAL_EQUALITY (ref); if (code == ENUMERAL_TYPE) { @@ -9919,6 +9919,7 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, { enumtype = make_node (ENUMERAL_TYPE); TYPE_SIZE (enumtype) = NULL_TREE; + SET_TYPE_STRUCTURAL_EQUALITY (enumtype); pushtag (loc, name, enumtype); if (fixed_underlying_type != NULL_TREE) { @@ -9935,6 +9936,8 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, TYPE_SIZE (enumtype) = NULL_TREE; TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type); ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type; + TYPE_CANONICAL (enumtype) = TYPE_CANONICAL (fixed_underlying_type); + c_update_type_canonical (enumtype); layout_type (enumtype); } } @@ -10094,6 +10097,10 @@ finish_enum (tree enumtype, tree values, tree attributes) ENUM_UNDERLYING_TYPE (enumtype) = c_common_type_for_size (TYPE_PRECISION (tem), TYPE_UNSIGNED (tem)); + TYPE_CANONICAL (enumtype) = + TYPE_CANONICAL (ENUM_UNDERLYING_TYPE (enumtype)); + c_update_type_canonical (enumtype); + layout_type (enumtype); } diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index 42a62c84fe7..283f6a8ae26 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -130,6 +130,8 @@ get_aka_type (tree type) result = get_aka_type (orig_type); } + else if (TREE_CODE (type) == ENUMERAL_TYPE) +return type; else { tree canonical = TYPE_CANONICAL (type); @@ -418,11 +420,6 @@ c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED) alias_set_type
[gcc r15-912] C23: fix aliasing for structures/unions with incomplete types
https://gcc.gnu.org/g:86b98d939989427ff025bcfd536ad361fcdc699c commit r15-912-g86b98d939989427ff025bcfd536ad361fcdc699c Author: Martin Uecker Date: Sat Mar 30 19:49:48 2024 +0100 C23: fix aliasing for structures/unions with incomplete types When incomplete structure/union types are completed later, compatibility of struct types that contain pointers to such types changes. When forming equivalence classes for TYPE_CANONICAL, we therefor need to be conservative and treat all structs with the same tag which are pointer targets as equivalent for purposed of determining equivalency of structure/union types which contain such types as member. This avoids having to update TYPE_CANONICAL of such structure/unions recursively. The pointer types themselves are updated in c_update_type_canonical. gcc/c/ * c-typeck.cc (comptypes_internal): Add flag to track whether a struct is the target of a pointer. (tagged_types_tu_compatible): When forming equivalence classes, treat nested pointed-to structs as equivalent. gcc/testsuite/ * gcc.dg/c23-tag-incomplete-alias-1.c: New test. Diff: --- gcc/c/c-typeck.cc | 43 +-- gcc/testsuite/gcc.dg/c23-tag-incomplete-alias-1.c | 36 +++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ad4c7add562..09b2c265a46 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1172,6 +1172,7 @@ struct comptypes_data { bool different_types_p; bool warning_needed; bool anon_field; + bool pointedto; bool equiv; const struct tagged_tu_seen_cache* cache; @@ -1235,8 +1236,36 @@ comptypes_check_different_types (tree type1, tree type2, } -/* Like comptypes, but if it returns nonzero for struct and union - types considered equivalent for aliasing purposes. */ +/* Like comptypes, but if it returns true for struct and union types + considered equivalent for aliasing purposes, i.e. for setting + TYPE_CANONICAL after completing a struct or union. + + This function must return false only for types which are not + compatible according to C language semantics (cf. comptypes), + otherwise the middle-end would make incorrect aliasing decisions. + It may return true for some similar types that are not compatible + according to those stricter rules. + + In particular, we ignore size expression in arrays so that the + following structs are in the same equivalence class: + + struct foo { char (*buf)[]; }; + struct foo { char (*buf)[3]; }; + struct foo { char (*buf)[4]; }; + + We also treat unions / structs with members which are pointers to + structures or unions with the same tag as equivalent (if they are not + incompatible for other reasons). Although incomplete structure + or union types are not compatible to any other type, they may become + compatible to different types when completed. To avoid having to update + TYPE_CANONICAL at this point, we only consider the tag when forming + the equivalence classes. For example, the following types with tag + 'foo' are all considered equivalent: + + struct bar; + struct foo { struct bar *x }; + struct foo { struct bar { int a; } *x }; + struct foo { struct bar { char b; } *x }; */ bool comptypes_equiv_p (tree type1, tree type2) @@ -1357,6 +1386,7 @@ comptypes_internal (const_tree type1, const_tree type2, /* Do not remove mode information. */ if (TYPE_MODE (t1) != TYPE_MODE (t2)) return false; + data->pointedto = true; return comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data); case FUNCTION_TYPE: @@ -1375,7 +1405,7 @@ comptypes_internal (const_tree type1, const_tree type2, if ((d1 == NULL_TREE) != (d2 == NULL_TREE)) data->different_types_p = true; - /* Ignore size mismatches. */ + /* Ignore size mismatches when forming equivalence classes. */ if (data->equiv) return true; /* Sizes must match unless one is missing or variable. */ @@ -1515,6 +1545,12 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, if (TYPE_NAME (t1) != TYPE_NAME (t2)) return false; + /* When forming equivalence classes for TYPE_CANONICAL in C23, we treat + structs with the same tag as equivalent, but only when they are targets + of pointers inside other structs. */ + if (data->equiv && data->pointedto) +return true; + if (!data->anon_field && NULL_TREE == TYPE_NAME (t1)) return false; @@ -1610,6 +1646,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, return false; data->anon_field = !DECL_NAME (s1); + data->pointedto = false; data->cache = if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data)) diff --git
[gcc r15-825] c: Fix for some variably modified types not being recognized [PR114831]
https://gcc.gnu.org/g:9f1798c1a93257526196a3c19828e40fb28ac551 commit r15-825-g9f1798c1a93257526196a3c19828e40fb28ac551 Author: Martin Uecker Date: Sat May 18 14:40:02 2024 +0200 c: Fix for some variably modified types not being recognized [PR114831] We did not evaluate expressions with variably modified types correctly in typeof and did not produce warnings when jumping over declarations using typeof. After addressof or array-to-pointer decay we construct new pointer types that have to be marked variably modified if the pointer target is variably modified. 2024-05-18 Martin Uecker PR c/114831 gcc/c/ * c-typeck.cc (array_to_pointer_conversion, build_unary_op): Propagate flag to pointer target. gcc/testsuite/ * gcc.dg/pr114831-1.c: New test. * gcc.dg/pr114831-2.c: New test. * gcc.dg/gnu23-varmod-1.c: New test. * gcc.dg/gnu23-varmod-2.c: New test. Diff: --- gcc/c/c-typeck.cc | 9 + gcc/testsuite/gcc.dg/gnu23-varmod-1.c | 12 gcc/testsuite/gcc.dg/gnu23-varmod-2.c | 16 gcc/testsuite/gcc.dg/pr114831-1.c | 27 +++ gcc/testsuite/gcc.dg/pr114831-2.c | 16 5 files changed, 80 insertions(+) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7ecca9f58c6..2d092357e0f 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1891,8 +1891,12 @@ 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; + if (INDIRECT_REF_P (exp)) return convert (ptrtype, TREE_OPERAND (exp, 0)); @@ -4630,6 +4634,7 @@ 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) @@ -5113,8 +5118,12 @@ 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; + /* ??? Cope with user tricks that amount to offsetof. Delete this when we have proper support for integer constant expressions. */ val = get_base_address (arg); diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-1.c b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c new file mode 100644 index 000..add10d13573 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } + * { dg-options "-std=gnu23" } */ + +int foo(int n) +{ + int (*a(void))[n] { return 0; }; + goto err; /* { dg-error "jump into scope" "variably modified" } */ + typeof((n++,a)) b2; +err: + return n; +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-2.c b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c new file mode 100644 index 000..c36af1d1647 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c @@ -0,0 +1,16 @@ +/* { dg-do run } + * { dg-options "-std=gnu23" } */ + +int foo(int n) +{ + int (*a(void))[n] { return 0; }; + typeof((n++,a)) b2; + return n; +} + +int main() +{ + if (2 != foo(1)) + __builtin_abort(); +} + diff --git a/gcc/testsuite/gcc.dg/pr114831-1.c b/gcc/testsuite/gcc.dg/pr114831-1.c new file mode 100644 index 000..ed30a494b3c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114831-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } */ + +void f(int n) +{ + int a[n]; + goto foo; /* { dg-error "jump into scope" "variably modified" } */ + typeof(a) b1; +foo: +} + +void g(int n) +{ + int a2[1][n]; + goto foo; /* { dg-error "jump into scope" "variably modified" } */ + typeof((n++,a2)) b2; +foo: +} + +void h(int n) +{ + int a[n]; + typeof(a) b1; + goto foo; /* { dg-error "jump into scope" "variably modified" } */ + typeof() b; +foo: +} diff --git a/gcc/testsuite/gcc.dg/pr114831-2.c b/gcc/testsuite/gcc.dg/pr114831-2.c new file mode 100644 index 000..ecfd87988c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114831-2.c @@ -0,0 +1,16 @@ +/* { dg-do run } + * { dg-options "-std=c23" } */ + +int foo(int n) +{ + int a[1][n]; + typeof((n++,a)) b2; + return n; +} + +int main() +{ + if (2 != foo(1)) + __builtin_abort(); +} +
[gcc r14-9805] Revert "Fix ICE with -g and -std=c23 related to incomplete types [PR114361]"
https://gcc.gnu.org/g:8057f9aa1f7e70490064de796d7a8d42d446caf8 commit r14-9805-g8057f9aa1f7e70490064de796d7a8d42d446caf8 Author: Martin Uecker Date: Fri Apr 5 12:14:56 2024 +0200 Revert "Fix ICE with -g and -std=c23 related to incomplete types [PR114361]" This reverts commit 871bb5ad2dd56343d80b6a6d269e85efdce5 because it breaks LTO and needs a bit more work. See PR 114574. Diff: --- gcc/c/c-decl.cc | 1 - gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c | 14 -- gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c | 13 - gcc/testsuite/gcc.dg/pr114361.c | 11 --- 4 files changed, 39 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index f2083b9d96f..c747abe9f4e 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9722,7 +9722,6 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t); C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; - TYPE_CANONICAL (x) = TYPE_CANONICAL (t); } /* Update type location to the one of the definition, instead of e.g. diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c deleted file mode 100644 index 82d652569e9..000 --- a/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c +++ /dev/null @@ -1,14 +0,0 @@ -/* { dg-do compile } - * { dg-options "-std=c23 -g" } */ - -struct a; -typedef struct a b; - -void g() { -struct a { b* x; }; -} - -struct a { b* x; }; - - - diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c deleted file mode 100644 index bc47a04ece5..000 --- a/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c +++ /dev/null @@ -1,13 +0,0 @@ -/* { dg-do compile } - * { dg-options "-std=c23 -g" } */ - -struct a; -typedef struct a b; - -void f() { - extern struct a { b* x; } t; -} - -extern struct a { b* x; } t; - - diff --git a/gcc/testsuite/gcc.dg/pr114361.c b/gcc/testsuite/gcc.dg/pr114361.c deleted file mode 100644 index 0f3feb53566..000 --- a/gcc/testsuite/gcc.dg/pr114361.c +++ /dev/null @@ -1,11 +0,0 @@ -/* PR c/114361 */ -/* { dg-do compile } */ -/* { dg-options "-std=gnu23 -g" } */ - -void f() -{ -typedef struct foo bar; -typedef __typeof( ({ (struct foo { bar *x; }){ }; }) ) wuz; -struct foo { wuz *x; }; -} -
[gcc r14-9763] Fix ICE with -g and -std=c23 related to incomplete types [PR114361]
https://gcc.gnu.org/g:871bb5ad2dd56343d80b6a6d269e85efdce5 commit r14-9763-g871bb5ad2dd56343d80b6a6d269e85efdce5 Author: Martin Uecker Date: Thu Mar 28 19:15:40 2024 +0100 Fix ICE with -g and -std=c23 related to incomplete types [PR114361] We did not copy TYPE_CANONICAL to the incomplete variants when completing a structure. PR c/114361 gcc/c/ * c-decl.cc (finish_struct): Set TYPE_CANONICAL when completing strucute types. gcc/testsuite/ * gcc.dg/pr114361.c: New test. * gcc.dg/c23-tag-incomplete-1.c: New test. * gcc.dg/c23-tag-incomplete-2.c: New test. Diff: --- gcc/c/c-decl.cc | 1 + gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c | 14 ++ gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c | 13 + gcc/testsuite/gcc.dg/pr114361.c | 11 +++ 4 files changed, 39 insertions(+) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index c747abe9f4e..f2083b9d96f 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9722,6 +9722,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t); C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; + TYPE_CANONICAL (x) = TYPE_CANONICAL (t); } /* Update type location to the one of the definition, instead of e.g. diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c new file mode 100644 index 000..82d652569e9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } + * { dg-options "-std=c23 -g" } */ + +struct a; +typedef struct a b; + +void g() { +struct a { b* x; }; +} + +struct a { b* x; }; + + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c new file mode 100644 index 000..bc47a04ece5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile } + * { dg-options "-std=c23 -g" } */ + +struct a; +typedef struct a b; + +void f() { + extern struct a { b* x; } t; +} + +extern struct a { b* x; } t; + + diff --git a/gcc/testsuite/gcc.dg/pr114361.c b/gcc/testsuite/gcc.dg/pr114361.c new file mode 100644 index 000..0f3feb53566 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114361.c @@ -0,0 +1,11 @@ +/* PR c/114361 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu23 -g" } */ + +void f() +{ +typedef struct foo bar; +typedef __typeof( ({ (struct foo { bar *x; }){ }; }) ) wuz; +struct foo { wuz *x; }; +} +