Bug 90617 - GCC 9 miscompiles Qt4 "foreach" macro
Summary: GCC 9 miscompiles Qt4 "foreach" macro
Status: RESOLVED DUPLICATE of bug 44715
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 98345 (view as bug list)
Depends on:
Blocks:
 
Reported: 2019-05-24 15:25 UTC by bastian.beischer
Modified: 2020-12-17 13:28 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
preprocessed qt4.C source. (132.29 KB, text/plain)
2019-05-24 15:25 UTC, bastian.beischer
Details

Note You need to log in before you can comment on or make changes to this bug.
Description bastian.beischer 2019-05-24 15:25:45 UTC
Created attachment 46410 [details]
preprocessed qt4.C source.

The following piece of code, which uses Qt 4.8.7:

#include <QList>
#include <iostream>

int main(int argc, char** argv) {
  QList<int> list;
  list.append(1);
  list.append(2);
  list.append(3);
  foreach(int x, list) {
    std::cout << x << std::endl;
  }

  return 0;
}

Compiled with gcc 9.1.0 like this:

$ g++ -I/usr/include/qt4 -I/usr/include/qt4/QtCore -lQtCore -o qt4 qt4.C

does not execute the "foreach" loop correctly.

$ ./qt4
1

Only the first list element is printed. This is a regression with respect to GCC 8.3.0:

$ g++-8 -I/usr/include/qt4 -I/usr/include/qt4/QtCore -lQtCore -o qt4 qt4.C
$ ./qt4
1
2
3

The preprocessed sources of qt4.C are attached as 'qt4.i'.

I managed to construct a reproducer (based on the Qt foreach macro) which is short and does not use Qt:

#include <iostream>
#include <vector>

template <typename T>
class ForeachContainer {
public:
  inline ForeachContainer(const T& t)
    : c(t)
    , brk(0)
    , i(c.begin())
    , e(c.end()) {
  }

  const T c;
  int brk;
  typename T::const_iterator i, e;
};

int main() {
  std::vector<int> v;
  v.push_back(0);
  v.push_back(1);
  v.push_back(2);

  for (ForeachContainer<std::vector<int>> _container_(v);
       !_container_.brk && _container_.i != _container_.e;
       __extension__ ({ ++_container_.brk; ++_container_.i; })) {

    for (int x = *_container_.i;
         ;
         __extension__ ({--_container_.brk; break;})) {

      std::cout << "x = " << x << std::endl;
    }
  }

  return 0;
}

$ g++ -g -o mini9 mini.C
$ ./mini9
x = 0

$ g++-8 -g -o mini8 mini.C
$ ./mini8
x = 0
x = 1
x = 2

Admittedly, the code is ugly, but that's what is in Qt 4.8.7.
Comment 1 Andrew Pinski 2019-05-24 15:29:50 UTC
>  for (int x = *_container_.i;
>         ;
>         __extension__ ({--_container_.brk; break;})) {
>
>      std::cout << "x = " << x << std::endl;
>    }


Hmmm,  the question here becomes where is that break should be breaking on; the inner most for loop or the outer one?  Before GCC 9, it was the inner one but in GCC 9 (and above) it is the outer most one.
Comment 2 Andreas Schwab 2019-05-24 16:13:37 UTC
According to [stmt.for] the expression is supposed to be evaluated in the scope of the inner loop.
Comment 3 Richard Biener 2019-05-27 07:42:04 UTC
There's a duplicate (closed as INVALID) and upstream is aware of this and fixes are out in the wild.
Comment 5 Andrew Pinski 2019-05-27 17:33:41 UTC
So mark as a dup of bug 44715.

*** This bug has been marked as a duplicate of bug 44715 ***
Comment 6 Jakub Jelinek 2020-12-17 13:28:14 UTC
*** Bug 98345 has been marked as a duplicate of this bug. ***