Created attachment 27156 [details] Preprocessed source [Component=middle-end was a guess, apologies if it's wrong.] The code below prints an infinite series of zeros, as if the iterator is never incremented. The problem goes away if: * the ternary expression is replaced by either tableA or tableB * 'flag' is set to true * the iterator increment is performed in a separate statement * the vector and iterators are replaced with an array and (int *) * tableA and tableB are replaced by vectors. If the result of the array indexing is actually used, e.g. printed to cerr, then results are the same at -O1 and above, but I see a segfault with -O0. ---------------------------------------------------------------- #include <iostream> #include <vector> int main (int argc, char *argv[]) { std::vector<int> v(1); int tableA[] = { 0 }; int tableB[] = { 0 }; bool flag = false; for (std::vector<int>::const_iterator it = v.begin(); it != v.end();) { (flag ? tableA : tableB)[*it++]; std::cerr << (it - v.begin()) << "\n"; } return 0; }
Confirmed. The gimplification looks bogus: if (flag != 0) goto <D.24453>; else goto <D.24454>; <D.24453>: D.24018 = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator++ (&it, 0); cleanup.1 = 1; D.24458 = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator* (&D.24018); D.24459 = *D.24458; goto <D.24460>; <D.24454>: D.24461 = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator* (&D.24018); D.24462 = *D.24461; <D.24460>: it is only incremented on one arm.
Another test case; this one doesn't need any headers and also cuts out the loop. The exit status should always be 1, but in fact it's 0 if no command-line args are supplied and 1 otherwise. ---------------------------------------------------------------- struct Counter { Counter (int val = 0) : m_val(val) {} int operator* () const { return m_val; } Counter operator++ (int) { return Counter(m_val++); } int m_val; }; int main (int argc, char *[]) { int a[] = {0}; int b[] = {0}; Counter c; ((argc > 1) ? a : b)[*c++]; return *c; }
same with gcc-8/9/?, works with clang
<<cleanup_point <<< Unknown tree: expr_stmt if (flag) { (void) tableA[(int) *__gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator* (&TARGET_EXPR <D.66535, __gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator++ (&it, 0)>)]; } else { (void) tableB[(int) *__gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator* (&TARGET_EXPR <D.66535, __gnu_cxx::__normal_iterator<const int*, std::vector<int> >::operator++ (&it, 0)>)]; } >>>>>; This is totally bogus. Basically we did: (flag ? tableA[*it++] : tableB[*it++]); But then only the *it++ in one of the branches because we only copied the tree and do a deap copy.