Home » C++ » Different results between gcc and clang when compiling a rather simple c++11 program

Different results between gcc and clang when compiling a rather simple c++11 program

Posted by: admin November 30, 2017 Leave a comment

Questions:

I’m trying to understand whether the different behavior exposed by gcc vs. clang in the output of this simple C++11 program is due to a bug in clang (Xcode 5.0.2, OS X 10.8.5). The code is as follows:

#include <iostream>

int main() {


    int matrix[][3]{{1,2,3}, {4,5,6}, {7,8,9}};
    auto dyn_matrix = new int[3][3]{{1,2,3}, {4,5,6}, {7,8,9}};

    std::cout << matrix[0][1] << std::endl;
    std::cout << dyn_matrix[0][1] << std::endl;

    return 0;   
}

As shown, I’m trying to use uniform initialization to initialize an anonymous (resp. named) multidimensional array of size 3x3. When compiling with gcc 4.7 from MacPorts the expected output is obtained:

$g++-mp-4.7 -std=c++11 dyn_matrix.cpp -o dyn_matrix 
$ ./dyn_matrix
2
2
$

Conversely, in case clang is used the output reads:

$ clang++ -std=c++11 -stdlib=libc++ dyn_matrix.cpp -o dyn_matrix_clang
$ ./dyn_matrix_clang 
2
4
$  

In this case the result is (apparently) wrong. clang --version reports:

Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix

Who’s to blame? me, gcc or clang?

UPDATE Dec 11th, 2013: The bug should have been fixed in r196995. Unfortunately, we still do not know how long it will take before Apple updates the version of clang that ships with Xcode.

UPDATE Dec 9th, 2013: I submitted a bug report on the LLVM bugzilla platform. It has indeed been recognized as a bug, a patch is currently under review, see http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/095099.html.

Thanks.

Answers:

Update: Thanks to Faisal Vali and Richard Smith, this bug has been corrected in Clang ToT; see the test file introduced by the commit.


According to §8.5.1 [dcl.init.aggr] it appears that Clang is wrong:

11/ Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member. [ Example:

float y[4][3] = {
    { 1, 3, 5 },
    { 2, 4, 6 },
    { 3, 5, 7 },
};

is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array y[0], namely y[0][0], y[0][1], and y[0][2]. Likewise the next two lines initialize y[1] and y[2]. The initializer ends early and therefore y[3]s elements are initialized as if explicitly initialized with an expression of the form float(), that is, are initialized with 0.0. In the following example, braces in the initializer-list are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the above example,

float y[4][3] = {
    1, 3, 5, 2, 4, 6, 3, 5, 7
};

The initializer for y begins with a left brace, but the one for y[0] does not, therefore three elements from the list are used. Likewise the next three are taken successively for y[1] and y[2]. —end example ]

Which I think applies because of §5.3.4 [expr.new]:

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

  • If the new-initializer is omitted, the object is default-initialized (§8.5); if no initialization is performed, the object has indeterminate value.
  • Otherwise, the new-initializer is interpreted according to the initialization rules of §8.5 for direct initialization.