Created attachment 27502 [details] preprocessed source for failed compile g++-4.7 -std=c++11 1.cpp -o e1 1.cpp: #include <iostream> #include <utility> #include <array> using namespace std; array<pair<string, unsigned> const, 1> const matchSynonyms{ {"smile",1} }; int main(int argc, char **argv){ cout<<"success"<<endl; } leads to output: " ‘ /home/mako/programming/cing/1.cpp:6: confused by earlier errors, bailing out Preprocessed source stored into /tmp/ccTX9zYB.out file, please attach this to your bugreport. " I also get problems when I try to use a vector instead of a pair, but the errors are a lot longer and confusing and it's harder to rule out user error.
In any case a good workaround is using matchSynonyms{{ {"smile",1} }}
#include <array> #include <utility> using std::array; using std::pair; struct string { string(const char*) { } }; array<pair<string, unsigned> const, 1> const matchSynonyms{ {"smile",1} };
further reduced #include <utility> using std::pair; template<typename T> struct array { typedef T value_type; value_type data[1]; }; struct string { string(const char*) { } }; array<pair<string, unsigned> const> const matchSynonyms{ {"smile",1} }; 4.6 correctly rejects it: a.cc:16:70: error: too many initializers for 'array<const std::pair<string, unsigned int> >::value_type [1] {aka const std::pair<string, unsigned int> [1]}' a.cc:16:70: error: could not convert '(const char*)"smile"' from 'const char*' to 'array<const std::pair<string, unsigned int> >::value_type {aka const std::pair<string, unsigned int>}' 4.7 gives: ' a.cc:16: confused by earlier errors, bailing out and 4.8 gives: ' in strip_typedefs, at cp/tree.c:1196 array<pair<string, unsigned> const> const matchSynonyms{ {"smile",1} }; ^ Please submit a full bug report, with preprocessed source if appropriate. See <http://gcc.gnu.org/bugs.html> for instructions.
And since it's actually invalid should be pretty easy to fix, the ICE is happening in a gcc_assert where alignment is handled, nothing to do.
Would someone please explain to me why that compile error is considered correct? It tells me nothing sensible.
Who said correct?!?
Uh, Johnathan said "4.6 correctly rejects it:", however 4.6's rejection message appears every bit as useless as 4.7's, perhaps more so, because it misattributes the error. If that's the correct way to reject it... Compiler logic is beyond me.
"correctly rejects it" in general means "per the ISO C++ Standard, which we are implementing, the testcase is invalid with diagnostics required, thus the compiler is right in rejecting it", thus it doesn't have anything to do with providing a better, more informative, error message. Just to clarify. And indeed, I think Jon's analysis is correct. Maybe Daniel has something to add.
4.6 gets the error right, what you're doing is equivalent to: struct pair { pair(const char*, int) { } }; struct array { pair data[1]; }; array a { { "smile", 1 } }; And that isn't valid. The error 4.6 gives for that is: t.cc:11:26: error: too many initializers for 'pair [1]' t.cc:11:26: error: could not convert '(const char*)"smile"' from 'const char*' to 'pair' Which is very similar to the error 4.6 gives for your original code, except he types in your original are more complicated because they involve templates and typedefs.
The code: array a { { "smile", 1 } }; Attempts to initialize array with { { "smile", 1 } } which attempts to initialize pair[2] with { "smile", 1 } which fairly obviously attemptes to initialize the first pair with "smile", and the second pair with 1, neither of which is valid. Why do you think the error is misattributed?
I will look into the ICE. Not immediately, however.
With checking disabled the error message comes out fine, thus the issue isn't really urgent.
Am I interpreting correctly that double braces are /required/ for std::array init lists but only when the subtype has has a multivariable initializer too? ..????
(In reply to comment #13) > Am I interpreting correctly that double braces are /required/ for std::array > init lists but only when the subtype has has a multivariable initializer too? I must agree that the compiler behaviour does not look correct to me. Initially I thought that the reason is due to the fact, that brace-elision does not apply here, but then I noticed that this code does not compile either: struct pair { pair(const char*, int) { } }; struct array_p { pair data[1]; }; array_p a = { { "smile", 1 } }; Here we have definitively brace elision in action, but I get the same error as from Jonathan's example. My impression is that the compiler incorrectly does not see the brace-elision case here. Here is an example that works (with an expected [-Wmissing-braces] warning): struct string { string(const char*) { } }; struct array_s { string data[1]; }; array_s b{ "smile" }; From this I see that gcc already implements http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1270 so I must conclude that the compiler should also accept the original example.
Thanks Daniel. Let's see if Jon agrees with your analysis. To be honest, at first, when I figured out the workaround, it seemed a brace-elision issue to me too, but then I haven't been able to spend enough time on the details of the issue, unfortunately.
(In reply to comment #14) > struct pair > { > pair(const char*, int) { } > }; > > struct array_p > { > pair data[1]; > }; > > array_p a = { { "smile", 1 } }; > > Here we have definitively brace elision in action, but I get the same error as > from Jonathan's example. "If the initializer-list begins with a left brace," which it does "then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate;" I read that to mean that { "smile", 1 } initializes the pair[1] "it is erroneous for there to be more initializer-clauses than members." There is only one member of pair[1] but two initializer-clauses. So I think the error is required, but Daniel is usually right about such things so I'm not certain :)
clang version 3.2 (trunk 155804) also rejects it: t.cc:11:18: error: no viable conversion from 'const char [6]' to 'pair'
(In reply to comment #16) > "If the initializer-list begins with a left brace," > > which it does > > "then the succeeding comma-separated list of initializer-clauses initializes > the members of a subaggregate;" > > I read that to mean that { "smile", 1 } initializes the pair[1] > > "it is erroneous for there to be more initializer-clauses than members." > > There is only one member of pair[1] but two initializer-clauses. > > So I think the error is required, but Daniel is usually right about such things > so I'm not certain :) Thanks Jon. I agree with you, the wording seems clear. This looks like a very unfortunate language rule, because it leads to an inconsistency (from the user-point), when comparing this with non-aggregate list-initialization as in the following case: std::initializer_list<std::pair<std::string, unsigned>> lp = { {"a", 1} }; which is well-formed. I would like to withdraw my concerns expressed in comment 14 so that there is no hindrance to close this issue - anything else seems to belong to a discussion at another place.
(In reply to comment #13) > Am I interpreting correctly that double braces are /required/ for std::array > init lists but only when the subtype has has a multivariable initializer too? > > ..???? Yes. Double braces are always correct and always allowed, but you can omit them if the result is unambiguous, e.g. array<int,3>{1,2,3} is equivalent to array<int,3>{{1,2,3}} But if the array's value_type is to be initialized with a braced-initializer-list then you need a completely-braced initialization so that the initializer-list for the value_type doesn't get interpreted as an initializer for the value_type[N] array. It still shouldn't crash the compiler though :)
Good, good, then let me fix the ICE.
No includes: template<typename T, typename U> struct pair { T first; U second; pair(const T&, const U&); }; template<typename T> struct array { typedef T value_type; value_type data[1]; }; struct string { string(const char*) { } }; array<pair<string, unsigned> const> const matchSynonyms{ {"smile",1} };
A tad simpler: template<typename T, typename U> struct pair { T first; U second; pair(const T&, const U&); }; template<typename T> struct array { typedef T value_type; value_type data[1]; }; array<pair<int, int> const> matchSynonyms{ { 1, 1 } };
GCC 4.7.1 is being released, adjusting target milestone.
Jon, can you help me double checking mainline? Apparently something changed and I can't reproduce the ICE anymore.
Fixed by the patch which fixed c++/53989.