Minimal app:
TestProject.pro:
QT += core gui widgets
CONFIG += C++11
QMAKE_CXXFLAGS_RELEASE -= -O
QMAKE_CXXFLAGS_RELEASE -= -O0
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE -= -Os
QMAKE_CXXFLAGS_RELEASE -= -Ofast
TARGET = TestProject
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
main.cpp:
#include <mainwindow.h>
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QObject>
#include <QStack>
class Other : public QObject
{
Q_OBJECT
public:
explicit Other(QObject* parent = 0);
virtual ~Other();
void test();
private:
QStack<int> myStack;
};
//--------------------------------------------------------------------------------------------------
#include <QMainWindow>
#include <QPushButton>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = 0);
virtual ~MainWindow();
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
Other::Other(QObject* parent) :
QObject(parent)
{}
Other::~Other()
{}
void Other::test() //warning on this line
{
myStack.pop(); //but not when this line is commented
}
//--------------------------------------------------------------------------------------------------
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent)
{
(new Other(this))->test();
}
MainWindow::~MainWindow()
{}
Compiling with g++ -O3 -Wall
gives this warning:
...TestProject/mainwindow.cpp:10: warning: assuming signed overflow does not occur when assuming that (X - c) <= X is always true [-Wstrict-overflow]
void Other::test() //warning on this line
^
Compiling with g++ -O2 -Wall
does not.
This question makes sense, as it's for a conditional, but I'm not getting it on a conditional. I'm getting it on a function itself.
I'd like to use the more aggressive optimization, but still compile cleanly if I can. Is there something weird going on with QStack
?
I still don't know what the warning is supposed to mean in this context, but I found a way to get rid of it.
I copied the code from qstack.h
and pasted it into my own function, then called it instead of the built-in QStack::pop()
:
void Other::pop() //warning on this line
{
Q_ASSERT(!myStack.isEmpty());
int t = myStack.data()[myStack.size() - 1];
myStack.resize(myStack.size() - 1);
return t;
}
Still have the warning, but it's moved to the custom pop()
function.
Then I played with it a bit and found that caching myStack.size() - 1
for the resize
operation kills the warning, but only if it's done before extracting the data()
:
void Other::pop() //no warning
{
Q_ASSERT(!myStack.isEmpty());
int size = myStack.size() - 1;
int t = myStack.data()[myStack.size() - 1];
myStack.resize(size);
return t;
}
Using the cached value for both operations is also warning-free.
So that's one of probably several ways to get rid of it, but does anyone know why it occurs here?
The warning is telling you that the compiler is not checking if the result of the substraction is negative or not.
Why this matters in this particular line?
myStack.data()[myStack.size() - 1];
Because you are indexing an array (actually using a pointer variable, coming from the data()
function, which returns a T*
) using the result of a substraction operation, which may result in a negative number, which is, typically, something you don't want.
When you take that substraction and move it to a new variable, then the compiler sees that you are indexing an array directly with an int
variable, and not the result of a substraction, so it does not warn anymore if the passed variable is negative or not.
About your comment, you are using the cached data for the resize
function. I am not really sure about why this happens, but I guess it may be related that, in -O3
the compiler enables the following flag:
-finline-functions
See http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for more details.
This flag enables all the inlining functions optimisation. Since you are using all templated classes, the compiler may be inlining all the involved functions, caching some results and somewhere is optimising the signed overflow. Probably in the if
sentence in the resize
function:
template <typename T>
void QVector<T>::resize(int asize)
{
int newAlloc;
const int oldAlloc = int(d->alloc);
QArrayData::AllocationOptions opt;
//Here, asize will be replaced with d->size - 1 after all the inlining.
//So the compiler is assuming that d->size - 1 will not overflow,
// because of undefined behaviour,
// instead of thinking that it may wrap.
if (asize > oldAlloc) {
newAlloc = asize;
opt = QArrayData::Grow;
} else {
newAlloc = oldAlloc;
}
reallocData(asize, newAlloc, opt);
}
But this is just a guess.