public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/31652]  New: postfix increment semantics implemented incorrectly
@ 2007-04-21 22:39 gcc-bugzilla at gcc dot gnu dot org
  2007-04-21 22:49 ` [Bug c++/31652] " pinskia at gcc dot gnu dot org
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: gcc-bugzilla at gcc dot gnu dot org @ 2007-04-21 22:39 UTC (permalink / raw)
  To: gcc-bugs


g++ parses the code correctly and calls the correct overloaded
increment operators, but in the wrong postfix order.  The semantics of
postfix are to take the rvalue before invoking the method.  Note this
is not related to multiple reference ordering between sequence points
as the object is only referenced once.  Although I have not checked
postfix decrement, it may have the same semantic problem and it is
trivial to adapt the supplied code.

Environment:
System: Linux dbox 2.6.18-3-686 #1 SMP Sun Dec 10 19:37:06 UTC 2006 i686
GNU/Linux
Architecture: i686


host: i486-pc-linux-gnu
build: i486-pc-linux-gnu
target: i486-pc-linux-gnu
configured with: ../src/configure -v
--enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-mpfr --with-tune=i686
--enable-checking=release i486-linux-gnu

How-To-Repeat:
cat > a.cpp
#include <iostream>

class C
{
public:
  int v;

  C( int v ) : v( v ) {}

  C & operator++( void ) { v++;      return *this; }
  C & operator++( int )  { v += 100; return *this; }
};

main()
{
  C a( 0 );
  C b( 0 );

  std::cout << "a:" << a.v << std::endl;  // 0
  std::cout << "b:" << b.v << std::endl;  // 0

  b = ++a;

  std::cout << "a:" << a.v << std::endl;  // 1
  std::cout << "b:" << b.v << std::endl;  // 1

  b = a++;

  std::cout << "a:" << a.v << std::endl;  // 101
  std::cout << "b:" << b.v << std::endl;  // should be 1, not 101!
}
^D
> g++ a.cpp ; ./a.out
a:0
b:0
a:1
b:1
a:101
b:101


------- Comment #1 from hayward at loup dot net  2007-04-21 23:39 -------
Fix:
Execute postfix methods *after* evaluating the expression they are in.


-- 
           Summary: postfix increment semantics implemented incorrectly
           Product: gcc
           Version: 4.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: hayward at loup dot net
 GCC build triplet: i486-pc-linux-gnu
  GCC host triplet: i486-pc-linux-gnu
GCC target triplet: i486-pc-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
@ 2007-04-21 22:49 ` pinskia at gcc dot gnu dot org
  2007-04-22  5:40 ` hayward at loup dot net
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: pinskia at gcc dot gnu dot org @ 2007-04-21 22:49 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #2 from pinskia at gcc dot gnu dot org  2007-04-21 23:49 -------
This is not a bug in GCC but instead a bug in your post fix increment operator:
  C & operator++( int )  { v += 100; return *this; }

Really should be implemented as:
  C operator++( int )  { C tmp = *this; v += 100; return tmp; }

Which is the correct way of implementing it.  postfix increment returns a
rvalue and not a lvalue. See example in the C++ standard in 13.5.7/1. 
Basically you just changed the semantics of post fix increment with the
operator overloader and changed it to be about the same as the pre incrementor
except incrementing by 100 instead of by 1.

Again this is not a bug in GCC but instead a bug in your code.

b = a++; is the same as doing:
b = a.operator++(0);

So if your operator++(int) returns *this, the result you are seeing is exactly
what is expected from the C++ standards point of view.


-- 

pinskia at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|                            |INVALID


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
  2007-04-21 22:49 ` [Bug c++/31652] " pinskia at gcc dot gnu dot org
@ 2007-04-22  5:40 ` hayward at loup dot net
  2007-04-22  6:04 ` pinskia at gcc dot gnu dot org
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: hayward at loup dot net @ 2007-04-22  5:40 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #3 from hayward at loup dot net  2007-04-22 06:40 -------
Subject: Re:  postfix increment semantics implemented incorrectly

Thanks for the quick response.  I do not, however, agree with this
interpretation of ISO/IEC FDIS 14882:1998(E) 13.5.7/1.

The spec trivially exemplifies the equivalance of the method syntax
and the postfix operator, but it mentions no explicit deviation from
post rvalue execution semantics.  Although it doesn't give a return by
reference example, nor does it provide a return by value definition in
it's example.  The spec does not mention anything about the postfix
increment and decrement methods being limited to providing post op
semantics for return by value and only if a copy constructor is
explicitly invoked at that.

