1
votes

Consider this program:

struct S {
    int m;
};

int main() {
    S s_arr[1]{0};
    S *s_new = new S[1]{0};
    int i_arr[1][1]{0};
    int (*i_new)[1] = new int[1][1]{0};
    return 0;
}

I think all four variables in the main function should be initialized using aggregate initialization.

However, GCC only accepts s_arr and i_arr, but rejects s_new and i_new, reporting (g++ 8.3.0 on Ubuntu):

test.cpp: In function ‘int main()’:
test.cpp:7:26: error: could not convert ‘0’ from ‘int’ to ‘S’
     S *s_new = new S[1]{0};
                          ^
test.cpp:9:38: error: array must be initialized with a brace-enclosed initializer
     int (*i_new)[1] = new int[1][1]{0};
                                      ^
test.cpp:9:38: error: array must be initialized with a brace-enclosed initializer

(note: the last duplicate line is produced by g++)

I also tested on godbolt, none of the gcc versions from 6.1 to 9.2 can compile this program. 6.x and 7.x versions also give the message saying: "sorry, unimplemented: cannot initialize multi-dimensional array with initializer" for i_new.

Changing {0} to {{0}} resolves both s_new and inew for all GCC versions tested on godbolt (6.1 to 9.2). I can understand this, as both S[1] and int[1][1] are both aggregate types whose element type is a sub-aggregate (array of S; array of array). However, C++ allows these braces to be elided, and GCC accepts s_arr and i_arr, where these braces are elided.

In the other hand, clang 6.0.0 to clang 9.0.0 accepts the original program happily.

In the specification of C++14 (gnu++14 is the default for GCC 6.5/7.4/8.3/9.2),

5.3.4 New / 17

A new-expression that creates an object of type T initializes that object as follows:

......

(17.2) — Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct initialization.

The new-initializer should be interpreted as direct-initialization. As s_arr and i_arr are also direct-initialized, I think they should be interpreted in the same way, and the original program should be well-formed.

Is there anything that I am missing here, or is this a bug in GCC?

I tried to search through GCC Bugzilla, but didn't find anything relevant.

1
{0} is often misleading, as it means "zero-initialize the first element and value-initialize the rest". It's better to just use {} or () to value-initialize the entire object (this will set it to 0). Incidentally that also compiles fine on gcc.rustyx

1 Answers

1
votes

Yes, this is definitely a bug. new expressions are defined to use the rules for direct-initialization ([expr.new]/18.2), and brace elision applies to all cases of aggregate initialization ([dcl.init.aggr]/12).

File a bug if you can't find one after searching through the bugzilla.