Bug 51392 - Wrong code with -Os when __attribute__((__const__)) function returns structure
Summary: Wrong code with -Os when __attribute__((__const__)) function returns structure
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.5.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-12-03 10:09 UTC by Cyp
Modified: 2016-10-16 09:52 UTC (History)
1 user (show)

See Also:
Host:
Target: x86_64-pc-linux-gnu
Build: gcc version 4.5.3 (Gentoo 4.5.3-r1 p1.0, pie-0.4.5)
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Cyp 2011-12-03 10:09:22 UTC
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();
}
Comment 1 cybersphinx 2011-12-03 16:27:09 UTC
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.
Comment 2 Mikael Pettersson 2011-12-04 14:04:06 UTC
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.
Comment 3 Richard Biener 2011-12-04 15:50:40 UTC
__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.
Comment 4 Cyp 2016-10-16 09:52:02 UTC
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__)).