Using a copy constructor and returning by value is of limited
applicability.  Having to invoke a copy constructor to "simulate" a
post rvalue operation is not an option for objects that do not support
copy, and perhaps more significantly for large objects, is both very
time inefficient and could blow stack.

I'm certain the language designers are aware of return by reference as
well as the costs and limitations of copy constructors and expect they
would be explicit if they intended this behavior.  Perhaps I am wrong,
but I have a hard time imagining this is what anyone involved with
this later language feature was trying to achieve.

Regardless of my speculation, *please consider* that changing the GNU
implementation to invoke the method after it is evaluated as an rvalue
would not in any way violate the specification or example of 13.5.7/1
and would make the method both intuitive and capable of working as
expected for return by reference.  Furthermore, changing the
implementation would not break any existing code that returns a copy
constructed object as in your example.  Such a change could only alter
semantics of source code that depends on non post rvalue op semantics
which are certainly not expected, specified, or likely.

Cheers.

- Mike

 > ------- Comment #2 from pinskia at gcc dot gnu dot org  2007-04-21 23:49
-------
 > This is not a bug in GCC but instead a bug in your post fix increment
operator:
 >   C & operator++( int )  { v += 100; return *this; }
 > 
 > Really should be implemented as:
 >   C operator++( int )  { C tmp = *this; v += 100; return tmp; }
 > 
 > Which is the correct way of implementing it.  postfix increment returns a
 > rvalue and not a lvalue. See example in the C++ standard in 13.5.7/1. 
 > Basically you just changed the semantics of post fix increment with the
 > operator overloader and changed it to be about the same as the pre
incrementor
 > except incrementing by 100 instead of by 1.
 > 
 > Again this is not a bug in GCC but instead a bug in your code.
 > 
 > b = a++; is the same as doing:
 > b = a.operator++(0);
 > 
 > So if your operator++(int) returns *this, the result you are seeing is
exactly
 > what is expected from the C++ standards point of view.
 > 
 > 
 > -- 
 > 
 > pinskia at gcc dot gnu dot org changed:
 > 
 >            What    |Removed                     |Added
 > ----------------------------------------------------------------------------
 >              Status|UNCONFIRMED                 |RESOLVED
 >          Resolution|                            |INVALID
 > 
 > 
 > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652
 > 
 > ------- You are receiving this mail because: -------
 > You reported the bug, or are watching the reporter.
 > 


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
  2007-04-21 22:49 ` [Bug c++/31652] " pinskia at gcc dot gnu dot org
  2007-04-22  5:40 ` hayward at loup dot net
@ 2007-04-22  6:04 ` pinskia at gcc dot gnu dot org
  2007-04-22 15:37 ` hayward at loup dot net
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: pinskia at gcc dot gnu dot org @ 2007-04-22  6:04 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #4 from pinskia at gcc dot gnu dot org  2007-04-22 07:03 -------
> Using a copy constructor and returning by value is of limited
> applicability.  Having to invoke a copy constructor to "simulate" a
> post rvalue operation is not an option for objects that do not support
> copy, and perhaps more significantly for large objects, is both very
> time inefficient and could blow stack.

Why do you say could blow the stack, the C++ standard actually mentions an
optimization where the copy constructored is removed and there is no extra
variable.  It is called named return value optimization which removes the need
for the extra stack, basically the return value is actually a pointer that is
passed into the function and then initialized that way.

So I don't see your point still.

The result you are seeing is exactly, I mean exactly what the C++ standard says
the results should be as b = a++; is translated exactly as b = a.operator++(0);
and not as b = (tmp = a, a.operator++(0), tmp);  In fact this is worse than
what you are suggesting the C++ standard says there is an extra tmp variable on
the stack to begin with while before with named return value, you don't have
one.


>Furthermore, changing the
> implementation would not break any existing code that returns a copy
> constructed object as in your example.  Such a change could only alter
> semantics of source code that depends on non post rvalue op semantics
> which are certainly not expected, specified, or likely.

Actually it would violate the C++ standard and break existing code as people
don't have to return the copy.  Your example shows exactly why your proposal
change will break valid code.

