Fails with -Os, works with -O2: 4.5.3 Works always: 4.1.2 4.2.4 4.3.6 4.4.6 Fails always: 3.4.6 Only fails if the copy constructor is manually defined. Works with __attribute__((__pure__)) instead of __attribute__((__const__)). Still fails with printf and #include <stdio.h> removed. Maybe it's somehow illegal with __attribute__((__const__)) to return a structure with a manually defined copy constructor? Testcase, reduced as much as I could: /* $ g++ -O2 -o error error.cpp $ ./error (-11 1 4) $ g++ -Os -o error error.cpp $ ./error (1790250 1127603896 -1465067344) Aborted $ ./error (1801140 -1464045896 574146144) Aborted */ extern "C" void abort(); struct Vector3f { Vector3f() {} Vector3f(int x, int y, int z) : x(x), y(y), z(z) {} Vector3f(Vector3f const &v) : x(v.x), y(v.y), z(v.z) {} // Essential int x, y, z; }; __attribute__((__const__)) Vector3f pie_SurfaceNormal3fv(Vector3f a, Vector3f b) { return Vector3f(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } void normalsOnTile(Vector3f *normals) { Vector3f b(3, 5, 7); Vector3f c(4, 8, 9); *normals = pie_SurfaceNormal3fv(b, c); } #include <stdio.h> int main() { Vector3f normals; normalsOnTile(&normals); printf("(%d %d %d)\n", normals.x, normals.y, normals.z); if (normals.x != -11) abort(); }
With Debian's gcc 4.6.2-5 the testcase fails with -Os, -O1, -O2, ok with -O0, -O3, -Ofast. 4.5.3-9 fails with -Os, -O1, ok with -O0, -O2, -O3.
I can reproduce the error on i686-linux with g++ 4.7-20111203, 4.6-20111202, and 4.5-20111201 at -Os/-O1. Works at -O0/-O3, -O2 varies. 4.4-20111108 seems to work.
__attribute__((__const__)) Vector3f pie_SurfaceNormal3fv(Vector3f a, Vector3f b) { return Vector3f(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } I think it is illegal to use the const attribute when the C++ frontend may elide the return value copy to being passed by invisible reference. That way the middle-end sees a store to global memory which is a side-effect that the const attribute does not allow (similar for pure btw.). Note that the Vector3f() constructors are not const either but they are both called from pie_SurfaceNormal3fv.
Is there any case in which a function returning a structure may not elide the return value copy to being passed by invisible reference? If not, I think it is either a bug that the code fails, or a bug that the C++ frontend allows __attribute__((__const__)) on any function which returns a structure. It seems strange to me that __attribute__((__const__)) doesn't work in cases where constexpr does work, since I thought constexpr is a now-standard version of __attribute__((__const__)).