[gnu.gcc.bug] GCC's structure-returning convention botches overlapping structures

eggert@twinsun.com (Paul Eggert) (10/14/89)

GCC's structure-returning convention doesn't work if the structure being
returned was copied from a source that overlaps the destination that the
returned value will be assigned to.  I'm reluctant to report this bug because:

	Fixing the bug will probably slow down the code GCC generates.

	The bug is rare in real programs.

	The proposed ANSI standard is not completely clear.  I think the
	standard should change here to agree with GCC, to avoid needless
	copying code in structure-returning function calls.

However, GCC doesn't behave properly for the program below.  Any of the
following actions makes the program behave properly:

	1.  Use -fpcc-struct-return on the Sun-3. (On the Sun-4, the bug
	persists even with -fpcc-struct-return.)

	2.  Use Sun's C compiler (either Sun-3 or Sun-4) instead of GCC.

	3.  Replace ``return *p;'' in the program below with

		{ struct s temp = *p;  return temp; }

	This statement is equivalent to ``return *p;'' because functions yield
	values, not lvalues, and copying a value does not affect the value.

In the program below, the statement ``*p = indirection(q);'' should yield a
copy of *q, and assign the copy to *p correctly even though *p and *q overlap.
Clearly the statement ``*p = *q;'' would violate the overlap restriction of
pANS 3.3.16.1.  But because of the implicit copy, ``*p = indirection(q);'' does
not violate the overlap restriction.

	struct s { int i, j, k, l; };

		struct s
	indirection(q)
		struct s *q;
	{
		return *q;
	}

		void
	copycheck(p, q)
		struct s *p, *q;
	{
		q->i = 1;  q->j = 2;  q->k = 3;  q->l = 4; 
		*p = indirection(q);
		printf(
			"%d, %d, %d, %d should be 1, 2, 3, 4\n",
			p->i, p->j, p->k, p->l
		);
	}

	union {
		struct { struct s s; int t; } s1;
		struct { int t; struct s s; } s2;
	} u;

		int
	main()
	{
		copycheck(&u.s1.s, &u.s2.s);
		copycheck(&u.s2.s, &u.s1.s);
		return 0;
	}

The following transcript shows GCC 1.36 (Sun-3/260, SunOS 4.0.3), improperly
behaves as though the overlap restriction is violated.

	13-burns% gcc -v u.c
	gcc version 1.36
	 /local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -Dmc68020 u.c /usr/tmp/cca04256.cpp
	GNU CPP version 1.36
	 /local/lib/gcc-cc1 /usr/tmp/cca04256.cpp -quiet -dumpbase u.c -version -o /usr/tmp/cca04256.s
	GNU C version 1.36 (68k, MIT syntax) compiled by GNU C version 1.36.
	default target switches: -m68020 -mc68020 -mbitfield
	 /local/lib/gcc-as -mc68020 -o u.o /usr/tmp/cca04256.s
	 ld -e start -dc -dp /lib/crt0.o /lib/Fcrt1.o u.o /local/lib/gcc-gnulib -lc
	14-burns% ./a.out
	1, 2, 3, 4 should be 1, 2, 3, 4
	1, 1, 1, 1 should be 1, 2, 3, 4

On a Sparcstation-1 (SunOS 4.0.3c), the output is wrong in a different way,
because the structure is copied in reverse order.

	40-rise% gcc -v u.c
	gcc version 1.36
	 /local/lib/gcc-cpp -v -undef -D__GNUC__ -Dsparc -Dsun -Dunix -D__sparc__ -D__sun__ -D__unix__ u.c /usr/tmp/cca01886.cpp
	GNU CPP version 1.36
	 /local/lib/gcc-cc1 /usr/tmp/cca01886.cpp -quiet -dumpbase u.c -version -o /usr/tmp/cca01886.s
	GNU C version 1.36 (sparc) compiled by GNU C version 1.36.
	default target switches: -mfpu -mepilogue
	 as -o u.o /usr/tmp/cca01886.s
	 ld -e start -dc -dp /lib/crt0.o u.o /local/lib/gcc-gnulib -lc
	41-rise% ./a.out
	4, 4, 4, 4 should be 1, 2, 3, 4
	1, 2, 3, 4 should be 1, 2, 3, 4