I think you need to go back and read more about overloading operators as it
seems like you don't understand that overloading operators can sometimes change
the semantics if the overloaded operator changes them as shown by your example.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
                   ` (2 preceding siblings ...)
  2007-04-22  6:04 ` pinskia at gcc dot gnu dot org
@ 2007-04-22 15:37 ` hayward at loup dot net
  2007-04-22 16:50 ` drow at gcc dot gnu dot org
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: hayward at loup dot net @ 2007-04-22 15:37 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #5 from hayward at loup dot net  2007-04-22 16:37 -------
Subject: Re:  postfix increment semantics implemented incorrectly

 > Why do you say could blow the stack, the C++ standard actually mentions an
 > optimization where the copy constructored is removed and there is no extra
 > variable.  It is called named return value optimization which removes the
need
 > for the extra stack, basically the return value is actually a pointer that
is
 > passed into the function and then initialized that way.
 > 
 > So I don't see your point still.

An optimizing compiler could, in theory, optimize out copy
construction and only copy the object portions modified in the body of
the postfix operator.  In practice that increment body could be far
more complex than simply incrementing a 32 bit counter and the return
value could be also be used for arbitrarily complex manipulations.  In
these cases the current interpretation will by necessity involve a
complete copy.

Consider a trivial example of a large n dimensional matrix object
where calling postfix increment should increment every component in
the entire matrix.  Assuming the matrix is actually used in the
expression, there is no inexpensive way to perform the postfix
increment without post evaluating the method.

 > The result you are seeing is exactly, I mean exactly what the C++ standard
says
 > the results should be as b = a++; is translated exactly as b =
a.operator++(0);
 > and not as b = (tmp = a, a.operator++(0), tmp);  In fact this is worse than
 > what you are suggesting the C++ standard says there is an extra tmp variable
on
 > the stack to begin with while before with named return value, you don't have
 > one.

It appears you are not completely undestanding my suggestion.  There
exists a difference between postfix syntax and postfix semantics.  I
am not by any means saying that a++ would not be equivalent to
a.operator++(0) as the operator notation is simply syntactic sugar.  I
am suggesting that they of course have equivalent semantics as is
specified, but that the semantics would be different from prefix ++a
and a.operator++().  If the operator doesn't has postfix semantics, it
is both misleading and additional syntax of limited use.

No expensive temporary copies need be involved as in the return by
value example you give... that would defeat the return by reference
argument I'm making.  Implementation would simply involve creating a
subsequent sequence point for any and all post rvalue operations.  For
example:

b = a++;               // postfix operator syntax

b = a;                 // equivalent semantics without postfix operator
++a;

Or if you prefer method syntax:

b = a.operator++(0);   // postfix method syntax

b = a;                 // equivalent semantics without postfix method
a.operator++();

 > Actually it would violate the C++ standard and break existing code as people
 > don't have to return the copy.  Your example shows exactly why your proposal
 > change will break valid code.

I realize a change could break code that depends on the current
implementation and doesn't return a copy by value.  Maybe that's
reason enough to not change an implementation, but I think not.  I'm
making the case that the implementation does not implement the intent
of the C++ standard.  There is the "letter of the law" and the "spirit
of the law" and without a more explicit specification, it is
understandable how we could argue for either interpretation.  That is
why if there is ambiguity I gravitated to the expected, semantically
consistent, more efficient, and simpler case.

 > I think you need to go back and read more about overloading operators as it
 > seems like you don't understand that overloading operators can sometimes
change
 > the semantics if the overloaded operator changes them as shown by
 > your example.

The semantics of an expression are dependent upon the method
implementation, of course, but also upon order of operation which
includes operator associativity.  It was my understanding that order
of operation and associativity are the same regardless of basic or
overloaded operator status.  The whole notion of postfix operation is
pretty simple to grasp (that the operation is performed "after" it is
used in the expression) and it's disappointing that although it could
be very efficient for arbitrary objects, it simply is not as it is
implemented now.

Since I am now clear that it is implemented as you would intend, I
will hold peace if you do not wish to champion my interpretation.  I
at least want someone in a position to affect things to fully grasp
the point I am making.  Perhaps yours is the more widely adopted
interpretation of the spec as written, but surely you see the benefit
of post expression semantics?  I think it would be useful if someone
could get the specification clarified and annotated on this point...

Once again, thanks for the feedback, and cheers :-)

- Mike


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
                   ` (3 preceding siblings ...)
  2007-04-22 15:37 ` hayward at loup dot net
