Bug 1833 - Temporary rvalue (result of cast) can be illegally bound to non-const reference
Summary: Temporary rvalue (result of cast) can be illegally bound to non-const reference
Status: RESOLVED DUPLICATE of bug 1920
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 2.95.2
: P3 normal
Target Milestone: 3.4.0
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 11374 (view as bug list)
Depends on:
Blocks:
 
Reported: 2001-02-01 11:26 UTC by peteb
Modified: 2003-07-24 04:05 UTC (History)
9 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2003-05-03 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description peteb 2001-02-01 11:26:00 UTC
The attached program calls two versions of a function,
one inlined and the other not. The inlined function does
not behave correctly. The type casting of a (char *)
argument to (const char *) as an argument to another funtion
that takes (const char *&) does not properly modify the
argument in the calling function in the inlined version.

Release:
2.94 -> 3.4

How-To-Repeat:
#include <iostream>


void frob2 (const char*& s)
{
  s += 3;
}


inline void frob_fail (char *s)
{
  frob2((const char *)s);

  cerr << "should be 34567: " << s << endl;
}


void frob_pass (char *s)
{
  frob2((const char *)s);

  cerr << "should be 34567: " << s << endl;
}


int main (unsigned argc, const char *const argv[])
{
  char *x = "01234567";
  frob_fail(x);

  char *y = "01234567";
  frob_pass(y);
}
Comment 1 Alexandre Oliva 2001-03-02 02:26:28 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: There is indeed a bug.  The problem is that the result of the cast is an rvalue, because the cast-to type is not a reference type.  Therefore, a temporary should be created.  However, a temporary cannot be bound to a non-const reference, but g++ happily binds it to frob2's argument, even with -ansi -pedantic.
    Even if the binding-to-non-const were to be done as an extension, it still shouldn't modify variable s; it should modify the temporary, then discard it.
    WRT the difference between the inline and the non-inline functions, the problem is likely to be in the tree level, because the initial RTL dump is already significantly different for the two functions.
Comment 2 Alexandre Oliva 2001-03-02 10:26:28 UTC
From: aoliva@gcc.gnu.org
To: gcc-gnats@gcc.gnu.org, nobody@gcc.gnu.org, peteb@sitera.com
Cc:  
Subject: Re: c++/1833
Date: 2 Mar 2001 10:26:28 -0000

 Synopsis: inlining sometimes causes incorrect behavior
 
 State-Changed-From-To: open->analyzed
 State-Changed-By: aoliva
 State-Changed-When: Fri Mar  2 02:26:28 2001
 State-Changed-Why:
     There is indeed a bug.  The problem is that the result of the cast is an rvalue, because the cast-to type is not a reference type.  Therefore, a temporary should be created.  However, a temporary cannot be bound to a non-const reference, but g++ happily binds it to frob2's argument, even with -ansi -pedantic.
     Even if the binding-to-non-const were to be done as an extension, it still shouldn't modify variable s; it should modify the temporary, then discard it.
     WRT the difference between the inline and the non-inline functions, the problem is likely to be in the tree level, because the initial RTL dump is already significantly different for the two functions.
 
 http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view&pr=1833&database=gcc

Comment 3 Wolfgang Bangerth 2002-10-30 19:27:24 UTC
From: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
To: gcc-bugs@gcc.gnu.org, <gcc-gnats@gcc.gnu.org>
Cc:  
Subject: Re: c++/1833: inlining sometimes causes incorrect behavior
Date: Wed, 30 Oct 2002 19:27:24 -0600 (CST)

 I can confirm this also with newer gcc's, and this indeed very surprising. 
 Here's the thing:
 -----------------------------------
 #include <iostream>
 using namespace std;
 
 typedef char *pchar;
 
 void advance_by_3 (pchar &s) { s += 3; }
 
 inline void frob_fail (char *s) {
   advance_by_3((pchar)s);
   cerr << "should be 34567: " << s << endl;
 }
 
 void frob_pass (char *s) {
   advance_by_3((pchar)s);
   cerr << "should be 34567: " << s << endl;
 }
 
 int main () {
   char *x = "01234567";  frob_fail(x);
   char *y = "01234567";  frob_pass(y);
 }
 -----------------------------------
 and I get:
   tmp/g> /home/bangerth/bin/gcc-3.2.1-pre/bin/c++ -O2 x.cc
   tmp/g> ./a.out
   should be 34567: 01234567
   should be 34567: 01234567
 
   tmp/g> /home/bangerth/bin/gcc-3.2.1-pre/bin/c++ x.cc
   tmp/g> ./a.out
   should be 34567: 34567
   should be 34567: 34567
 
 With present CVS I get the first results also for -O0. For 2.95, I get the 
 wrong result only for the _inlined_ function, where I now get it 
 uniformly.
 
 The problem is rather surreal, since touching it somewhere makes it go 
 away. For example, removing the (pchar) casts in the call to advance_by_3 
 make a difference, although the variable is already a char*.
 
 Regards
   Wolfgang
 
 -------------------------------------------------------------------------
 Wolfgang Bangerth              email:           bangerth@ticam.utexas.edu
                                www: http://www.ticam.utexas.edu/~bangerth
 
 

