Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
Version 7.1

10/9/26 [GH #260]
GNU and Clang C++ modes: members skipped by a designated initializer

In GNU C++ modes before C++20 and in all Clang C++ modes, a member that was
not designated, but that precedes a designated member, was zero-initialized
instead of being initialized from its default member initializer. That is
now fixed. For example, with --gnu_version=170100:

struct P { int x = 1, y = 2, z = 3; };
P p = { .x = 10, .z = 30 }; // p.y was previously 0. It is now 2.


10/9/26 [GH #27]
Clearer diagnostic when auto is deduced from an incomplete type

Expand Down
36 changes: 25 additions & 11 deletions src/cp_gen_be.c
Original file line number Diff line number Diff line change
Expand Up @@ -8305,6 +8305,25 @@ one step instead of class-by-class, return TRUE.
} /* pm_cast_is_unambiguous */


static a_constant_ptr first_explicit_aggr_constant(a_constant_ptr con)
/*
con is NULL or a constant in the list of an aggregate constant. Return the
first constant in that list, starting with con, that is not an implicit
initializer for a base class or member (such initializers do not appear in
the generated source), or NULL if there is none.
*/
{
while (con != NULL &&
(con->constant_for_base_class_from_constexpr_folding ||
con->implicit_aggr_element ||
(constant_is(con, ck_dynamic_init) &&
is_default_dynamic_init(con->variant.dynamic_init.ptr)))) {
con = con->next;
} /* while */
return con;
} /* first_explicit_aggr_constant */


static void gen_designator(a_constant_ptr con,
a_field_ptr *field,
a_constant_ptr *p_eff_con,
Expand Down Expand Up @@ -8388,12 +8407,13 @@ brace/parenthesis delimiters around it should be suppressed.
if (!eff_con->explicit_braces_on_aggregate &&
!eff_con->explicit_parentheses_on_aggregate &&
!eff_con->explicit_cast_applied) {
a_constant_ptr first_con = eff_con->variant.aggregate.first_constant;
first_con = first_explicit_aggr_constant(first_con);
*suppress_delims = TRUE;
if (eff_con->variant.aggregate.first_constant != NULL &&
constant_is(eff_con->variant.aggregate.first_constant,
ck_designator)) {
if (first_con != NULL && constant_is(first_con, ck_designator)) {
/* Do not close the designator if another one will follow
immediately. */
immediately (i.e., a chained designator, possibly preceded by
implicit initializers for the members it skips). */
close = FALSE;
} /* if */
} /* if */
Expand Down Expand Up @@ -8603,13 +8623,7 @@ which constant is the value.
/* Loop through the list of initializer constants. */
/* First, skip over any implicit initializers for base classes and
initial members; they shouldn't appear in the generated source. */
for (sub_con = first_con;
sub_con != NULL &&
(sub_con->constant_for_base_class_from_constexpr_folding ||
sub_con->implicit_aggr_element ||
(sub_con->kind == (a_constant_repr_kind)ck_dynamic_init &&
is_default_dynamic_init(sub_con->variant.dynamic_init.ptr)));
sub_con = sub_con->next) {}
sub_con = first_explicit_aggr_constant(first_con);
if (sub_con != NULL &&
sub_con->kind == (a_constant_repr_kind)ck_init_repeat) {
/* A ck_init_repeat constant is used to do default initialization
Expand Down
56 changes: 44 additions & 12 deletions src/decl_inits.c
Original file line number Diff line number Diff line change
Expand Up @@ -3319,6 +3319,33 @@ Return TRUE if field second follows field first in the declaration order.
} /* fields_are_ordered */


static a_boolean field_range_is_designated(a_constant_ptr aggr_con,
a_field_ptr first,
a_field_ptr end)
/*
Return TRUE if a ck_designator constant in the aggregate constant aggr_con
designates field first or a field declared between first and end (excluding
end itself). That is possible only when out-of-order designators are accepted:
E.g., in "{ .c = 3, .a = 1, .d = 4 }", c lies between b (the field following
a) and d.
*/
{
a_boolean result = FALSE;
a_constant_ptr con;

for (con = aggr_con->variant.aggregate.first_constant;
con != NULL && !result;
con = con->next) {
if (constant_is(con, ck_designator) &&
con->variant.designator.is_field_designator) {
a_field_ptr fp = con->variant.designator.variant.field;
result = fields_are_ordered(first, fp) && !fields_are_ordered(end, fp);
} /* if */
} /* for */
return result;
} /* field_range_is_designated */


static void aggr_init_field_designator(an_init_component_ptr *p_icp,
a_type_ptr class_type,
an_init_state *is,
Expand Down Expand Up @@ -3561,18 +3588,23 @@ initialization. */
} /* if */
if (okay) {
if ((orig_field != *field || *p_bcp != NULL ) &&
cpp20_designators_restriction && !is->init_error &&
!is->check_validity_only && orig_field != NULL &&
!type_is(class_type, tk_union)) {
/* C++20 designators can cause base classes and certain members to
be skipped. Initialize those members before initializing the
designated member. If we found an error, we shouldn't proceed with
the initialization of remaining members, as the designators
may not be in order. If orig_field is NULL, we have already
initialized all the members and this designator is invalid. It is
possible that it has not been diagnosed as invalid yet, so we
check orig_field here just in case. If we're checking validity only,
there's no need to initialize the remainder. */
!is->init_error && !is->check_validity_only && orig_field != NULL &&
!type_is(class_type, tk_union) &&
(cpp20_designators_restriction || gpp_version_is(>= 80000) ||
(clang_mode && !C_mode() && fields_are_ordered(orig_field, *field) &&
!field_range_is_designated(aggr_con, orig_field, *field)))) {
/* C++ designators can cause base classes and certain members to
be skipped. Initialize those members (e.g., using their default member
initializers) before initializing the designated member. If we found
an error, we shouldn't proceed with the initialization of remaining
members, as the designators may not be in order. If orig_field is
NULL, we have already initialized all the members and this designator
is invalid. It is possible that it has not been diagnosed as invalid
yet, so we check orig_field here just in case. If we're checking
validity only, there's no need to initialize the remainder. Clang
accepts out-of-order designators (with a warning), so in that mode the
skipped members are initialized only if the designator does not go
backward and none of them was designated earlier. */
aggr_init_class_remainder_if_needed(aggr_con, class_type, orig_field,
*p_bcp, is, diag_pos, *field);
*p_bcp = NULL;
Expand Down
1 change: 0 additions & 1 deletion tests/expectations/edg_x86_32/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -7525,7 +7525,6 @@ gnu/cpp/diagnostic/alignof3.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/auto1.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-no-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/base.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:ABORT:
gnu/cpp/diagnostic/bindings1.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/constexpr3.sft.cpp:fn:-DTEST_NUMBER=1 --c++14:ABORT:
gnu/cpp/diagnostic/constexpr4.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
Expand Down
1 change: 0 additions & 1 deletion tests/expectations/edg_x86_32_cp/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -7547,7 +7547,6 @@ gnu/cpp/diagnostic/alignof3.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/auto1.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-no-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/base.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:ABORT:
gnu/cpp/diagnostic/bindings1.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/constexpr3.sft.cpp:fn:-DTEST_NUMBER=1 --c++14:ABORT:
gnu/cpp/diagnostic/constexpr4.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
Expand Down
4 changes: 0 additions & 4 deletions tests/expectations/edg_x86_64/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -1424,9 +1424,6 @@ clang/cpp/SemaCXX/unavailable_aligned_allocation.sft.cpp:fn:-DTEST_NUMBER=7 --c+
clang/cpp/SemaCXX/unavailable_aligned_allocation.sft.cpp:fn:-DTEST_NUMBER=8 --c++17 -DWATCHOS -w --exceptions:FAIL:
clang/cpp/SemaCXX/unavailable_aligned_allocation.sft.cpp:fn:-DTEST_NUMBER=9 --c++17 -DNO_ERRORS --exceptions:FAIL:
clang/cpp/SemaCXX/undefined-inline.sft.cpp:fp:-DTEST_NUMBER=1 -w --c++11:FAIL:
clang/cpp/SemaCXX/uninitialized.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:ABORT:
clang/cpp/SemaCXX/uninitialized.sft.cpp:fp:-DTEST_NUMBER=2 --c++17:ABORT:
clang/cpp/SemaCXX/uninitialized.sft.cpp:fp:-DTEST_NUMBER=3 --c++20:ABORT:
clang/cpp/SemaCXX/unqualified-std-call-fixits.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
clang/cpp/SemaCXX/unqualified-std-call-fixits.sft.cpp:fp:-DTEST_NUMBER=2 --c++20:FAIL:
clang/cpp/SemaCXX/unqualified-std-call-fixits.sft.cpp:fp:-DTEST_NUMBER=3 --c++20:FAIL:
Expand Down Expand Up @@ -7195,7 +7192,6 @@ gnu/cpp/diagnostic/alignof3.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/auto1.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-no-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/base.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:ABORT:
gnu/cpp/diagnostic/bindings1.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/constexpr3.sft.cpp:fn:-DTEST_NUMBER=1 --c++14:ABORT:
gnu/cpp/diagnostic/constexpr4.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
Expand Down
4 changes: 0 additions & 4 deletions tests/expectations/edg_x86_64_cp/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -1418,9 +1418,6 @@ clang/cpp/SemaCXX/unavailable_aligned_allocation.sft.cpp:fn:-DTEST_NUMBER=7 --c+
clang/cpp/SemaCXX/unavailable_aligned_allocation.sft.cpp:fn:-DTEST_NUMBER=8 --c++17 -DWATCHOS -w --exceptions:FAIL:
clang/cpp/SemaCXX/unavailable_aligned_allocation.sft.cpp:fn:-DTEST_NUMBER=9 --c++17 -DNO_ERRORS --exceptions:FAIL:
clang/cpp/SemaCXX/undefined-inline.sft.cpp:fp:-DTEST_NUMBER=1 -w --c++11:FAIL:
clang/cpp/SemaCXX/uninitialized.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:ABORT:
clang/cpp/SemaCXX/uninitialized.sft.cpp:fp:-DTEST_NUMBER=2 --c++17:ABORT:
clang/cpp/SemaCXX/uninitialized.sft.cpp:fp:-DTEST_NUMBER=3 --c++20:ABORT:
clang/cpp/SemaCXX/unqualified-std-call-fixits.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
clang/cpp/SemaCXX/unqualified-std-call-fixits.sft.cpp:fp:-DTEST_NUMBER=2 --c++20:FAIL:
clang/cpp/SemaCXX/unqualified-std-call-fixits.sft.cpp:fp:-DTEST_NUMBER=3 --c++20:FAIL:
Expand Down Expand Up @@ -7191,7 +7188,6 @@ gnu/cpp/diagnostic/alignof3.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/auto1.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/bad-binary-ops-no-highlight-colors.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/base.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:ABORT:
gnu/cpp/diagnostic/bindings1.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/diagnostic/constexpr3.sft.cpp:fn:-DTEST_NUMBER=1 --c++14:ABORT:
gnu/cpp/diagnostic/constexpr4.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
static constexpr C c2 = { .a = 1.0, .x = 3 };
^

"Test_name.c", line 86: error: static assertion failed
static_assert(a.a.d == string{}.d);
^
"Test_name.c", line 86: note: the final comparison was 0 == 43
static_assert(a.a.d == string{}.d);
^

"Test_name.c", line 87: error: static assertion failed
static_assert(a.b == 42);
^
"Test_name.c", line 87: note: the final comparison was 0 == 42
static_assert(a.b == 42);
^

"Test_name.c", line 112: error: an initializer cannot be specified for a flexible array member
int y[] = { 0 };
^
Expand Down Expand Up @@ -53,4 +39,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
constexpr S2 y[2] = {
^

9 errors detected in the compilation of "Test_name.c".
7 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++11 Test_name.c
"Test_name.c", line 48: error: no instance of constructor "Reorder::X::X" matches the argument list
foo n = {.y = 4, .x = 5};
^
"Test_name.c", line 37: note: number of parameters of function "Reorder::X::X(const Reorder::X &)" does not match the call
struct X {
^
"Test_name.c", line 37: note: number of parameters of function "Reorder::X::X(Reorder::X &&)" does not match the call
struct X {
^
"Test_name.c", line 38: note: number of parameters of function "Reorder::X::X(int)" does not match the call
X(int n);
^

"Test_name.c", line 48: warning: out-of-order initializers are nonstandard in C++
foo n = {.y = 4, .x = 5};
^
Expand Down Expand Up @@ -35,6 +48,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
S s1 = {
^

"Test_name.c", line 90: error: variable "Reorder3::s2" has an uninitialized const or reference member
S s2 = {
^

"Test_name.c", line 94: warning: out-of-order initializers are nonstandard in C++
.b = s3.a, .a = 1,
^
Expand All @@ -43,6 +60,20 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
S s3 = {
^

"Test_name.c", line 101: error: a class or namespace qualified name is required
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [1]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=1]" at line 119

"Test_name.c", line 101: error: expected a ";"
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [1]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=1]" at line 119

"Test_name.c", line 117: warning: out-of-order initializers are nonstandard in C++
.a = 1,
^
Expand All @@ -65,10 +96,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [2]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=2]" at line 124

"Test_name.c", line 127: warning: out-of-order initializers are nonstandard in C++
.a = 1
^

"Test_name.c", line 101: error: a class or namespace qualified name is required
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
Expand All @@ -83,14 +110,60 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [3]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=3]" at line 128

"Test_name.c", line 127: warning: out-of-order initializers are nonstandard in C++
.a = 1
^

"Test_name.c", line 101: error: a class or namespace qualified name is required
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [4]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=4]" at line 132

"Test_name.c", line 101: error: expected a ";"
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [4]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=4]" at line 132

"Test_name.c", line 135: warning: out-of-order initializers are nonstandard in C++
.a = 1,
^

"Test_name.c", line 101: error: a class or namespace qualified name is required
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [6]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=6]" at line 142

"Test_name.c", line 101: error: expected a ";"
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [6]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=6]" at line 142

"Test_name.c", line 141: warning: out-of-order initializers are nonstandard in C++
.e = {4, 4}
^

"Test_name.c", line 101: error: a class or namespace qualified name is required
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [7]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=7]" at line 148

"Test_name.c", line 101: error: expected a ";"
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
detected during:
instantiation of class "NoCheckingFilledHoles::Error<T> [with T=int [7]]" at line 105
instantiation of "NoCheckingFilledHoles::DefaultInitIsError<N>::DefaultInitIsError(NoCheckingFilledHoles::Error<int [N]>) [with N=7]" at line 148

"Test_name.c", line 101: error: a class or namespace qualified name is required
template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
^
Expand Down Expand Up @@ -119,4 +192,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "void Bar<T>::Test() [with T=bool]" at line 33

11 errors detected in the compilation of "Test_name.c".
21 errors detected in the compilation of "Test_name.c".
Loading
Loading