Bug 58051 - [DR1579] No named return value optimization when returned object is implicitly converted
Summary: [DR1579] No named return value optimization when returned object is implicitl...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.1
: P3 enhancement
Target Milestone: 5.0
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on:
Blocks: RVO
  Show dependency treegraph
 
Reported: 2013-08-02 04:33 UTC by Ryan Johnson
Modified: 2014-06-28 07:47 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-06-26 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ryan Johnson 2013-08-02 04:33:31 UTC
The following test case introduces an extra object copy, even though none should be required:

// <<<--- bug.cpp --->>>
extern "C" void puts(char const *);
struct A {
    A()=default;
    A(A &&)=default;
    A(A const &) { puts("copy"); }
    ~A() { puts("~A"); }
};
struct B {
    A _a;
    B(A a) : _a((A&&)(a)) { }
};
B go() {
    A rval;
    return rval;
}
int main () { go(); }
// <<<--- end bug.cpp --->>>

(when compiled with both `gcc-4.8.1 -std=gnu++11' and `gcc-4.6.3 -std=gnu++0x')

RVO works properly if go() returns A() or std::move(rval).
Comment 1 piotr5 2014-06-26 08:48:27 UTC
I have the same problem, it makes the r-value types tedious.
however this is not a bug in gcc directly, it's a bug in stdc++1x specs omitting this special case and what should be done here. however, as a feature-request I suggest at least when accepting gcc extensions to the standard (or better yet check with the stdc++1x paper if this contradicts the standard), gcc should proceed as suggested in this bug-report.

more concretely: if in the example given the return-value rval would stay alive after the return (for example it's static), then the current behaviour of gcc should be kept. if rval would become destroyed because of going out of scope through the return, then std::move() should implicitly be added by the compiler alike to syntactic sugar.

alternatively one could write a software which checks all return statements for classes which can be r-value initialized and outputs a warning whenever the return statement doesn't come with std::move() around the returned value and the used variable is going out of scope. this functionality could also be added to whatever code-checker. but such a solution would only introduce yet another hassle for the programmer.

to emphasize: the reason why this feature is important is because gcc doesn't automatically do garbage-collection. if return-statements copy and destroy some big class frequently, this creates many holes in memory, cluttering free space. so this kind of optimization is needed for both, speed and size...
Comment 2 Jonathan Wakely 2014-06-26 09:44:23 UTC
(In reply to Ryan Johnson from comment #0)
> RVO works properly if go() returns A() or std::move(rval).

RVO is already working properly, C++11 did not allow the expression in the return statement to be treated as an rvalue when it is a different type to the function's return type.

However the standard changed:
http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579
Comment 3 Jonathan Wakely 2014-06-26 10:06:12 UTC
I wonder if it's this simple:

--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8618,8 +8618,6 @@ check_return_expr (tree retval, bool *no_warning)
              || TREE_CODE (retval) == PARM_DECL)
          && DECL_CONTEXT (retval) == current_function_decl
          && !TREE_STATIC (retval)
-         && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
-                         (TYPE_MAIN_VARIANT (functype)))
          /* This is only interesting for class type.  */
          && CLASS_TYPE_P (functype))
        flags = flags | LOOKUP_PREFER_RVALUE;
Comment 4 Jonathan Wakely 2014-06-28 07:46:06 UTC
Author: redi
Date: Sat Jun 28 07:45:27 2014
New Revision: 212099

URL: https://gcc.gnu.org/viewcvs?rev=212099&root=gcc&view=rev
Log:
gcc/cp:
	DR 1579
	PR c++/58051
	* typeck.c (check_return_expr): Lookup as an rvalue even when the
	types aren't the same.

gcc/testsuite:
	* g++.dg/cpp0x/elision_conv.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/elision_conv.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/typeck.c
    trunk/gcc/testsuite/ChangeLog
Comment 5 Jonathan Wakely 2014-06-28 07:47:19 UTC
fixed on trunk