Comment 4 Wolfgang Bangerth 2002-11-14 14:35:19 UTC
From: Wolfgang Bangerth <bangerth@apex68.ticam.utexas.edu>
To: gcc-gnats@gcc.gnu.org
Cc:  
Subject: c++/1833: inlining sometimes causes incorrect behavior
Date: Thu, 14 Nov 2002 14:35:19 -0600

 Re-confirmed with 3.3 CVS from 2002-11-10 and 3.2.1 pre from the same date.

Comment 5 Wolfgang Bangerth 2003-04-03 11:31:58 UTC
From: Wolfgang Bangerth <bangerth@ices.utexas.edu>
To: gcc-gnats@gcc.gnu.org, <nigels@nigels.com>
Cc:  
Subject: Re: c++/1833
Date: Thu, 3 Apr 2003 11:31:58 -0600 (CST)

 Nigel,
 the problem you sent has nothing to do with the problem described in PR 
 1833. You are violating aliasing rules. The code in the report is legal, 
 yours is not.
 
 W.
 
 -------------------------------------------------------------------------
 Wolfgang Bangerth              email:            bangerth@ices.utexas.edu
                                www: http://www.ices.utexas.edu/~bangerth/
 
 

Comment 6 nigels 2003-04-04 03:24:48 UTC
From: Nigel Stewart <nigels@nigels.com>
To: gcc-gnats@gcc.gnu.org,  gcc-bugs@gcc.gnu.org,  nobody@gcc.gnu.org, 
 gcc-prs@gcc.gnu.org,  peteb@sitera.com
Cc:  
Subject: Re: c++/1833: [2003-01-01] inlining sometimes causes incorrect behavior
Date: Fri, 04 Apr 2003 03:24:48 +1000

 http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=1833
 
 Perhaps the bug/problem/issue I've found in gcc is related to this one
 already in the database: Problem Report 1833
 
 -------
 
 #include <iostream>
 using namespace std;
 
 float foo()
 {
 	assert(sizeof(unsigned int)==sizeof(float));
 	
 	float tmp = 0.0;
 	*((unsigned int *) &tmp) = (127<<23) | (1<<22);
 	
 	return tmp;
 }
 
 int main(int argc,char *argv[])
 {
 	cout << "Output should be 1.5: " << foo() << endl;
 }
 
 -------
 
 $ gcc -v
 Reading specs from /usr/lib/gcc-lib/i686-pc-cygwin/3.2/specs
 Configured with: /netrel/src/gcc-3.2-3/configure --enable-languages=c,c++,f77,java --enable-libgcj --enable-threads=posix --with-system-zlib --enable-nls --without-included-gettext --enable-interpreter --disable-sjlj-exceptions --disable-version-specific-runtime-libs --enable-shared --build=i686-pc-linux --host=i686-pc-cygwin --target=i686-pc-cygwin --enable-haifa --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --includedir=/nonexistent/include --libexecdir=/usr/sbin
 Thread model: posix
 gcc version 3.2 20020927 (prerelease)
 
 $ g++ test.cpp -o test && ./test
 Output should be 1.5: 1.5
 
 $ g++ -O2 test.cpp -o test && ./test
 Output should be 1.5: 0
 
 --------
 
 The following version of foo does not exhibit the same problem:
 
 float foo()
 {
 	assert(sizeof(unsigned int)==sizeof(float));
 
 	unsigned int tmp = (127<<23) | (1<<22);
 	return *((float *) &tmp);
 }
 
 Regards,
 
 Nigel Stewart
 nigels@nigels.com
 