@ 2007-04-22 16:50 ` drow at gcc dot gnu dot org
  2007-04-22 17:18 ` pinskia at gcc dot gnu dot org
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: drow at gcc dot gnu dot org @ 2007-04-22 16:50 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #6 from drow at gcc dot gnu dot org  2007-04-22 17:50 -------
I believe that this bug should not be RESOLVED/INVALID at least until a C++
front end maintainer has looked at it.


-- 

drow at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |UNCONFIRMED
         Resolution|INVALID                     |


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
                   ` (4 preceding siblings ...)
  2007-04-22 16:50 ` drow at gcc dot gnu dot org
@ 2007-04-22 17:18 ` pinskia at gcc dot gnu dot org
  2007-04-22 17:49 ` drow at false dot org
  2007-04-22 17:49 ` mmitchel at gcc dot gnu dot org
  7 siblings, 0 replies; 9+ messages in thread
From: pinskia at gcc dot gnu dot org @ 2007-04-22 17:18 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #7 from pinskia at gcc dot gnu dot org  2007-04-22 18:18 -------
13.5.1/1 explains that:
@x is the same as operator@(x) or x.operator@() [depending on if x has a member
function for operator@ or not] .

So:
a = b++; is the exactly the same as:
a = b.operator++(0);

so function operator++ can do anything, it does not have to follow what is a
postfix incremement at all.  13.5/7 goes in a little detail at what is required
for basic types does not have to hold for overloaded operators.

So again this bug is invalid.  The code is acting exactly what the C++ standard
says it should act and any change is going to make GCC a non C++ compiler.

>In these cases the current interpretation will by necessity involve a
> complete copy.

No, no, no, it does not this is one of my points I have been trying to explain,
12.8/15 explains sometimes temporaries can be avioded and this case it can.

For any:
a = b.function(); 

where function could be an operator call (invoke implictly via the operator
too) and the function returns a large data type so the copy constructor is not
called and there is no extra variable on the stack.  So I don't see your point
with postfix being special really, as there is nothing special about those
operators.


-- 

pinskia at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|                            |INVALID


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
                   ` (5 preceding siblings ...)
  2007-04-22 17:18 ` pinskia at gcc dot gnu dot org
@ 2007-04-22 17:49 ` drow at false dot org
  2007-04-22 17:49 ` mmitchel at gcc dot gnu dot org
  7 siblings, 0 replies; 9+ messages in thread
From: drow at false dot org @ 2007-04-22 17:49 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #8 from drow at gcc dot gnu dot org  2007-04-22 18:49 -------
Subject: Re:  postfix increment semantics implemented
        incorrectly

On Sun, Apr 22, 2007 at 05:18:09PM -0000, pinskia at gcc dot gnu dot org wrote:
> 13.5.1/1 explains that:
> @x is the same as operator@(x) or x.operator@() [depending on if x has a member
> function for operator@ or not] .

Sorry; I checked with Mark and this is indeed the relevant paragraph.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/31652] postfix increment semantics implemented incorrectly
  2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
                   ` (6 preceding siblings ...)
  2007-04-22 17:49 ` drow at false dot org
@ 2007-04-22 17:49 ` mmitchel at gcc dot gnu dot org
  7 siblings, 0 replies; 9+ messages in thread
From: mmitchel at gcc dot gnu dot org @ 2007-04-22 17:49 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #9 from mmitchel at gcc dot gnu dot org  2007-04-22 18:49 -------
Daniel asked me to look at this issue.

Andrew is correct:

  b = a++;

is exactly equivalent to:

  b = a.operator++(0);

It is completely up to the operator to implement the postfix semantics; it's
just a function.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31652


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-04-22 17:49 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-21 22:39 [Bug c++/31652] New: postfix increment semantics implemented incorrectly gcc-bugzilla at gcc dot gnu dot org
2007-04-21 22:49 ` [Bug c++/31652] " pinskia at gcc dot gnu dot org
2007-04-22  5:40 ` hayward at loup dot net
2007-04-22  6:04 ` pinskia at gcc dot gnu dot org
2007-04-22 15:37 ` hayward at loup dot net
2007-04-22 16:50 ` drow at gcc dot gnu dot org
2007-04-22 17:18 ` pinskia at gcc dot gnu dot org
2007-04-22 17:49 ` drow at false dot org
2007-04-22 17:49 ` mmitchel at gcc dot gnu dot org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).