Comment 7 nigels 2003-04-04 12:58:54 UTC
From: Nigel Stewart <nigels@nigels.com>
To: Wolfgang Bangerth <bangerth@ices.utexas.edu>
Cc: gcc-gnats@gcc.gnu.org
Subject: Re: c++/1833
Date: Fri, 04 Apr 2003 12:58:54 +1000

 Wolfgang,
 
 Heeding your advice about aliasing rules, I've replaced
 the cast with a union.  Problem is solved.  However, I
 would suggest that gcc should provide warnings or errors
 in the case of being fed illegal code.
 
 float foo()
 {
 	assert(sizeof(unsigned int)==sizeof(float));
 	union { float f; unsigned int i; } tmp;
 	tmp.i = (127<<23) | (1<<22);
 	return tmp.f;
 }
 
 Thanks for your response, and my apologies for cluttering
 the bug database...
 
 N Stewart
 
 > Nigel,
 > the problem you sent has nothing to do with the problem described in PR 
 > 1833. You are violating aliasing rules. The code in the report is legal, 
 > yours is not.
 > 
 > W.
 

Comment 8 Wolfgang Bangerth 2003-05-08 18:38:11 UTC
From: Wolfgang Bangerth <bangerth@ices.utexas.edu>
To: gcc-gnats@gcc.gnu.org, Giovanni Bajo <giovannibajo@libero.it>
Cc:  
Subject: Re: c++/1833
Date: Thu, 8 May 2003 18:38:11 -0500 (CDT)

 This is a gcc extension: cast-as-lvalue. I personally think it's an evil 
 one.
 
 Binding it to a reference yields all sorts of problems. I closed several 
 duplicates of some such bug recently. Giovanni, check 1920 and 7884, 
 possibly also 7503.
 
 W.
 
 -------------------------------------------------------------------------
 Wolfgang Bangerth              email:            bangerth@ices.utexas.edu
                                www: http://www.ices.utexas.edu/~bangerth/
 
 

Comment 9 Giovanni Bajo 2003-05-09 01:17:04 UTC
From: "Giovanni Bajo" <giovannibajo@libero.it>
To: <gcc-gnats@gcc.gnu.org>,
	<gcc-bugs@gcc.gnu.org>,
	<nobody@gcc.gnu.org>,
	<gcc-prs@gcc.gnu.org>,
	<peteb@sitera.com>
Cc:  
Subject: Re: c++/1833: [2003-01-01] inlining sometimes causes incorrect behavior
Date: Fri, 9 May 2003 01:17:04 +0200

 http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=1833
 
 Given Alexander's analysys, which I confirm, this PR boils down to the
 following code:
 
 --------------------------------
 typedef char *pchar;
 
 void func(pchar &s)
 {}
 
 int main ()
 {
     char *s = "123";
     func((pchar)s);
 }
 --------------------------------
 
 which is illegal, because the cast creates a temporary rvalue which cannot
 be bound to a non-const reference. But GCC compiles it happily even
 with -ansi -pedantic. So it's an accept-illegal.
 
 Giovanni Bajo
 

Comment 10 Gabriel Dos Reis 2003-05-09 09:05:35 UTC
From: Gabriel Dos Reis <gdr@integrable-solutions.net>
To: Wolfgang Bangerth <bangerth@ices.utexas.edu>
Cc: gcc-gnats@gcc.gnu.org
Subject: Re: c++/1833
Date: 09 May 2003 09:05:35 +0200

 Wolfgang Bangerth <bangerth@ices.utexas.edu> writes:
 
 | The following reply was made to PR c++/1833; it has been noted by GNATS.
 | 
 | From: Wolfgang Bangerth <bangerth@ices.utexas.edu>
 | To: gcc-gnats@gcc.gnu.org, Giovanni Bajo <giovannibajo@libero.it>
 | Cc:  
 | Subject: Re: c++/1833
 | Date: Thu, 8 May 2003 18:38:11 -0500 (CDT)
 | 
 |  This is a gcc extension: cast-as-lvalue. I personally think it's an evil 
 |  one.
 
 It should be removed.
 
 -- Gaby
Comment 11 Andrew Pinski 2003-06-30 01:28:40 UTC
*** Bug 11374 has been marked as a duplicate of this bug. ***
Comment 12 Andrew Pinski 2003-07-24 04:05:18 UTC
This is a dup of bug 1920 which is the meta-bug for cast-as-lvalue extension in c++..

*** This bug has been marked as a duplicate of 1920 ***